1 // 2 // ByteBuffer.cs 3 // 4 // Author: 5 // Jb Evain (jbevain@gmail.com) 6 // 7 // Copyright (c) 2008 - 2011 Jb Evain 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining 10 // a copy of this software and associated documentation files (the 11 // "Software"), to deal in the Software without restriction, including 12 // without limitation the rights to use, copy, modify, merge, publish, 13 // distribute, sublicense, and/or sell copies of the Software, and to 14 // permit persons to whom the Software is furnished to do so, subject to 15 // the following conditions: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 // 28 29 using System; 30 31 namespace Mono.Cecil.PE { 32 33 class ByteBuffer { 34 35 internal byte [] buffer; 36 internal int length; 37 internal int position; 38 ByteBuffer()39 public ByteBuffer () 40 { 41 this.buffer = Empty<byte>.Array; 42 } 43 ByteBuffer(int length)44 public ByteBuffer (int length) 45 { 46 this.buffer = new byte [length]; 47 } 48 ByteBuffer(byte [] buffer)49 public ByteBuffer (byte [] buffer) 50 { 51 this.buffer = buffer ?? Empty<byte>.Array; 52 this.length = this.buffer.Length; 53 } 54 Reset(byte [] buffer)55 public void Reset (byte [] buffer) 56 { 57 this.buffer = buffer ?? Empty<byte>.Array; 58 this.length = this.buffer.Length; 59 } 60 Advance(int length)61 public void Advance (int length) 62 { 63 position += length; 64 } 65 ReadByte()66 public byte ReadByte () 67 { 68 return buffer [position++]; 69 } 70 ReadSByte()71 public sbyte ReadSByte () 72 { 73 return (sbyte) ReadByte (); 74 } 75 ReadBytes(int length)76 public byte [] ReadBytes (int length) 77 { 78 var bytes = new byte [length]; 79 Buffer.BlockCopy (buffer, position, bytes, 0, length); 80 position += length; 81 return bytes; 82 } 83 ReadUInt16()84 public ushort ReadUInt16 () 85 { 86 ushort value = (ushort) (buffer [position] 87 | (buffer [position + 1] << 8)); 88 position += 2; 89 return value; 90 } 91 ReadInt16()92 public short ReadInt16 () 93 { 94 return (short) ReadUInt16 (); 95 } 96 ReadUInt32()97 public uint ReadUInt32 () 98 { 99 uint value = (uint) (buffer [position] 100 | (buffer [position + 1] << 8) 101 | (buffer [position + 2] << 16) 102 | (buffer [position + 3] << 24)); 103 position += 4; 104 return value; 105 } 106 ReadInt32()107 public int ReadInt32 () 108 { 109 return (int) ReadUInt32 (); 110 } 111 ReadUInt64()112 public ulong ReadUInt64 () 113 { 114 uint low = ReadUInt32 (); 115 uint high = ReadUInt32 (); 116 117 return (((ulong) high) << 32) | low; 118 } 119 ReadInt64()120 public long ReadInt64 () 121 { 122 return (long) ReadUInt64 (); 123 } 124 ReadCompressedUInt32()125 public uint ReadCompressedUInt32 () 126 { 127 byte first = ReadByte (); 128 if ((first & 0x80) == 0) 129 return first; 130 131 if ((first & 0x40) == 0) 132 return ((uint) (first & ~0x80) << 8) 133 | ReadByte (); 134 135 return ((uint) (first & ~0xc0) << 24) 136 | (uint) ReadByte () << 16 137 | (uint) ReadByte () << 8 138 | ReadByte (); 139 } 140 ReadCompressedInt32()141 public int ReadCompressedInt32 () 142 { 143 var value = (int) (ReadCompressedUInt32 () >> 1); 144 if ((value & 1) == 0) 145 return value; 146 if (value < 0x40) 147 return value - 0x40; 148 if (value < 0x2000) 149 return value - 0x2000; 150 if (value < 0x10000000) 151 return value - 0x10000000; 152 return value - 0x20000000; 153 } 154 ReadSingle()155 public float ReadSingle () 156 { 157 if (!BitConverter.IsLittleEndian) { 158 var bytes = ReadBytes (4); 159 Array.Reverse (bytes); 160 return BitConverter.ToSingle (bytes, 0); 161 } 162 163 float value = BitConverter.ToSingle (buffer, position); 164 position += 4; 165 return value; 166 } 167 ReadDouble()168 public double ReadDouble () 169 { 170 if (!BitConverter.IsLittleEndian) { 171 var bytes = ReadBytes (8); 172 Array.Reverse (bytes); 173 return BitConverter.ToDouble (bytes, 0); 174 } 175 176 double value = BitConverter.ToDouble (buffer, position); 177 position += 8; 178 return value; 179 } 180 181 #if !READ_ONLY 182 WriteByte(byte value)183 public void WriteByte (byte value) 184 { 185 if (position == buffer.Length) 186 Grow (1); 187 188 buffer [position++] = value; 189 190 if (position > length) 191 length = position; 192 } 193 WriteSByte(sbyte value)194 public void WriteSByte (sbyte value) 195 { 196 WriteByte ((byte) value); 197 } 198 WriteUInt16(ushort value)199 public void WriteUInt16 (ushort value) 200 { 201 if (position + 2 > buffer.Length) 202 Grow (2); 203 204 buffer [position++] = (byte) value; 205 buffer [position++] = (byte) (value >> 8); 206 207 if (position > length) 208 length = position; 209 } 210 WriteInt16(short value)211 public void WriteInt16 (short value) 212 { 213 WriteUInt16 ((ushort) value); 214 } 215 WriteUInt32(uint value)216 public void WriteUInt32 (uint value) 217 { 218 if (position + 4 > buffer.Length) 219 Grow (4); 220 221 buffer [position++] = (byte) value; 222 buffer [position++] = (byte) (value >> 8); 223 buffer [position++] = (byte) (value >> 16); 224 buffer [position++] = (byte) (value >> 24); 225 226 if (position > length) 227 length = position; 228 } 229 WriteInt32(int value)230 public void WriteInt32 (int value) 231 { 232 WriteUInt32 ((uint) value); 233 } 234 WriteUInt64(ulong value)235 public void WriteUInt64 (ulong value) 236 { 237 if (position + 8 > buffer.Length) 238 Grow (8); 239 240 buffer [position++] = (byte) value; 241 buffer [position++] = (byte) (value >> 8); 242 buffer [position++] = (byte) (value >> 16); 243 buffer [position++] = (byte) (value >> 24); 244 buffer [position++] = (byte) (value >> 32); 245 buffer [position++] = (byte) (value >> 40); 246 buffer [position++] = (byte) (value >> 48); 247 buffer [position++] = (byte) (value >> 56); 248 249 if (position > length) 250 length = position; 251 } 252 WriteInt64(long value)253 public void WriteInt64 (long value) 254 { 255 WriteUInt64 ((ulong) value); 256 } 257 WriteCompressedUInt32(uint value)258 public void WriteCompressedUInt32 (uint value) 259 { 260 if (value < 0x80) 261 WriteByte ((byte) value); 262 else if (value < 0x4000) { 263 WriteByte ((byte) (0x80 | (value >> 8))); 264 WriteByte ((byte) (value & 0xff)); 265 } else { 266 WriteByte ((byte) ((value >> 24) | 0xc0)); 267 WriteByte ((byte) ((value >> 16) & 0xff)); 268 WriteByte ((byte) ((value >> 8) & 0xff)); 269 WriteByte ((byte) (value & 0xff)); 270 } 271 } 272 WriteCompressedInt32(int value)273 public void WriteCompressedInt32 (int value) 274 { 275 if (value >= 0) { 276 WriteCompressedUInt32 ((uint) (value << 1)); 277 return; 278 } 279 280 if (value > -0x40) 281 value = 0x40 + value; 282 else if (value >= -0x2000) 283 value = 0x2000 + value; 284 else if (value >= -0x20000000) 285 value = 0x20000000 + value; 286 287 WriteCompressedUInt32 ((uint) ((value << 1) | 1)); 288 } 289 WriteBytes(byte [] bytes)290 public void WriteBytes (byte [] bytes) 291 { 292 var length = bytes.Length; 293 if (position + length > buffer.Length) 294 Grow (length); 295 296 Buffer.BlockCopy (bytes, 0, buffer, position, length); 297 position += length; 298 299 if (position > this.length) 300 this.length = position; 301 } 302 WriteBytes(int length)303 public void WriteBytes (int length) 304 { 305 if (position + length > buffer.Length) 306 Grow (length); 307 308 position += length; 309 310 if (position > this.length) 311 this.length = position; 312 } 313 WriteBytes(ByteBuffer buffer)314 public void WriteBytes (ByteBuffer buffer) 315 { 316 if (position + buffer.length > this.buffer.Length) 317 Grow (buffer.length); 318 319 Buffer.BlockCopy (buffer.buffer, 0, this.buffer, position, buffer.length); 320 position += buffer.length; 321 322 if (position > this.length) 323 this.length = position; 324 } 325 WriteSingle(float value)326 public void WriteSingle (float value) 327 { 328 var bytes = BitConverter.GetBytes (value); 329 330 if (!BitConverter.IsLittleEndian) 331 Array.Reverse (bytes); 332 333 WriteBytes (bytes); 334 } 335 WriteDouble(double value)336 public void WriteDouble (double value) 337 { 338 var bytes = BitConverter.GetBytes (value); 339 340 if (!BitConverter.IsLittleEndian) 341 Array.Reverse (bytes); 342 343 WriteBytes (bytes); 344 } 345 Grow(int desired)346 void Grow (int desired) 347 { 348 var current = this.buffer; 349 var current_length = current.Length; 350 351 var buffer = new byte [System.Math.Max (current_length + desired, current_length * 2)]; 352 Buffer.BlockCopy (current, 0, buffer, 0, current_length); 353 this.buffer = buffer; 354 } 355 356 #endif 357 358 } 359 } 360