buffer to struct type conversion...TArrayStream?

via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Mar 19 11:42:02 PDT 2015


On Thursday, 19 March 2015 at 17:48:00 UTC, Charles Hixson wrote:
> I've read a chunk of data into a buffer and want to convert it 
> into a struct.  The reading routine is in a class that doesn't 
> know about the struct, but the size should be exactly the same.
>  (I.e., I want to use the converse procedure to write it.)
>
> Is there a better way to do this than using TArrayStream?
>
> The idea here is to have a file of fixed length records (rather 
> like Fortran binary records, except that there's a header 
> record which is a different size and which specifies various 
> things about the file).  The class (well, struct) that handles 
> the fixed length records only knows what the record size is, 
> and a couple of other quite general things.  The class which 
> uses it holds each record in a fixed length struct with no 
> indirections.  So I thought I could just cast the buffer to the 
> struct...but this doesn't work.  Every straightforward way I've 
> tried of doing it yields:
> Error: cannot cast from Node_ to ubyte[]
> or something reasonably analogous.  The current version of the 
> (non-working) code is:
>         ubyte    buf[];

Please use D-style array declarations, the syntax you're using is 
deprecated:
ubyte[] buf;

>         auto    len    =    btFile.read(nodeId, buf);
>         assert    (len == n.self.sizeof);
>
>
>         n.self    =    to!(Node.Node_)(buf);
>         //    TODO    write the code
> which yields the error:
> Error: template instance std.conv.to!(Node_).to!(ubyte[]) error 
> instantiating

If you want to reinterpret a byte array as another type, there 
are three ways:

1) Using a cast (unsafe):
    n.self = *cast(Node.Node_*)buf.ptr;

2) With a union:
    union {
        ubyte[Node.Node_.sizeof] asBytes;
        Node.Node_ asNode;
    } buf;
    auto len = btFile.read(nodeId, buf.asBytes[]);
    assert(len == n.self.sizeof);
    n.self = buf.asNode

3) Using std.bitmap.peek(), which also supports conversion 
between big- and little-endian:
    import std.bitmap;
    n.self = buf.peek!(Node.Node_, Endian.bigEndian);

(The examples are untested, it's possible you'll need to make 
some adjustments to make them work.)

You should probably use option 3). It is safe, because it checks 
that the buffer has the right size, and it also allows you to 
specify the endian-ness (many file formats have a standardized 
endian-ness).

While you're at it, you can also try std.bitmanip.read(). It can 
be applied to any range, so you can probably do something like 
this (also untested):

     auto input = btFile.byChunk(4096).joiner;
     while(!input.empty) {
         auto node = input.read!(Node.Node_, Endian.bigEndian);
         // use `node`
     }


More information about the Digitalmars-d-learn mailing list