0

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?

3
  • 1
    Does a 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? Commented Jun 15, 2020 at 9:16
  • Is this Java? .. Commented Jun 15, 2020 at 20:49
  • I suggest splitting into two classes, one for reading and one for writing. Greatly simplifies things. Commented Nov 24, 2021 at 17:52

1 Answer 1

2

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.

1
  • 4
    I 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. Commented Jun 15, 2020 at 19:52

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.