336 lines
8.5 KiB
C#
336 lines
8.5 KiB
C#
//
|
|
// 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 MonoFN.Cecil.PE
|
|
{
|
|
internal class ByteBuffer
|
|
{
|
|
internal byte[] buffer;
|
|
internal int length;
|
|
internal int position;
|
|
|
|
public ByteBuffer()
|
|
{
|
|
buffer = Empty<byte>.Array;
|
|
}
|
|
|
|
public ByteBuffer(int length)
|
|
{
|
|
buffer = new byte [length];
|
|
}
|
|
|
|
public ByteBuffer(byte[] buffer)
|
|
{
|
|
this.buffer = buffer ?? Empty<byte>.Array;
|
|
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)
|
|
{
|
|
byte[] 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()
|
|
{
|
|
byte b = buffer[position];
|
|
int u = (int)ReadCompressedUInt32();
|
|
int 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)
|
|
{
|
|
byte[] 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)
|
|
{
|
|
byte[] bytes = ReadBytes(8);
|
|
Array.Reverse(bytes);
|
|
return BitConverter.ToDouble(bytes, 0);
|
|
}
|
|
|
|
double value = BitConverter.ToDouble(buffer, position);
|
|
position += 8;
|
|
return value;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int 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 > length)
|
|
length = position;
|
|
}
|
|
|
|
public void WriteSingle(float value)
|
|
{
|
|
byte[] bytes = BitConverter.GetBytes(value);
|
|
|
|
if (!BitConverter.IsLittleEndian)
|
|
Array.Reverse(bytes);
|
|
|
|
WriteBytes(bytes);
|
|
}
|
|
|
|
public void WriteDouble(double value)
|
|
{
|
|
byte[] bytes = BitConverter.GetBytes(value);
|
|
|
|
if (!BitConverter.IsLittleEndian)
|
|
Array.Reverse(bytes);
|
|
|
|
WriteBytes(bytes);
|
|
}
|
|
|
|
private void Grow(int desired)
|
|
{
|
|
byte[] current = this.buffer;
|
|
int current_length = current.Length;
|
|
|
|
byte[] buffer = new byte [Math.Max(current_length + desired, current_length * 2)];
|
|
Buffer.BlockCopy(current, 0, buffer, 0, current_length);
|
|
this.buffer = buffer;
|
|
}
|
|
}
|
|
} |