comp.lang.ada
 help / color / mirror / Atom feed
* Load an object from a file
@ 2009-04-03 12:01 Olivier Scalbert
  2009-04-03 13:07 ` Niklas Holsti
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Olivier Scalbert @ 2009-04-03 12:01 UTC (permalink / raw)


Hello everybody !

In my Ada self-study context, I was asking myself how can I create and 
fill objects or records from a file.
As an example, I have tried to represent a java class file format 
structure and fill it with a .class java file.

The ClassFile structure is something like:

     ClassFile {
     	u4 magic;
     	u2 minor_version;
     	u2 major_version;
     	u2 constant_pool_count;
     	cp_info constant_pool[constant_pool_count-1];
     	u2 access_flags;
     	u2 this_class;
     	u2 super_class;
     	u2 interfaces_count;
     	u2 interfaces[interfaces_count];
     	u2 fields_count;
     	field_info fields[fields_count];
     	u2 methods_count;
     	method_info methods[methods_count];
     	u2 attributes_count;
     	attribute_info attributes[attributes_count];
     }


JVM Specs can be found there:
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html

I have no problem to represent and to fill from file, the first four fields.
But I do not know what is the best (Ada) way of representing the array 
of info constant_pool as the size is only known at run time.(= 
constant_pool_cout).
Also how can I fill this array ?

Thanks to help me and have a nice day.

Olivier



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 12:01 Load an object from a file Olivier Scalbert
@ 2009-04-03 13:07 ` Niklas Holsti
  2009-04-03 13:37 ` Ludovic Brenta
  2009-04-03 13:41 ` Thomas Løcke
  2 siblings, 0 replies; 16+ messages in thread
From: Niklas Holsti @ 2009-04-03 13:07 UTC (permalink / raw)


Olivier Scalbert wrote:
> Hello everybody !
> 
> In my Ada self-study context, I was asking myself how can I create and 
> fill objects or records from a file.
> As an example, I have tried to represent a java class file format 
> structure and fill it with a .class java file.
> 
> The ClassFile structure is something like:
> 
>     ClassFile {
>         u4 magic;
>         u2 minor_version;
>         u2 major_version;
>         u2 constant_pool_count;
>         cp_info constant_pool[constant_pool_count-1];
>         u2 access_flags;
>         u2 this_class;
>         u2 super_class;
>         u2 interfaces_count;
>         u2 interfaces[interfaces_count];
>         u2 fields_count;
>         field_info fields[fields_count];
>         u2 methods_count;
>         method_info methods[methods_count];
>         u2 attributes_count;
>         attribute_info attributes[attributes_count];
>     }
> 
> 
> JVM Specs can be found there:
> http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html
> 
> I have no problem to represent and to fill from file, the first four 
> fields.
> But I do not know what is the best (Ada) way of representing the array 
> of info constant_pool as the size is only known at run time.(= 
> constant_pool_cout).

You could use suitable container structures, for example 
Ada.Containers.Vectors. That would hide the storage management from 
your problem space.

There are two more basic methods:

1. Make the size components discriminants of the record, not
    ordinary components:

    type Constant_Pool_T is array (Positive range <>) of cp_info;
    ... etc types for the other arrays.

    type Class_File_T (
       Constant_Pool_Count : u2;
       Interfaces_Count    : u2;
       Fields_Count        : u2;
       Attributes_Count    : u2)
    is record
       ...
       Constant_Pool : Constant_Pool_T (1 .. Constant_Pool_Count);
       ...
       Attributes : Attributes_T (1 .. Attributes_Count);
    end record;

    In this method, you must know the sizes of the arrays
    before you can create the Class_File_T object. This could
    be hard in your case -- I assume you must read the components
    from a file in the order given in the record type, so you
    would have to read all constant-pool items before reading
    interfaces_count, for example.

    In this method it is more convenient to index the
    arrays starting from 1, not 0, because you cannot do
    arithmetic on the discriminants to define the array
    bounds; the "-1" is forbidden here:

    type Class_File_T ( ... ) is record
       ...
       Constant_Pool :
          Constant_Pool_T (0 .. Constant_Pool_Count - 1);
       ...
    end record;

2. Use heap allocation and access types:

    type Constant_Pool_T is array Natural range <>) of cp_info;
    type Constant_Pool_Ref is access Constant_Pool_T;

    type Class_File_T is record
       ...
       Constant_Pool : Constant_Pool_Ref;
       ...
       Attributes : Attributes_Ref;
    end record;

    In this method, you can create the Class_File_T object
    before you know the array sizes. The components Constant_Pool
    etc. will initially be null. When you know the size, you
    can create arrays of the right size on the heap:

       CF.Constant_Pool :=
          new Constant_Pool_T (0 .. constant_pool_count - 1);

