* Handling of unfriendly data structures
@ 2002-09-15 13:48 L. Siever
2002-09-15 20:26 ` tmoran
2002-09-15 21:54 ` Nick Roberts
0 siblings, 2 replies; 3+ messages in thread
From: L. Siever @ 2002-09-15 13:48 UTC (permalink / raw)
Hello,
I'm getting a block of binary data from a proprietary communication
channel.
I've successfully read the data in an array of U8 :)
Now I've to interpret the data.
The problem is that the block has a rather unfriendly data structure.
type U8 is mod 2 ** 8;
type U8 is mod 2 ** 14;
type part_a is record
a_byte : U8;
b_byte : U14;
...
many more bits of many differnt types
...
size : U8;
end record;
type part_b is record
a_byte : U8;
b_byte : U8;
...
many more bits of many differnt types
...
size : U8;
end record;
...
type part_y is record
..
The layout of a block looks like this:
part_a
text string -- size is stored in part_a
part_b
text string -- size is stored in part_b
..
..
part_y
text string -- size is stored in part_y
next block:
part_a
And finaly my question is:
What would be the "Ada-way" to implement this, considering that
the code should run on little- and big-endian with 32 and 64 bit
plattforms.
My idea is to copy&convert somehow the data into the records.
Since I've alot of differnt records, I wonder if any OO aproaches
would be possible and efficient? (I'm new to OOP)
Linda
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Handling of unfriendly data structures
2002-09-15 13:48 Handling of unfriendly data structures L. Siever
@ 2002-09-15 20:26 ` tmoran
2002-09-15 21:54 ` Nick Roberts
1 sibling, 0 replies; 3+ messages in thread
From: tmoran @ 2002-09-15 20:26 UTC (permalink / raw)
> What would be the "Ada-way" to implement this, considering that
That depends somewhat on how to will want to access the data after
reading a block. You seem to have declarations for part_? and
you could declare
type string_access is access string;
type block_type is new ada.finalization.limited_controlled with record
a : part_a;
a_text : string_access;
b : part_b;
b_text : string_access;
...
y : part_y;
y_text : string_access;
end record;
procedure read_a_block(block : out block_type);
private
procedure finalize(block : in out block_type); -- free allocated ?_text's
If your program wants to access things sequentially, ie, the things in
a_part, then a_text, then the items in b_part, then b_text, etc, then you
might instead want to write a routine that reads a
part_a, doing endianness conversion as needed and returning a part_a to
its caller, and similar routines for part_b etc. and finally a text
reader that uses its output size to read the right number of characters.
Using Ada.Streams, for instance, you could then write something like:
part_a'read(stream, a);
declare
a_text : string(1 .. a.size);
begin
text'read(stream, a_text);
-- process the part_a and a_text stuff
end;
part_b'read(stream, b);
declare
b_text : string(1 .. b.size);
begin
text'read(stream, b_text);
-- process the part_b and b_text stuff
end;
...
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Handling of unfriendly data structures
2002-09-15 13:48 Handling of unfriendly data structures L. Siever
2002-09-15 20:26 ` tmoran
@ 2002-09-15 21:54 ` Nick Roberts
1 sibling, 0 replies; 3+ messages in thread
From: Nick Roberts @ 2002-09-15 21:54 UTC (permalink / raw)
On 15 Sep 2002 06:48:54 -0700, lsiever6619@yahoo.com (L. Siever) strongly
typed:
>Hello,
>I'm getting a block of binary data from a proprietary communication
>channel. I've successfully read the data in an array of U8 :)
>
>Now I've to interpret the data.
>The problem is that the block has a rather unfriendly data structure.
>
>type U8 is mod 2 ** 8;
>type U8 is mod 2 ** 14;
[Presumably intended to be:]
>type U14 is mod 2 ** 14;
>type part_a is record
> a_byte : U8;
> b_byte : U14;
>...
>What would be the "Ada-way" to implement this, considering that
>the code should run on little- and big-endian with 32 and 64 bit
>plattforms.
>
>My idea is to copy&convert somehow the data into the records.
>Since I've alot of differnt records, I wonder if any OO aproaches
>would be possible and efficient? (I'm new to OOP)
Yes an object-oriented approach may well be highly suitable (and
efficient). The Ada Way to deal with the above problem is very likely to be
something like the following.
Declare a tagged, possibly abstract, base type upon which to 'hang' the
different record types for the different variations of data item you are
receiving. E.g.:
package MyTalk_IO is
type General_Packet is abstract tagged private;
procedure Process (Packet: in out General_Packet) is abstract;
...
type Protocol_Negotiation_Packet is new General_Packet with
record
...
end record;
...
Now, Ada defines two special 'stream I/O' procedures for each subtype T:
T'Read and T'Write. It provides default implementations (which are based on
the base type of T, not what we want), but these can be overridden by your
own implementations if you wish. So:
procedure Read_PNC (Stream: access Ada.Streams.Root_Stream_Type'Class;
Item: out Protocol_Negotiation_Packet) is
Buffer: Ada.Streams.Stream_Element_Array(0..?);
begin
-- read elements and unravel bits into relevant parts of Item
end;
for Protocol_Negotiation_Packet'Read use Read_PNC;
You do the same (in reverse) for Write. Strong hint: don't assume a stream
element is a byte. Either test that it is, or use Ada.Stream_Element'Size
in all your code.
The communications paths (in and out) will need wrappers to make them into
streams.
You will probably need to write a special procedure that is capable of
distinguishing which type of packet has been sent (if it cannot do this in
advance, it will have to read the packet into a stream element buffer, and
then make the buffer available to the other Read procedures as a stream),
so that it can be used to read a General_Packet'Class object (either
directly, in which it may need to be a function, or indirectly via an
access value). Suppose it's a function called Input:
function Input (Stream: access Ada.Streams.Root_Stream_Type'Class)
return General_Packet'Class;
You will then have a main loop that goes something like:
loop
Process(Input(Comm_Stream_In));
exit when Stop_Flag;
end loop;
The Process procedure is dynamically (polymorphically) selected according
to the type of packet returned by Input on each iteration of the loop.
(This is the essence of an object-oriented solution.)
If you are careful in writing the Read and Write routines, you can make
your code portable across different architectures. Sometimes an easier
approach is to 'factor' these off (e.g. into separate bodies) and write a
different implementation for each different architecture (if you do this,
ensure your code tests that the implementation architecture matches the
compiler's target).
Look in the Ada reference manual for details about streams and stream I/O,
as well as representation clauses. (But beware, on a portability note, that
different compilers have different levels of support for representation.)
Look in books on the subject, if you can get your hands on any.
Finally, if you have further (more detailed) questions, ask away in this
place.
Hope This Helps.
--
Nick Roberts
Per Ardua ad Disastra
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2002-09-15 21:54 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-15 13:48 Handling of unfriendly data structures L. Siever
2002-09-15 20:26 ` tmoran
2002-09-15 21:54 ` Nick Roberts
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox