From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,1757aa928c05e15f X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2002-09-15 14:53:40 PST Path: archiver1.google.com!news1.google.com!newsfeed.stanford.edu!newsfeed1.bredband.com!bredband!uio.no!feed.news.nacamar.de!fu-berlin.de!uni-berlin.de!pc-62-31-50-169-cr.blueyonder.co.UK!not-for-mail From: nickroberts@blueyonder.co.uk (Nick Roberts) Newsgroups: comp.lang.ada Subject: Re: Handling of unfriendly data structures Date: Sun, 15 Sep 2002 21:54:10 GMT Organization: AdaOS Message-ID: <3d84f5a7.1271030355@news.cis.dfn.de> References: NNTP-Posting-Host: pc-62-31-50-169-cr.blueyonder.co.uk (62.31.50.169) X-Trace: fu-berlin.de 1032126818 2235803 62.31.50.169 (16 [25716]) X-Newsreader: Forte Free Agent 1.21/32.243 Xref: archiver1.google.com comp.lang.ada:28997 Date: 2002-09-15T21:54:10+00:00 List-Id: 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