I have a Buffer which wraps a stream of binary data. The first byte indicates order, either big endian or little endian, which is needed to unpack the data.
class FooBuffer implements Buffer is
private field stream: resource
private field order: int
constructor FooBuffer(stream) is
this.stream = stream
this.order = unpack("C", fread(this.stream, 1)) // unpacking 1 byte unsigned char
method readUnsignedLong():int is
return unpack(this.order ? "V" : "N", fread(this.stream, 4))
method readDouble():double is
method writeUnsignedLong(data):int is
return fwrite(this.stream, pack(this.order ? "V" : "N", data))
method writeDouble(data):int is
// and other methods rewind() eof() seek() close()
There is no problem with reading, but for writing we have to somehow indicate which order to use.
empty_resource = "";
stream = new FooBuffer(empty_resource, SYSTEM_BYTE_ORDER or LITTLE_ENDIAN or BIG_ENDIAN)
Additional parameter to our constructor can be added
constructor FooBuffer(stream, order) is
this.stream = stream
if (this.stream != "")
this.order = unpack("C", fread(this.stream, 1))
else
fwrite(this.stream, pack("C", order))
this.order = order
But in this case we end up with information redundancy, also it's prone to error in case the order and the data do not match.
hex_resource = 0x00ABCDEF010101010101010101010; // all data encoded with big endian 00
stream = new FooBuffer(to_binary(hex_resource), 01) // we pass little endian as order
Now we dont know what is important order value that we put in constructor or order from resource. Do I need a separate factory so I can pass order along with displaced resource pointer?
class FooBufferFactory implements BufferFactory is
private field stream: resource
constructor FooBufferFactory(stream) is
this.stream = stream
method createBuffer():Buffer is
order = unpack("C", fread(this.stream, 1))
// will read correctly because pointer already moved
return new FooBuffer(this.stream, order)
or I need to keep this logic inside constructor, or there is any other solution?
Summary, what is the correct OOP way to read/write binary data if meta information of how data is encoded are stored inside data itself?
1 Answer 1
Endianess is stored in two different places in your code.
- If the stream is not empty, the endianess is a property of the stream.
- If the stream is empty, the endianess is introduced when creating the buffer.
I propose to change the stream to include the endianess property. Its constructor will write the first byte in the stream. The buffer can then read that property from the stream.
-
4I don't agree. A stream is just a stream; it knows nothing about endianness. It's the responsibility of the reader and writer to manage the proper byte order.Robert Harvey– Robert Harvey2020年06月15日 19:52:17 +00:00Commented Jun 15, 2020 at 19:52
FooBuffer
support reading and writing of the same resource? If so, can you read the resource as big-endian and the write it as little-endian?