using FSO.Files.Utils; using System; using System.IO; namespace FSO.Files.Formats.IFF.Chunks { /// <summary> /// Used to read values from field encoded stream. /// </summary> public class IffFieldEncode : IOProxy { private byte bitPos = 0; private byte curByte = 0; private bool odd = false; public byte[] widths = { 5, 8, 13, 16 }; public byte[] widths2 = { 6, 11, 21, 32 }; public bool StreamEnd; public void setBytePos(int n) { io.Seek(SeekOrigin.Begin, n); curByte = io.ReadByte(); bitPos = 0; } public override ushort ReadUInt16() { return (ushort)ReadField(false); } public override short ReadInt16() { return (short)ReadField(false); } public override int ReadInt32() { return (int)ReadField(true); } public override uint ReadUInt32() { return (uint)ReadField(true); } public override float ReadFloat() { return (float)ReadField(true); //this is incredibly wrong } private long ReadField(bool big) { if (ReadBit() == 0) return 0; uint code = ReadBits(2); byte width = (big) ? widths2[code] : widths[code]; long value = ReadBits(width); value |= -(value & (1 << (width - 1))); return value; } public Tuple<long, int> DebugReadField(bool big) { if (ReadBit() == 0) return new Tuple<long, int>(0, 0); uint code = ReadBits(2); byte width = (big) ? widths2[code] : widths[code]; long value = ReadBits(width); value |= -(value & (1 << (width - 1))); return new Tuple<long, int>(value, width); } public Tuple<byte, byte, bool, long> MarkStream() { return new Tuple<byte, byte, bool, long>(bitPos, curByte, odd, io.Position); } public void RevertToMark(Tuple<byte, byte, bool, long> mark) { StreamEnd = false; bitPos = mark.Item1; curByte = mark.Item2; odd = mark.Item3; io.Seek(SeekOrigin.Begin, mark.Item4); } public uint ReadBits(int n) { uint total = 0; for (int i = 0; i < n; i++) { total += (uint)(ReadBit() << ((n - i) - 1)); } return total; } private byte ReadBit() { byte result = (byte)((curByte & (1 << (7 - bitPos))) >> (7 - bitPos)); if (++bitPos > 7) { bitPos = 0; try { curByte = io.ReadByte(); odd = !odd; } catch (Exception) { curByte = 0; //no more data, read 0 odd = !odd; StreamEnd = true; } } return result; } public string ReadString(bool nextField) { if (bitPos == 0) { io.Seek(SeekOrigin.Current, -1); odd = !odd; } var str = io.ReadNullTerminatedString(); if ((str.Length % 2 == 0) == !odd) io.ReadByte(); //2 byte pad bitPos = 8; if (nextField && io.HasMore) { curByte = io.ReadByte(); odd = true; bitPos = 0; } else { odd = false; } return str; } public IffFieldEncode(IoBuffer io) : base(io) { curByte = io.ReadByte(); odd = !odd; bitPos = 0; } } }