// // Author: // Jb Evain (jbevain@gmail.com) // // Copyright (c) 2008 - 2015 Jb Evain // Copyright (c) 2008 - 2011 Novell, Inc. // // Licensed under the MIT/X11 license. // using System; namespace Mono.Cecil.PE { class ByteBuffer { internal byte [] buffer; internal int length; internal int position; public ByteBuffer () { this.buffer = Empty.Array; } public ByteBuffer (int length) { this.buffer = new byte [length]; } public ByteBuffer (byte [] buffer) { this.buffer = buffer ?? Empty.Array; this.length = this.buffer.Length; } public void Advance (int length) { position += length; } public byte ReadByte () { return buffer [position++]; } public sbyte ReadSByte () { return (sbyte) ReadByte (); } public byte [] ReadBytes (int length) { var bytes = new byte [length]; Buffer.BlockCopy (buffer, position, bytes, 0, length); position += length; return bytes; } public ushort ReadUInt16 () { ushort value = (ushort) (buffer [position] | (buffer [position + 1] << 8)); position += 2; return value; } public short ReadInt16 () { return (short) ReadUInt16 (); } public uint ReadUInt32 () { uint value = (uint) (buffer [position] | (buffer [position + 1] << 8) | (buffer [position + 2] << 16) | (buffer [position + 3] << 24)); position += 4; return value; } public int ReadInt32 () { return (int) ReadUInt32 (); } public ulong ReadUInt64 () { uint low = ReadUInt32 (); uint high = ReadUInt32 (); return (((ulong) high) << 32) | low; } public long ReadInt64 () { return (long) ReadUInt64 (); } public uint ReadCompressedUInt32 () { byte first = ReadByte (); if ((first & 0x80) == 0) return first; if ((first & 0x40) == 0) return ((uint) (first & ~0x80) << 8) | ReadByte (); return ((uint) (first & ~0xc0) << 24) | (uint) ReadByte () << 16 | (uint) ReadByte () << 8 | ReadByte (); } public int ReadCompressedInt32 () { var b = buffer [position]; var u = (int) ReadCompressedUInt32 (); var v = u >> 1; if ((u & 1) == 0) return v; switch (b & 0xc0) { case 0: case 0x40: return v - 0x40; case 0x80: return v - 0x2000; default: return v - 0x10000000; } } public float ReadSingle () { if (!BitConverter.IsLittleEndian) { var bytes = ReadBytes (4); Array.Reverse (bytes); return BitConverter.ToSingle (bytes, 0); } float value = BitConverter.ToSingle (buffer, position); position += 4; return value; } public double ReadDouble () { if (!BitConverter.IsLittleEndian) { var bytes = ReadBytes (8); Array.Reverse (bytes); return BitConverter.ToDouble (bytes, 0); } double value = BitConverter.ToDouble (buffer, position); position += 8; return value; } #if !READ_ONLY public void WriteByte (byte value) { if (position == buffer.Length) Grow (1); buffer [position++] = value; if (position > length) length = position; } public void WriteSByte (sbyte value) { WriteByte ((byte) value); } public void WriteUInt16 (ushort value) { if (position + 2 > buffer.Length) Grow (2); buffer [position++] = (byte) value; buffer [position++] = (byte) (value >> 8); if (position > length) length = position; } public void WriteInt16 (short value) { WriteUInt16 ((ushort) value); } public void WriteUInt32 (uint value) { if (position + 4 > buffer.Length) Grow (4); buffer [position++] = (byte) value; buffer [position++] = (byte) (value >> 8); buffer [position++] = (byte) (value >> 16); buffer [position++] = (byte) (value >> 24); if (position > length) length = position; } public void WriteInt32 (int value) { WriteUInt32 ((uint) value); } public void WriteUInt64 (ulong value) { if (position + 8 > buffer.Length) Grow (8); buffer [position++] = (byte) value; buffer [position++] = (byte) (value >> 8); buffer [position++] = (byte) (value >> 16); buffer [position++] = (byte) (value >> 24); buffer [position++] = (byte) (value >> 32); buffer [position++] = (byte) (value >> 40); buffer [position++] = (byte) (value >> 48); buffer [position++] = (byte) (value >> 56); if (position > length) length = position; } public void WriteInt64 (long value) { WriteUInt64 ((ulong) value); } public void WriteCompressedUInt32 (uint value) { if (value < 0x80) WriteByte ((byte) value); else if (value < 0x4000) { WriteByte ((byte) (0x80 | (value >> 8))); WriteByte ((byte) (value & 0xff)); } else { WriteByte ((byte) ((value >> 24) | 0xc0)); WriteByte ((byte) ((value >> 16) & 0xff)); WriteByte ((byte) ((value >> 8) & 0xff)); WriteByte ((byte) (value & 0xff)); } } public void WriteCompressedInt32 (int value) { if (value >= 0) { WriteCompressedUInt32 ((uint) (value << 1)); return; } if (value > -0x40) value = 0x40 + value; else if (value >= -0x2000) value = 0x2000 + value; else if (value >= -0x20000000) value = 0x20000000 + value; WriteCompressedUInt32 ((uint) ((value << 1) | 1)); } public void WriteBytes (byte [] bytes) { var length = bytes.Length; if (position + length > buffer.Length) Grow (length); Buffer.BlockCopy (bytes, 0, buffer, position, length); position += length; if (position > this.length) this.length = position; } public void WriteBytes (int length) { if (position + length > buffer.Length) Grow (length); position += length; if (position > this.length) this.length = position; } public void WriteBytes (ByteBuffer buffer) { if (position + buffer.length > this.buffer.Length) Grow (buffer.length); Buffer.BlockCopy (buffer.buffer, 0, this.buffer, position, buffer.length); position += buffer.length; if (position > this.length) this.length = position; } public void WriteSingle (float value) { var bytes = BitConverter.GetBytes (value); if (!BitConverter.IsLittleEndian) Array.Reverse (bytes); WriteBytes (bytes); } public void WriteDouble (double value) { var bytes = BitConverter.GetBytes (value); if (!BitConverter.IsLittleEndian) Array.Reverse (bytes); WriteBytes (bytes); } void Grow (int desired) { var current = this.buffer; var current_length = current.Length; var buffer = new byte [System.Math.Max (current_length + desired, current_length * 2)]; Buffer.BlockCopy (current, 0, buffer, 0, current_length); this.buffer = buffer; } #endif } }