How can one simplify network byte-order conversion from a BinaryReader?

11,920

Solution 1

There is no built-in converter. Here's my wrapper (as you can see, I only implemented the functionality I needed but the structure is pretty easy to change to your liking):

/// <summary>
/// Utilities for reading big-endian files
/// </summary>
public class BigEndianReader
{
    public BigEndianReader(BinaryReader baseReader)
    {
        mBaseReader = baseReader;
    }

    public short ReadInt16()
    {
        return BitConverter.ToInt16(ReadBigEndianBytes(2), 0);
    }

    public ushort ReadUInt16()
    {
        return BitConverter.ToUInt16(ReadBigEndianBytes(2), 0);
    }

    public uint ReadUInt32()
    {
        return BitConverter.ToUInt32(ReadBigEndianBytes(4), 0);
    }

    public byte[] ReadBigEndianBytes(int count)
    {
        byte[] bytes = new byte[count];
        for (int i = count - 1; i >= 0; i--)
            bytes[i] = mBaseReader.ReadByte();

        return bytes;
    }

    public byte[] ReadBytes(int count)
    {
        return mBaseReader.ReadBytes(count);
    }

    public void Close()
    {
        mBaseReader.Close();
    }

    public Stream BaseStream
    {
        get { return mBaseReader.BaseStream;  }
    }

    private BinaryReader mBaseReader;
}

Basically, ReadBigEndianBytes does the grunt work, and this is passed to a BitConverter. There will be a definite problem if you read a large number of bytes since this will cause a large memory allocation.

Solution 2

I built a custom BinaryReader to handle all of this. It's available as part of my Nextem library. It also has a very easy way of defining binary structs, which I think will help you here -- check out the Examples.

Note: It's only in SVN right now, but very stable. If you have any questions, email me at cody_dot_brocious_at_gmail_dot_com.

Share:
11,920
Zach Lute
Author by

Zach Lute

I'm awesome.

Updated on July 01, 2022

Comments

  • Zach Lute
    Zach Lute almost 2 years

    System.IO.BinaryReader reads values in a little-endian format.

    I have a C# application connecting to a proprietary networking library on the server side. The server-side sends everything down in network byte order, as one would expect, but I find that dealing with this on the client side is awkward, particularly for unsigned values.

    UInt32 length = (UInt32)IPAddress.NetworkToHostOrder(reader.ReadInt32());
    

    is the only way I've come up with to get a correct unsigned value out of the stream, but this seems both awkward and ugly, and I have yet to test if that's just going to clip off high-order values so that I have to do fun BitConverter stuff.

    Is there some way I'm missing short of writing a wrapper around the whole thing to avoid these ugly conversions on every read? It seems like there should be an endian-ness option on the reader to make things like this simpler, but I haven't come across anything.

  • Zach Lute
    Zach Lute over 15 years
    Thanks. I was kind of hoping to avoid picking up an additional library dependency, since this whole thing really should be fairly small and simple, but I'll keep it in mind. Nice to see the license is unambiguous, though. :)
  • Serafina Brocious
    Serafina Brocious over 15 years
    Ah, I see. Well, I hope it works for you if you choose to go with it. And yea, I went public domain for just that reason -- I want people to be able to do absolutely anything they want with it, and the components are small enough that getting patches back isn't of any concern :)
  • Dr. Funk
    Dr. Funk almost 8 years
    Note: Array.Reverse() will reverse the order of your array in place.
  • Thorham
    Thorham almost 5 years
    Reading single bytes is potentially quite slow. Better read as many bytes as possible in one go. Also, endian conversion is fastest using the traditional bit wise conversion solutions. Not a big deal for small amounts of data, of course.