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