For unconstrained types, Ada.Sequential_IO needs to encode length information
prior to actual object representation. This length information is now stored
with the same endianness as the object itself, which means that the same
representation is now generated, independent of platform endianness, if the
Scalar_Storage_Order aspect is specified for the actual type.

The following unit test must produce the indicated output:
$ gnatmake -q endian_io
$ endian_io
out_le: 8 0 0 0 0 0 0 0 123 0 0 0 200 1 0 0
out_be: 0 0 0 0 0 0 0 8 0 0 0 123 0 0 1 200

with System; use System;
with Ada.Text_IO; use Ada.Text_IO;

with Ada.Exceptions;
with Ada.Sequential_IO;
with Ada.Streams.Stream_IO;

procedure Endian_IO is

   package Int_IO is new Ada.Sequential_IO (Integer);
   pragma Unreferenced (Int_IO);
   --  Check that Sequential_IO can be instantiated for a non-composite type

   type Arr is array (Integer range <>) of Integer;
   package Arr_IO is new Ada.Sequential_IO (Arr);
   F : Arr_IO.File_Type;

   type Arr_BE is new Arr
      with Scalar_Storage_Order => High_Order_First;
   package Arr_BE_IO is new Ada.Sequential_IO (Arr_BE);
   F_BE : Arr_BE_IO.File_Type;

   type Arr_LE is new Arr
      with Scalar_Storage_Order => Low_Order_First;
   package Arr_LE_IO is new Ada.Sequential_IO (Arr_LE);
   F_LE : Arr_LE_IO.File_Type;

   Val    : constant Arr := (1 => 123, 2 => 456);
   Val_BE : constant Arr_BE := Arr_BE (Val);
   Val_LE : constant Arr_LE := Arr_LE (Val);

   Rval    : Arr (1 .. 2);

   use Arr_IO, Arr_BE_IO, Arr_LE_IO;

   DBO : System.Bit_Order renames System.Default_Bit_Order;

   procedure Dump (FN : String) is
      use Ada.Streams, Ada.Streams.Stream_IO;

      F : Ada.Streams.Stream_IO.File_Type;
      SEA : Stream_Element_Array (1 .. 32);
      Last : Stream_Element_Offset;
   begin
      Open (F, In_File, FN);
      Read (F, SEA, Last);
      Put (FN & ":");
      for J in SEA'First .. Last loop
         Put (SEA (J)'Img);
      end loop;
      New_Line;
      Close (F);
   end Dump;

begin
   Create (F, Out_File, "out");
   Write (F, Val);
   Close (F);

   Create (F_BE, Out_File, "out_be");
   Write (F_BE, Val_BE);
   Close (F_BE);

   Create (F_LE, Out_File, "out_le");
   Write (F_LE, Val_LE);
   Close (F_LE);

   Open (F, In_File, (if DBO = High_Order_First
                        then "out_be"
                        else "out_le"));
   begin
      Read (F, Rval);
   exception
      when E : others =>
         Rval := (others => 666);
         Put_Line ("exception raised: "
           & Ada.Exceptions.Exception_Information (E));
   end;
   Close (F);

   if Rval /= Val then
      Put_Line ("FAIL re-reading " & DBO'Img);
   end if;

   Dump ("out_le");
   Dump ("out_be");
end Endian_IO;

Tested on x86_64-pc-linux-gnu, committed on trunk

2013-10-10  Thomas Quinot  <qui...@adacore.com>

        * sem_attr.adb (Analyse_Attribute, case
        Attribute_Scalar_Storage_Order): a 'Scalar_Storage_Order attribute
        reference for a generic type is permitted in GNAT runtime mode.
        * a-sequio.adb (Read, Write): Use the endianness of the actual
        type to encode length information written to the file.

Index: sem_attr.adb
===================================================================
--- sem_attr.adb        (revision 203346)
+++ sem_attr.adb        (working copy)
@@ -5040,23 +5040,43 @@
       --------------------------
 
       when Attribute_Scalar_Storage_Order => Scalar_Storage_Order :
+      declare
+         Ent : Entity_Id := Empty;
       begin
          Check_E0;
          Check_Type;
 
-         if not Is_Record_Type (P_Type) or else Is_Array_Type (P_Type) then
-            Error_Attr_P
-              ("prefix of % attribute must be record or array type");
-         end if;
+         if not (Is_Record_Type (P_Type) or else Is_Array_Type (P_Type)) then
 
-         if Bytes_Big_Endian xor Reverse_Storage_Order (P_Type) then
-            Rewrite (N,
-              New_Occurrence_Of (RTE (RE_High_Order_First), Loc));
+            --  In GNAT mode, the attribute applies to generic types as well
+            --  as composite types, and for non-composite types always returns
+            --  the default bit order for the target.
+
+            if not (GNAT_Mode and then Is_Generic_Type (P_Type))
+                  and then not In_Instance
+            then
+               Error_Attr_P
+                 ("prefix of % attribute must be record or array type");
+
+            elsif not Is_Generic_Type (P_Type) then
+               if Bytes_Big_Endian then
+                  Ent := RTE (RE_High_Order_First);
+               else
+                  Ent := RTE (RE_Low_Order_First);
+               end if;
+            end if;
+
+         elsif Bytes_Big_Endian xor Reverse_Storage_Order (P_Type) then
+            Ent := RTE (RE_High_Order_First);
+
          else
-            Rewrite (N,
-              New_Occurrence_Of (RTE (RE_Low_Order_First), Loc));
+            Ent := RTE (RE_Low_Order_First);
          end if;
 
+         if Present (Ent) then
+            Rewrite (N, New_Occurrence_Of (Ent, Loc));
+         end if;
+
          Set_Etype (N, RTE (RE_Bit_Order));
          Resolve (N);
 
Index: a-sequio.adb
===================================================================
--- a-sequio.adb        (revision 203342)
+++ a-sequio.adb        (working copy)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2012, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2013, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -34,13 +34,14 @@
 --  in System.File_IO (for common file functions), or in System.Sequential_IO
 --  (for specialized Sequential_IO functions)
 
-with Interfaces.C_Streams; use Interfaces.C_Streams;
+with Ada.Unchecked_Conversion;
 with System;
 with System.CRTL;
 with System.File_Control_Block;
 with System.File_IO;
 with System.Storage_Elements;
-with Ada.Unchecked_Conversion;
+with Interfaces.C_Streams; use Interfaces.C_Streams;
+with GNAT.Byte_Swapping;
 
 package body Ada.Sequential_IO is
 
@@ -57,8 +58,26 @@
    function To_FCB is new Ada.Unchecked_Conversion (File_Mode, FCB.File_Mode);
    function To_SIO is new Ada.Unchecked_Conversion (FCB.File_Mode, File_Mode);
 
+   use type System.Bit_Order;
    use type System.CRTL.size_t;
 
+   procedure Byte_Swap (Siz : in out size_t);
+   --  Byte swap Siz
+
+   ---------------
+   -- Byte_Swap --
+   ---------------
+
+   procedure Byte_Swap (Siz : in out size_t) is
+      use GNAT.Byte_Swapping;
+   begin
+      case Siz'Size is
+         when 32     => Swap4 (Siz'Address);
+         when 64     => Swap8 (Siz'Address);
+         when others => raise Program_Error;
+      end case;
+   end Byte_Swap;
+
    -----------
    -- Close --
    -----------
@@ -170,6 +189,10 @@
          FIO.Read_Buf
            (AP (File), Rsiz'Address, size_t'Size / System.Storage_Unit);
 
+         if Element_Type'Scalar_Storage_Order /= System.Default_Bit_Order then
+            Byte_Swap (Rsiz);
+         end if;
+
          --  For a type with discriminants, we have to read into a temporary
          --  buffer if Item is constrained, to check that the discriminants
          --  are correct.
@@ -252,7 +275,11 @@
 
    procedure Write (File : File_Type; Item : Element_Type) is
       Siz : constant size_t := (Item'Size + SU - 1) / SU;
+      --  Size to be written, in native representation
 
+      Swapped_Siz : size_t := Siz;
+      --  Same, possibly byte swapped to account for Element_Type endianness
+
    begin
       FIO.Check_Write_Status (AP (File));
 
@@ -261,8 +288,12 @@
       if not Element_Type'Definite
         or else Element_Type'Has_Discriminants
       then
+         if Element_Type'Scalar_Storage_Order /= System.Default_Bit_Order then
+            Byte_Swap (Swapped_Siz);
+         end if;
+
          FIO.Write_Buf
-           (AP (File), Siz'Address, size_t'Size / System.Storage_Unit);
+           (AP (File), Swapped_Siz'Address, size_t'Size / System.Storage_Unit);
       end if;
 
       FIO.Write_Buf (AP (File), Item'Address, Siz);

Reply via email to