HTH,

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 12:01 Load an object from a file Olivier Scalbert
  2009-04-03 13:07 ` Niklas Holsti
@ 2009-04-03 13:37 ` Ludovic Brenta
  2009-04-03 15:19   ` Olivier Scalbert
                     ` (2 more replies)
  2009-04-03 13:41 ` Thomas Løcke
  2 siblings, 3 replies; 16+ messages in thread
From: Ludovic Brenta @ 2009-04-03 13:37 UTC (permalink / raw)


Olivier Scalbert wrote on comp.lang.ada:
> Hello everybody !
>
> In my Ada self-study context, I was asking myself how can I create and
> fill objects or records from a file.
> As an example, I have tried to represent a java class file format
> structure and fill it with a .class java file.
>
> The ClassFile structure is something like:
>
>      ClassFile {
>         u4 magic;
>         u2 minor_version;
>         u2 major_version;
>         u2 constant_pool_count;
>         cp_info constant_pool[constant_pool_count-1];
>         u2 access_flags;
>         u2 this_class;
>         u2 super_class;
>         u2 interfaces_count;
>         u2 interfaces[interfaces_count];
>         u2 fields_count;
>         field_info fields[fields_count];
>         u2 methods_count;
>         method_info methods[methods_count];
>         u2 attributes_count;
>         attribute_info attributes[attributes_count];
>      }
>
> JVM Specs can be found there:http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc...
>
> I have no problem to represent and to fill from file, the first four fields.
> But I do not know what is the best (Ada) way of representing the array
> of info constant_pool as the size is only known at run time.(=
> constant_pool_cout).

I would create a record type with one discriminant for each array,
like so:

type Constant_Pool_Array is array (Positive range <>) of cp_info;
type Interfaces_Array is array (Positive range <>) of u2;
-- etc.

type Class_File
  (constant_pool_count,
   interfaces_count,
   fields_count,
   methods_count,
   attributes_count : u2)
is record
   ...
   constant_pool : Constant_Pool_Array (2 .. constant_pool_count);
   ...
   interfaces : Interfaces_Array (1 .. interfaces_count);
   ... etc.
end record;

> Also how can I fill this array ?

You would normally simply call the predefined Class_File'Read but this
wouldn't work since the order of the components in type Class_File
does not match the order in the file. So, you'd specify your own Read:

function Input(
   Stream : not null access Ada.Streams.Root_Stream_Type'Class)
   return Class_File); -- see RM 13.13(22) and following
for Class_File'Input use Input; -- as per RM 13.13(38/2)

function Input(
   Stream : not null access Ada.Streams.Root_Stream_Type'Class)
   return Class_File)
is
   Constant_Pool_Count : u2;
   type Constant_Pool_Array_Access is access Constant_Pool_Array;
   procedure Free is new Ada.Unchecked_Deallocation
     (Constant_Pool_Array, Constant_Pool_Array_Access);
   Constant_Pool : Constant_Pool_Array_Access;
begin
   ...
   u2'Read (Stream, Constant_Pool_Count);
   Constant_Pool := new Constant_Pool_Array (1 .. Constant_Pool - 1);
   Constant_Pool_Array'Read (Stream, Constant_Pool.all);
   ...

After reading all members, construct the result:

declare
   Result : Class_File
  (constant_pool_count => Constant_Pool_Count,
   interfaces_count => Interfaces_Count,
   fields_count => Fields_Count,
   methods_count => Methods_Count,
   attributes_count => Attricutes_Count);
begin
   Result.Constant_Pool := Constant_Pool.all;
   ...
   Free (Constant_Pool);
   ...
   return Result;
end;
end Input;

You can also eliminate the use of access types and dynamic allocation
and deallocation by nesting declare blocks, e.g.

u2'Read (Stream, Constant_Pool_Count);
declare
   Constant_Pool : Constant_Pool_Array (1 .. Constant_Pool_Count);
begin
   Constant_Pool_Array'Read (Stream, Constant_Pool);
   ...
   u2'Read (Stream, Interfaces_Count);
   declare
      Interfaces : Interfaces_Count_Array (1 .. Interfaces_Count);
   begin
      ...
   end;
end;

HTH

--
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 12:01 Load an object from a file Olivier Scalbert
  2009-04-03 13:07 ` Niklas Holsti
  2009-04-03 13:37 ` Ludovic Brenta
@ 2009-04-03 13:41 ` Thomas Løcke
  2 siblings, 0 replies; 16+ messages in thread
From: Thomas Løcke @ 2009-04-03 13:41 UTC (permalink / raw)


Olivier Scalbert wrote:
> But I do not know what is the best (Ada) way of representing the array 
> of info constant_pool as the size is only known at run time.(= 
> constant_pool_cout).
> Also how can I fill this array ?
> 
> Thanks to help me and have a nice day.

Hey Olivier,

I don't know if it's the "best" way, but I would use 
Ada.Containers.Vector in your case. Here's a small example:

-----
with Ada.Text_IO;               use Ada.Text_IO;
with Ada.Containers.Vectors;    use Ada.Containers;

procedure Vec is
    type CP_Info_Type is new String (1 .. 3);
    package Constant_Pool_Container is new Vectors (Natural, CP_Info_Type);
    Constant_Pool : Constant_Pool_Container.Vector;
    CP_Info : CP_Info_Type;
