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))
            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
    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? – Bart van Ingen Schenau Jun 15 '20 at 9:16
  • Is this Java? .. – Robert Harvey Jun 15 '20 at 20:49

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 introduces 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
    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. – Robert Harvey Jun 15 '20 at 19:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.