Search code examples
c#binarywriter

Bit-Based BinaryWriter in C#


I'm working on a bit-based B/W/Greyscale Pre-Compiled font format, and was having issues with either reading or writing the format, (I've not been able to determine where the issue was. (I do have a B/W bit-based version working, but an Aliased font doesn't look too good, as you can imagine, especially when working with a 320x200 pixel screen) ) but decided that just using a BinaryWriter would be much easier than writing to a bool[] when I pulled the image data.

The basic format of a pixel in the file looks like this:

1 - White Pixel (Shortest, as this would be most of the pixels)

00 - Black Pixel (No reason to write 10-bits for a pure black pixel, which there are a reasonable number of)

01 - Greyscale Pixel, and is followed by 1 byte describing the shade of the pixel

Now, everything is fine and dandy with writing the required info, as that's all full bytes, but the default .Net 4.0 BinaryWriter writes a Boolean value as a full byte, and as you can imagine, that negates the use of a bit-based format. So I was wondering, is there a BinaryWriter, (and BinaryReader) implementation out there that's bit-based

Edit: I ended up creating my own. (See the answer for the code.)


Solution

  • I ended up writing my own, so here they are.

    The BinaryWriter (I've only overridden the ones that I needed)

    private class BinaryWriter : System.IO.BinaryWriter
    {
        private bool[] curByte = new bool[8];
        private byte curBitIndx = 0;
        private System.Collections.BitArray ba;
    
        public BinaryWriter(Stream s) : base(s) { }
    
        public override void Flush()
        {
            base.Write(ConvertToByte(curByte));
            base.Flush();
        }
    
        public override void Write(bool value)
        {
            curByte[curBitIndx] = value;
            curBitIndx++;
    
            if (curBitIndx == 8)
            {
                base.Write(ConvertToByte(curByte));
                this.curBitIndx = 0;
                this.curByte = new bool[8];
            }
        }
    
        public override void Write(byte value)
        {
            ba = new BitArray(new byte[] { value });
            for (byte i = 0; i < 8; i++)
            {
                this.Write(ba[i]);
            }
            ba = null;
        }
    
        public override void Write(byte[] buffer)
        {
            for (int i = 0; i < buffer.Length; i++)
            {
                this.Write((byte)buffer[i]);
            }
        }
    
        public override void Write(uint value)
        {
            ba = new BitArray(BitConverter.GetBytes(value));
            for (byte i = 0; i < 32; i++)
            {
                this.Write(ba[i]);
            }
            ba = null;
        }
    
        public override void Write(ulong value)
        {
            ba = new BitArray(BitConverter.GetBytes(value));
            for (byte i = 0; i < 64; i++)
            {
                this.Write(ba[i]);
            }
            ba = null;
        }
    
        public override void Write(ushort value)
        {
            ba = new BitArray(BitConverter.GetBytes(value));
            for (byte i = 0; i < 16; i++)
            {
                this.Write(ba[i]);
            }
            ba = null;
        }
    
        private static byte ConvertToByte(bool[] bools)
        {
            byte b = 0;
    
            byte bitIndex = 0;
            for (int i = 0; i < 8; i++)
            {
                if (bools[i])
                {
                    b |= (byte)(((byte)1) << bitIndex);
                }
                bitIndex++;
            }
    
            return b;
        }
    }
    

    And, the BinaryReader, once again, I've only overridden the methods that I needed.

    private class BinaryReader : System.IO.BinaryReader
    {
        private bool[] curByte = new bool[8];
        private byte curBitIndx = 0;
        private BitArray ba;
    
        public BinaryReader(Stream s) : base(s)
        {
            ba = new BitArray(new byte[] { base.ReadByte() });
            ba.CopyTo(curByte, 0);
            ba = null;
        }
    
        public override bool ReadBoolean()
        {
            if (curBitIndx == 8)
            {
                ba = new BitArray(new byte[] { base.ReadByte() });
                ba.CopyTo(curByte, 0);
                ba = null;
                this.curBitIndx = 0;
            }
    
            bool b = curByte[curBitIndx];
            curBitIndx++;
            return b;
        }
    
        public override byte ReadByte()
        {
            bool[] bar = new bool[8];
            byte i;
            for (i = 0; i < 8; i++)
            {
                bar[i] = this.ReadBoolean();
            }
    
            byte b = 0;
            byte bitIndex = 0;
            for (i = 0; i < 8; i++)
            {
                if (bar[i])
                {
                    b |= (byte)(((byte)1) << bitIndex);
                }
                bitIndex++;
            }
            return b;
        }
    
        public override byte[] ReadBytes(int count)
        {
            byte[] bytes = new byte[count];
            for (int i = 0; i < count; i++)
            {
                bytes[i] = this.ReadByte();
            }
            return bytes;
        }
    
        public override ushort ReadUInt16()
        {
            byte[] bytes = ReadBytes(2);
            return BitConverter.ToUInt16(bytes, 0);
        }
    
        public override uint ReadUInt32()
        {
            byte[] bytes = ReadBytes(4);
            return BitConverter.ToUInt32(bytes, 0);
        }
    
        public override ulong ReadUInt64()
        {
            byte[] bytes = ReadBytes(8);
            return BitConverter.ToUInt64(bytes, 0);
        }
    }