begin
    CP_Info := "Foo";
    Constant_Pool.Append (New_Item => CP_Info);

    CP_Info := "Bar";
    Constant_Pool.Append (New_Item => CP_Info);

    CP_Info := "42!";
    Constant_Pool.Append (New_Item => CP_Info);

    for i in 0 .. Constant_Pool.Last_Index loop
       Put_Line (String (Constant_Pool.Element (Index => i)));
    end loop;
end Vec;
-----

If all goes well, output should be:

    Foo
    Bar
    42!

You can read more about Ada.Containers.Vectors here: 
http://adaic.org/standards/05rm/html/RM-A-18-2.html

:o)
/Thomas



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 13:37 ` Ludovic Brenta
@ 2009-04-03 15:19   ` Olivier Scalbert
  2009-04-03 16:08     ` Georg Bauhaus
  2009-04-09 20:32   ` Olivier Scalbert
  2009-04-19 13:08   ` Olivier Scalbert
  2 siblings, 1 reply; 16+ messages in thread
From: Olivier Scalbert @ 2009-04-03 15:19 UTC (permalink / raw)


Thanks Ludovic,

One more question:

with:
     type u2 is new Integer;
     type cp_info is new Integer;

     type Constant_Pool_Array is array (Positive range <>) of cp_info;
     type Interfaces_Array is array (Positive range <>) of u2;

     type Class_File
     (constant_pool_count,
     interfaces_count,
     fields_count,
     methods_count,
     attributes_count : u2)
     is record
        constant_pool : Constant_Pool_Array (2 .. constant_pool_count);
        interfaces : Interfaces_Array (1 .. interfaces_count);
     end record;

I have an error: expected type "Standard.Integer", in the 2 last lines.
If I replace the line:
"attributes_count : u2" by
"attributes_count : Integer"
then compile is Ok !
Don't know how to cleanly solve ...

Olivier






Ludovic Brenta wrote:

> I would create a record type with one discriminant for each array,
> like so:
> 
> type Constant_Pool_Array is array (Positive range <>) of cp_info;
> type Interfaces_Array is array (Positive range <>) of u2;
> -- etc.
> 
> type Class_File
>   (constant_pool_count,
>    interfaces_count,
>    fields_count,
>    methods_count,
>    attributes_count : u2)
> is record
>    ...
>    constant_pool : Constant_Pool_Array (2 .. constant_pool_count);
>    ...
>    interfaces : Interfaces_Array (1 .. interfaces_count);
>    ... etc.
> end record;
> 
>> Also how can I fill this array ?
> 
> You would normally simply call the predefined Class_File'Read but this
> wouldn't work since the order of the components in type Class_File
> does not match the order in the file. So, you'd specify your own Read:
> 
> function Input(
>    Stream : not null access Ada.Streams.Root_Stream_Type'Class)
>    return Class_File); -- see RM 13.13(22) and following
> for Class_File'Input use Input; -- as per RM 13.13(38/2)
> 
> function Input(
>    Stream : not null access Ada.Streams.Root_Stream_Type'Class)
>    return Class_File)
> is
>    Constant_Pool_Count : u2;
>    type Constant_Pool_Array_Access is access Constant_Pool_Array;
>    procedure Free is new Ada.Unchecked_Deallocation
>      (Constant_Pool_Array, Constant_Pool_Array_Access);
>    Constant_Pool : Constant_Pool_Array_Access;
> begin
>    ...
>    u2'Read (Stream, Constant_Pool_Count);
>    Constant_Pool := new Constant_Pool_Array (1 .. Constant_Pool - 1);
>    Constant_Pool_Array'Read (Stream, Constant_Pool.all);
>    ...
> 
> After reading all members, construct the result:
> 
> declare
>    Result : Class_File
>   (constant_pool_count => Constant_Pool_Count,
>    interfaces_count => Interfaces_Count,
>    fields_count => Fields_Count,
>    methods_count => Methods_Count,
>    attributes_count => Attricutes_Count);
> begin
>    Result.Constant_Pool := Constant_Pool.all;
>    ...
>    Free (Constant_Pool);
>    ...
>    return Result;
> end;
> end Input;
> 
> You can also eliminate the use of access types and dynamic allocation
> and deallocation by nesting declare blocks, e.g.
> 
> u2'Read (Stream, Constant_Pool_Count);
> declare
>    Constant_Pool : Constant_Pool_Array (1 .. Constant_Pool_Count);
> begin
>    Constant_Pool_Array'Read (Stream, Constant_Pool);
>    ...
>    u2'Read (Stream, Interfaces_Count);
>    declare
>       Interfaces : Interfaces_Count_Array (1 .. Interfaces_Count);
>    begin
>       ...
>    end;
> end;
> 
> HTH
> 
> --
> Ludovic Brenta.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 15:19   ` Olivier Scalbert
@ 2009-04-03 16:08     ` Georg Bauhaus
  2009-04-03 16:22       ` Ludovic Brenta
  2009-04-03 16:46       ` Adam Beneschan
  0 siblings, 2 replies; 16+ messages in thread
From: Georg Bauhaus @ 2009-04-03 16:08 UTC (permalink / raw)


Olivier Scalbert schrieb:
> Thanks Ludovic,
> 
> One more question:
> 
> with:
>     type u2 is new Integer;
>     type cp_info is new Integer;
> 
>     type Constant_Pool_Array is array (Positive range <>) of cp_info;
>     type Interfaces_Array is array (Positive range <>) of u2;

Make the index type the same as the type in the disciminant,
that is, u2.

   type Constant_Pool_Array is array (u2 range <>) of cp_info;
   type Interfaces_Array is array (u2 range <>) of u2;

since U2 is the type of the discriminants used in providing
the array bounds.

In fact, very likely the type U2 is range 0 .. Something, with
Java's integer type semantics regarding overflow and wrap
around.  Perhaps it is a good idea to express this in Ada
for U2 as well.


>     type Class_File
>     (constant_pool_count,
>     interfaces_count,
>     fields_count,
>     methods_count,
>     attributes_count : u2)
>     is record
>        constant_pool : Constant_Pool_Array (2 .. constant_pool_count);
>        interfaces : Interfaces_Array (1 .. interfaces_count);
>     end record;
> 
> I have an error: expected type "Standard.Integer", in the 2 last lines.
> If I replace the line:
> "attributes_count : u2" by
> "attributes_count : Integer"
> then compile is Ok !
> Don't know how to cleanly solve ...



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 16:08     ` Georg Bauhaus
@ 2009-04-03 16:22       ` Ludovic Brenta
  2009-04-03 16:41         ` Olivier Scalbert
  2009-04-03 16:46       ` Adam Beneschan
  1 sibling, 1 reply; 16+ messages in thread
From: Ludovic Brenta @ 2009-04-03 16:22 UTC (permalink / raw)


Georg Bauhaus wrote on comp.lang.ada:
> Olivier Scalbert schrieb:
>
> > Thanks Ludovic,
>
> > One more question:
>
> > with:
> >     type u2 is new Integer;
> >     type cp_info is new Integer;
>
> >     type Constant_Pool_Array is array (Positive range <>) of cp_info;
> >     type Interfaces_Array is array (Positive range <>) of u2;
>
> Make the index type the same as the type in the disciminant,
> that is, u2.
>
>    type Constant_Pool_Array is array (u2 range <>) of cp_info;
>    type Interfaces_Array is array (u2 range <>) of u2;
>
> since U2 is the type of the discriminants used in providing
> the array bounds.
>
> In fact, very likely the type U2 is range 0 .. Something, with
> Java's integer type semantics regarding overflow and wrap
> around.  Perhaps it is a good idea to express this in Ada
> for U2 as well.

Right; in fact, Java's u2 probably corresponds to

type u2 is mod 2 ** 32; -- or perhaps 64?

--
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 16:22       ` Ludovic Brenta
@ 2009-04-03 16:41         ` Olivier Scalbert
  0 siblings, 0 replies; 16+ messages in thread
From: Olivier Scalbert @ 2009-04-03 16:41 UTC (permalink / raw)


Ludovic Brenta wrote:
> Georg Bauhaus wrote on comp.lang.ada:
>> Olivier Scalbert schrieb:
>>
>>> Thanks Ludovic,
>>> One more question:
>>> with:
>>>     type u2 is new Integer;
>>>     type cp_info is new Integer;
>>>     type Constant_Pool_Array is array (Positive range <>) of cp_info;
>>>     type Interfaces_Array is array (Positive range <>) of u2;
>> Make the index type the same as the type in the disciminant,
>> that is, u2.
>>
>>    type Constant_Pool_Array is array (u2 range <>) of cp_info;
>>    type Interfaces_Array is array (u2 range <>) of u2;
>>
>> since U2 is the type of the discriminants used in providing
>> the array bounds.
>>
>> In fact, very likely the type U2 is range 0 .. Something, with
>> Java's integer type semantics regarding overflow and wrap
>> around.  Perhaps it is a good idea to express this in Ada
>> for U2 as well.
> 
> Right; in fact, Java's u2 probably corresponds to
> 
> type u2 is mod 2 ** 32; -- or perhaps 64?
> 
> --
> Ludovic Brenta.A class file consists of a stream of 8-bit bytes. All 16-bit, 32-bit, and 64-bit quantities are constructed by reading in two, four, and eight consecutive 8-bit bytes, respectively. Multibyte data items are always stored in big-endian order, where the high bytes come first. In the Java and Java 2 platforms, this format is supported by interfaces java.io.DataInput and java.io.DataOutput and classes such as java.io.DataInputStream and java.io.DataOutputStream.

Yes it works !

I should focus on the domain problem.
I should focus on the domain problem.
I should focus on the domain problem.
I should focus on the domain problem.
I should focus on the domain problem.

For your info:
...
A class file consists of a stream of 8-bit bytes. All 16-bit, 32-bit, 
and 64-bit quantities are constructed by reading in two, four, and eight 
consecutive 8-bit bytes, respectively. Multibyte data items are always 
stored in big-endian order, where the high bytes come first.
...
This chapter defines its own set of data types representing class file 
data: The types u1, u2, and u4 represent an unsigned one-, two-, or 
four-byte quantity, respectively.
...

The firt 4 bytes that composed the magic field are:
0xCAFEBABE
;-)

Olivier



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 16:08     ` Georg Bauhaus
  2009-04-03 16:22       ` Ludovic Brenta
@ 2009-04-03 16:46       ` Adam Beneschan
  2009-04-03 20:22         ` Ludovic Brenta
  1 sibling, 1 reply; 16+ messages in thread
From: Adam Beneschan @ 2009-04-03 16:46 UTC (permalink / raw)


On Apr 3, 9:08 am, Georg Bauhaus <rm.dash-bauh...@futureapps.de>
wrote:
> Olivier Scalbert schrieb:
>
> > Thanks Ludovic,
>
> > One more question:
>
> > with:
> >     type u2 is new Integer;
> >     type cp_info is new Integer;
>
> >     type Constant_Pool_Array is array (Positive range <>) of cp_info;
> >     type Interfaces_Array is array (Positive range <>) of u2;
>
> Make the index type the same as the type in the disciminant,
> that is, u2.
>
>    type Constant_Pool_Array is array (u2 range <>) of cp_info;
>    type Interfaces_Array is array (u2 range <>) of u2;
>
> since U2 is the type of the discriminants used in providing
> the array bounds.

Or, if you want to keep the "Positive" aspect:

    subtype Positive_U2 is U2 range 1 .. U2'Last;
    type Constant_Pool_Array is array (Positive_U2 range <>) of
cp_info;
    type Interfaces_Array is array (Positive_U2 range <>) of U2;

P.S. You may need to be a bit cautious if you define U2 as a modular
type, as Ludovic suggested, and then use it as the base type of an
unconstrained array.  If you define

    type Some_Array is array (u2 range <>) of u2;

you might be tempted to write code like this:

    procedure Do_Some_Operation (Count : U2) is
       Result : Some_Array (0 .. Count - 1);
       ...

If you call Do_Some_Operation(0), Result is not going to be an empty
array like you expect, but rather an array too large to fit in your
computer, because 0-1 doesn't return a negative number for modular
types but rather a very large positive number.

                              -- Adam




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 16:46       ` Adam Beneschan
@ 2009-04-03 20:22         ` Ludovic Brenta
  0 siblings, 0 replies; 16+ messages in thread
From: Ludovic Brenta @ 2009-04-03 20:22 UTC (permalink / raw)


Adam Beneschan wrote on comp.lang.ada:
> P.S. You may need to be a bit cautious if you define U2 as a modular
> type, as Ludovic suggested, and then use it as the base type of an
> unconstrained array.  If you define
>
>     type Some_Array is array (u2 range <>) of u2;
>
> you might be tempted to write code like this:
>
>     procedure Do_Some_Operation (Count : U2) is
>        Result : Some_Array (0 .. Count - 1);
>        ...
>
> If you call Do_Some_Operation(0), Result is not going to be an empty
> array like you expect, but rather an array too large to fit in your
> computer, because 0-1 doesn't return a negative number for modular
> types but rather a very large positive number.

In the light of Adam's remark,

type u2 is mod 2 ** 16;

is the exact equivalent of Java's u2, but we now see that Java's u2
does _not_ represent the problem domain accurately; therefore defining
u2 in Ada as

type u2 is range 0 .. 2 ** 16 - 1;

does reflect the problem domain accurately (i.e. in the problem
domain, there is no wrap-around semantics) at the expense, perhaps, of
exposing bugs in the Java code :)

--
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 13:37 ` Ludovic Brenta
  2009-04-03 15:19   ` Olivier Scalbert
@ 2009-04-09 20:32   ` Olivier Scalbert
  2009-04-09 21:22     ` Ludovic Brenta
  2009-04-19 13:08   ` Olivier Scalbert
  2 siblings, 1 reply; 16+ messages in thread
From: Olivier Scalbert @ 2009-04-09 20:32 UTC (permalink / raw)


Hi,

I still have one question ...
How can I implement the Load_Class procedure that will use the Input 
function?
I do not know how to get the needed stream from a given file name.
And I do not know how to define the Class_File_Structure result (I get 
an unconstrained subtype (need initialization)).

Thanks,

Olivier




Here is my spec:
--------------------------

package jvm is

     type Byte_T is range 0..255;
     for Byte_T'Size use 8;

     type U2_T is range 0 .. 2 ** 16 - 1;
     type U4_T is range 0 .. 2 ** 32 - 1;

     type cp_info_T is new Integer; -- Just for test !

     type Constant_Pool_Array_T is array (U2_T range <>) of cp_info_T;

     type Class_File_Structure_T(
                                 constant_pool_count,
                                 interfaces_count,
                                 fields_count,
                                 methods_count,
                                 attributes_count : U2_T) is record

         Magic               : U4_T;
         Minor_Version       : U2_T;
         Major_Version       : U2_T;
         Constant_Pool : Constant_Pool_Array_T (2 .. constant_pool_count);
         --interfaces   : Interfaces_Array_T (1 .. interfaces_count);
     end record;

     procedure Run;

     procedure Load_Class(File_Name: String);

     function Input(Stream : not null access 
Ada.Streams.Root_Stream_Type'Class)
                    return Class_File_Structure_T; -- see RM 13.13(22) 
and following
     for Class_File_Structure_T'Input use Input; -- as per RM 13.13(38/2)

end jvm;


Here is the body:
--------------------------

with Ada.Text_IO;                          use Ada.Text_IO;
with Ada.Sequential_IO;
with Ada.Unchecked_Deallocation;

package body jvm is

     procedure run is
     begin
         Load_Class("Main.class");
     end run;


     procedure Load_Class(File_Name: String) is

         Class_File_Structure: Class_File_Structure_T; -- (unconstrained 
subtype (need initialization)
     begin
         Put_Line(File_Name);

         Class_file_Structure := Input(Stream ???);


     end Load_Class;

     function Input(Stream : not null access 
Ada.Streams.Root_Stream_Type'Class)
                    return Class_File_Structure_T is
         Magic               : U4_T;
         Minor_Version       : U2_T;
         Major_Version       : U2_T;
         Constant_Pool_Count : U2_T;
         type Constant_Pool_Array_Access is access Constant_Pool_Array_T;
         procedure Free is new Ada.Unchecked_Deallocation
           (Constant_Pool_Array_T, Constant_Pool_Array_Access);
         Constant_Pool : Constant_Pool_Array_Access;

     begin
         -- Read
         U4_T'Read(Stream, Magic);
         U2_T'Read(Stream, Minor_Version);
         U2_T'Read(Stream, Major_Version);
         U2_T'Read (Stream, Constant_Pool_Count);
         Constant_Pool := new Constant_Pool_Array_T (1 .. 
Constant_Pool_Count - 1);
         Constant_Pool_Array_T'Read (Stream, Constant_Pool.all);

         -- Fill in to the result
         declare
             Result : Class_File_Structure_T
               (constant_pool_count => Constant_Pool_Count,
                interfaces_count => 0, --Interfaces_Count,
                fields_count => 0, --Fields_Count,
                methods_count => 0, --Methods_Count,
                attributes_count => 0); --Attricutes_Count);
         begin
             Result.Magic := Magic;
             Result.Minor_Version := Minor_Version;
             Result.Major_Version := Major_Version;
             Result.Constant_Pool := Constant_Pool.all;
             Free(Constant_Pool);
             return Result;
         end;
     end;

end jvm;




Ludovic Brenta wrote:
> Olivier Scalbert wrote on comp.lang.ada:
>> Hello everybody !
>>
>> In my Ada self-study context, I was asking myself how can I create and
>> fill objects or records from a file.
>> As an example, I have tried to represent a java class file format
>> structure and fill it with a .class java file.
>>
>> The ClassFile structure is something like:
>>
>>      ClassFile {
>>         u4 magic;
>>         u2 minor_version;
>>         u2 major_version;
>>         u2 constant_pool_count;
>>         cp_info constant_pool[constant_pool_count-1];
>>         u2 access_flags;
>>         u2 this_class;
>>         u2 super_class;
>>         u2 interfaces_count;
>>         u2 interfaces[interfaces_count];
>>         u2 fields_count;
>>         field_info fields[fields_count];
>>         u2 methods_count;
>>         method_info methods[methods_count];
>>         u2 attributes_count;
>>         attribute_info attributes[attributes_count];
>>      }
>>
>> JVM Specs can be found there:http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc...
>>
>> I have no problem to represent and to fill from file, the first four fields.
>> But I do not know what is the best (Ada) way of representing the array
>> of info constant_pool as the size is only known at run time.(=
>> constant_pool_cout).
> 
> I would create a record type with one discriminant for each array,
> like so:
> 
> type Constant_Pool_Array is array (Positive range <>) of cp_info;
> type Interfaces_Array is array (Positive range <>) of u2;
> -- etc.
> 
> type Class_File
>   (constant_pool_count,
>    interfaces_count,
>    fields_count,
>    methods_count,
>    attributes_count : u2)
> is record
>    ...
>    constant_pool : Constant_Pool_Array (2 .. constant_pool_count);
>    ...
>    interfaces : Interfaces_Array (1 .. interfaces_count);
>    ... etc.
> end record;
> 
>> Also how can I fill this array ?
> 
> You would normally simply call the predefined Class_File'Read but this
> wouldn't work since the order of the components in type Class_File
> does not match the order in the file. So, you'd specify your own Read:
> 
> function Input(
>    Stream : not null access Ada.Streams.Root_Stream_Type'Class)
>    return Class_File); -- see RM 13.13(22) and following
> for Class_File'Input use Input; -- as per RM 13.13(38/2)
> 
> function Input(
>    Stream : not null access Ada.Streams.Root_Stream_Type'Class)
>    return Class_File)
> is
>    Constant_Pool_Count : u2;
>    type Constant_Pool_Array_Access is access Constant_Pool_Array;
>    procedure Free is new Ada.Unchecked_Deallocation
>      (Constant_Pool_Array, Constant_Pool_Array_Access);
>    Constant_Pool : Constant_Pool_Array_Access;
> begin
>    ...
>    u2'Read (Stream, Constant_Pool_Count);
>    Constant_Pool := new Constant_Pool_Array (1 .. Constant_Pool - 1);
>    Constant_Pool_Array'Read (Stream, Constant_Pool.all);
>    ...
> 
> After reading all members, construct the result:
> 
> declare
>    Result : Class_File
>   (constant_pool_count => Constant_Pool_Count,
>    interfaces_count => Interfaces_Count,
>    fields_count => Fields_Count,
>    methods_count => Methods_Count,
>    attributes_count => Attricutes_Count);
> begin
>    Result.Constant_Pool := Constant_Pool.all;
>    ...
>    Free (Constant_Pool);
>    ...
>    return Result;
> end;
> end Input;
> 
> You can also eliminate the use of access types and dynamic allocation
> and deallocation by nesting declare blocks, e.g.
> 
> u2'Read (Stream, Constant_Pool_Count);
> declare
>    Constant_Pool : Constant_Pool_Array (1 .. Constant_Pool_Count);
> begin
>    Constant_Pool_Array'Read (Stream, Constant_Pool);
>    ...
>    u2'Read (Stream, Interfaces_Count);
>    declare
>       Interfaces : Interfaces_Count_Array (1 .. Interfaces_Count);
>    begin
>       ...
>    end;
> end;
> 
> HTH
> 
> --
> Ludovic Brenta.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-09 20:32   ` Olivier Scalbert
@ 2009-04-09 21:22     ` Ludovic Brenta
  2009-04-09 22:22       ` Olivier Scalbert
  0 siblings, 1 reply; 16+ messages in thread
From: Ludovic Brenta @ 2009-04-09 21:22 UTC (permalink / raw)


On Apr 9, 10:32 pm, Olivier Scalbert <olivier.scalb...@algosyn.com>
wrote:
> Hi,
>
> I still have one question ...
> How can I implement the Load_Class procedure that will use the Input
> function?
> I do not know how to get the needed stream from a given file name.
> And I do not know how to define the Class_File_Structure result (I get
> an unconstrained subtype (need initialization)).
[...]
> package body jvm is
[...]
>      procedure Load_Class(File_Name: String) is
>
>          Class_File_Structure: Class_File_Structure_T; -- (unconstrained
> subtype (need initialization)
>      begin
>          Put_Line(File_Name);
>
>          Class_file_Structure := Input(Stream ???);
>
>      end Load_Class;
[...]
> end jvm;

Because Class_File_Structure_T is unconstrained and needs
initialization, you cannot use a procedure to load one: out parameters
don't work, and the procedure cannot write into a variable because you
can't declare a variable without initializing it.  So, here is a
possible solution replacing your procedure with a function:

with Ada.Streams.Stream_IO;
...
function From_File (File_Name : String) return Class_File_Structure_T
is
   File : Ada.Streams.Stream_IO.File_Type;
begin
   Ada.Streams.Stream_IO.Open (File,
                               File_Mode =>
Ada.Streams.Stream_IO.In_File,
                               Name      => File_Name);
   declare
      Result : constant Class_File_Structure_T :=
        Class_File_Structure_T'Input (Ada.Streams.Stream_IO.Stream
(File));
   begin
      Ada.Streams.Stream_IO.Close (File);
      return Result;
   end;
end From_File;

HTH

--
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-09 21:22     ` Ludovic Brenta
@ 2009-04-09 22:22       ` Olivier Scalbert
  0 siblings, 0 replies; 16+ messages in thread
From: Olivier Scalbert @ 2009-04-09 22:22 UTC (permalink / raw)


Thanks, it compiles and it runs!
Now I will try to display the Magic part in hexadecimal, so I will come 
back in few days with one more question !
;-)

Olivier



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-03 13:37 ` Ludovic Brenta
  2009-04-03 15:19   ` Olivier Scalbert
  2009-04-09 20:32   ` Olivier Scalbert
@ 2009-04-19 13:08   ` Olivier Scalbert
  2009-04-19 19:52     ` Ludovic Brenta
  2009-04-19 20:27     ` Gautier
  2 siblings, 2 replies; 16+ messages in thread
From: Olivier Scalbert @ 2009-04-19 13:08 UTC (permalink / raw)


Hello,

I have an endianness problem. In the file, The u2 data are stored in 
big-endian order. As I am working on a Pentium, the reading is done in 
little-endian order. Is it possible to fix it with the representation 
stuff ?

Thanks,

Olivier

Ludovic Brenta wrote:
> 
> I would create a record type with one discriminant for each array,
> like so:
> 
> type Constant_Pool_Array is array (Positive range <>) of cp_info;
> type Interfaces_Array is array (Positive range <>) of u2;
> -- etc.
> 
> type Class_File
>   (constant_pool_count,
>    interfaces_count,
>    fields_count,
>    methods_count,
>    attributes_count : u2)
> is record
>    ...
>    constant_pool : Constant_Pool_Array (2 .. constant_pool_count);
>    ...
>    interfaces : Interfaces_Array (1 .. interfaces_count);
>    ... etc.
> end record;
> 
>> Also how can I fill this array ?
> 
> You would normally simply call the predefined Class_File'Read but this
> wouldn't work since the order of the components in type Class_File
> does not match the order in the file. So, you'd specify your own Read:
> 
> function Input(
>    Stream : not null access Ada.Streams.Root_Stream_Type'Class)
>    return Class_File); -- see RM 13.13(22) and following
> for Class_File'Input use Input; -- as per RM 13.13(38/2)
> 
> function Input(
>    Stream : not null access Ada.Streams.Root_Stream_Type'Class)
>    return Class_File)
> is
>    Constant_Pool_Count : u2;
>    type Constant_Pool_Array_Access is access Constant_Pool_Array;
>    procedure Free is new Ada.Unchecked_Deallocation
>      (Constant_Pool_Array, Constant_Pool_Array_Access);
>    Constant_Pool : Constant_Pool_Array_Access;
> begin
>    ...
>    u2'Read (Stream, Constant_Pool_Count);
>    Constant_Pool := new Constant_Pool_Array (1 .. Constant_Pool - 1);
>    Constant_Pool_Array'Read (Stream, Constant_Pool.all);
>    ...
> 
> After reading all members, construct the result:
> 
> declare
>    Result : Class_File
>   (constant_pool_count => Constant_Pool_Count,
>    interfaces_count => Interfaces_Count,
>    fields_count => Fields_Count,
>    methods_count => Methods_Count,
>    attributes_count => Attricutes_Count);
> begin
>    Result.Constant_Pool := Constant_Pool.all;
>    ...
>    Free (Constant_Pool);
>    ...
>    return Result;
> end;
> end Input;
> 
> You can also eliminate the use of access types and dynamic allocation
> and deallocation by nesting declare blocks, e.g.
> 
> u2'Read (Stream, Constant_Pool_Count);
> declare
>    Constant_Pool : Constant_Pool_Array (1 .. Constant_Pool_Count);
> begin
>    Constant_Pool_Array'Read (Stream, Constant_Pool);
>    ...
>    u2'Read (Stream, Interfaces_Count);
>    declare
>       Interfaces : Interfaces_Count_Array (1 .. Interfaces_Count);
>    begin
>       ...
>    end;
> end;
> 
> HTH
> 
> --
> Ludovic Brenta.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-19 13:08   ` Olivier Scalbert
@ 2009-04-19 19:52     ` Ludovic Brenta
  2009-04-19 20:27     ` Gautier
  1 sibling, 0 replies; 16+ messages in thread
From: Ludovic Brenta @ 2009-04-19 19:52 UTC (permalink / raw)


Olivier Scalbert wrote on comp.lang.ada:
> I have an endianness problem. In the file, The u2 data are stored in
> big-endian order. As I am working on a Pentium, the reading is done in
> little-endian order. Is it possible to fix it with the representation
> stuff ?

No; Ada's representation clauses only allow you to control bit order,
not
byte order.  On little-endian architectures, you'll have to resort to
something like

procedure Read (Stream : access Ada.Streams.Root_Stream_Type'Class;
                Item : out u2) is
   type Byte is mod 2**8;
   for Byte'Size use 8;
   High_Order, Low_Order : Byte;
begin
   Byte'Read (Stream, High_Order); -- call the predefined Read for
type Byte
   Byte'Read (Stream, Low_Order);
   Item := High_Order * 2**8 + Low_Order;
end Read;

for u2'Read use Read;

HTH

--
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Load an object from a file
  2009-04-19 13:08   ` Olivier Scalbert
  2009-04-19 19:52     ` Ludovic Brenta
@ 2009-04-19 20:27     ` Gautier
  1 sibling, 0 replies; 16+ messages in thread
From: Gautier @ 2009-04-19 20:27 UTC (permalink / raw)


In the GLOBE_3D and Zip-Ada projects (from link below) you'll
find the generic Intel_nb functions that do the I/O by merging/splitting 
integers of various sizes from/to bytes (the way Ludovic described).
It is in the packages GLOBE_3D.IO and Zip.Headers respectively.

On the other hand, I kind of remember having read about a GNAT-only way 
to replace some run-time package to obtain the same with less efforts: 
T'Read could be doable with a specific endianess, no need to load in 
small pieces. Maybe I'm dreaming ?...

_________________________________________________________
Gautier's Ada programming -- http://sf.net/users/gdemont/
NB: For a direct answer, e-mail address on the Web site!



^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2009-04-19 20:27 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-03 12:01 Load an object from a file Olivier Scalbert
2009-04-03 13:07 ` Niklas Holsti
2009-04-03 13:37 ` Ludovic Brenta
2009-04-03 15:19   ` Olivier Scalbert
2009-04-03 16:08     ` Georg Bauhaus
2009-04-03 16:22       ` Ludovic Brenta
2009-04-03 16:41         ` Olivier Scalbert
2009-04-03 16:46       ` Adam Beneschan
2009-04-03 20:22         ` Ludovic Brenta
2009-04-09 20:32   ` Olivier Scalbert
2009-04-09 21:22     ` Ludovic Brenta
2009-04-09 22:22       ` Olivier Scalbert
2009-04-19 13:08   ` Olivier Scalbert
2009-04-19 19:52     ` Ludovic Brenta
2009-04-19 20:27     ` Gautier
2009-04-03 13:41 ` Thomas Løcke

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox