/Mono.Cecil.PE/ByteBuffer.cs
C# | 336 lines | 263 code | 64 blank | 9 comment | 36 complexity | 2e45d631b077a8ba9d680c1bef3e33e6 MD5 | raw file
1// 2// Author: 3// Jb Evain (jbevain@gmail.com) 4// 5// Copyright (c) 2008 - 2015 Jb Evain 6// Copyright (c) 2008 - 2011 Novell, Inc. 7// 8// Licensed under the MIT/X11 license. 9// 10 11using System; 12 13namespace Mono.Cecil.PE { 14 15 class ByteBuffer { 16 17 internal byte [] buffer; 18 internal int length; 19 internal int position; 20 21 public ByteBuffer () 22 { 23 this.buffer = Empty<byte>.Array; 24 } 25 26 public ByteBuffer (int length) 27 { 28 this.buffer = new byte [length]; 29 } 30 31 public ByteBuffer (byte [] buffer) 32 { 33 this.buffer = buffer ?? Empty<byte>.Array; 34 this.length = this.buffer.Length; 35 } 36 37 public void Advance (int length) 38 { 39 position += length; 40 } 41 42 public byte ReadByte () 43 { 44 return buffer [position++]; 45 } 46 47 public sbyte ReadSByte () 48 { 49 return (sbyte) ReadByte (); 50 } 51 52 public byte [] ReadBytes (int length) 53 { 54 var bytes = new byte [length]; 55 Buffer.BlockCopy (buffer, position, bytes, 0, length); 56 position += length; 57 return bytes; 58 } 59 60 public ushort ReadUInt16 () 61 { 62 ushort value = (ushort) (buffer [position] 63 | (buffer [position + 1] << 8)); 64 position += 2; 65 return value; 66 } 67 68 public short ReadInt16 () 69 { 70 return (short) ReadUInt16 (); 71 } 72 73 public uint ReadUInt32 () 74 { 75 uint value = (uint) (buffer [position] 76 | (buffer [position + 1] << 8) 77 | (buffer [position + 2] << 16) 78 | (buffer [position + 3] << 24)); 79 position += 4; 80 return value; 81 } 82 83 public int ReadInt32 () 84 { 85 return (int) ReadUInt32 (); 86 } 87 88 public ulong ReadUInt64 () 89 { 90 uint low = ReadUInt32 (); 91 uint high = ReadUInt32 (); 92 93 return (((ulong) high) << 32) | low; 94 } 95 96 public long ReadInt64 () 97 { 98 return (long) ReadUInt64 (); 99 } 100 101 public uint ReadCompressedUInt32 () 102 { 103 byte first = ReadByte (); 104 if ((first & 0x80) == 0) 105 return first; 106 107 if ((first & 0x40) == 0) 108 return ((uint) (first & ~0x80) << 8) 109 | ReadByte (); 110 111 return ((uint) (first & ~0xc0) << 24) 112 | (uint) ReadByte () << 16 113 | (uint) ReadByte () << 8 114 | ReadByte (); 115 } 116 117 public int ReadCompressedInt32 () 118 { 119 var b = buffer [position]; 120 var u = (int) ReadCompressedUInt32 (); 121 var v = u >> 1; 122 if ((u & 1) == 0) 123 return v; 124 125 switch (b & 0xc0) 126 { 127 case 0: 128 case 0x40: 129 return v - 0x40; 130 case 0x80: 131 return v - 0x2000; 132 default: 133 return v - 0x10000000; 134 } 135 } 136 137 public float ReadSingle () 138 { 139 if (!BitConverter.IsLittleEndian) { 140 var bytes = ReadBytes (4); 141 Array.Reverse (bytes); 142 return BitConverter.ToSingle (bytes, 0); 143 } 144 145 float value = BitConverter.ToSingle (buffer, position); 146 position += 4; 147 return value; 148 } 149 150 public double ReadDouble () 151 { 152 if (!BitConverter.IsLittleEndian) { 153 var bytes = ReadBytes (8); 154 Array.Reverse (bytes); 155 return BitConverter.ToDouble (bytes, 0); 156 } 157 158 double value = BitConverter.ToDouble (buffer, position); 159 position += 8; 160 return value; 161 } 162 163 public void WriteByte (byte value) 164 { 165 if (position == buffer.Length) 166 Grow (1); 167 168 buffer [position++] = value; 169 170 if (position > length) 171 length = position; 172 } 173 174 public void WriteSByte (sbyte value) 175 { 176 WriteByte ((byte) value); 177 } 178 179 public void WriteUInt16 (ushort value) 180 { 181 if (position + 2 > buffer.Length) 182 Grow (2); 183 184 buffer [position++] = (byte) value; 185 buffer [position++] = (byte) (value >> 8); 186 187 if (position > length) 188 length = position; 189 } 190 191 public void WriteInt16 (short value) 192 { 193 WriteUInt16 ((ushort) value); 194 } 195 196 public void WriteUInt32 (uint value) 197 { 198 if (position + 4 > buffer.Length) 199 Grow (4); 200 201 buffer [position++] = (byte) value; 202 buffer [position++] = (byte) (value >> 8); 203 buffer [position++] = (byte) (value >> 16); 204 buffer [position++] = (byte) (value >> 24); 205 206 if (position > length) 207 length = position; 208 } 209 210 public void WriteInt32 (int value) 211 { 212 WriteUInt32 ((uint) value); 213 } 214 215 public void WriteUInt64 (ulong value) 216 { 217 if (position + 8 > buffer.Length) 218 Grow (8); 219 220 buffer [position++] = (byte) value; 221 buffer [position++] = (byte) (value >> 8); 222 buffer [position++] = (byte) (value >> 16); 223 buffer [position++] = (byte) (value >> 24); 224 buffer [position++] = (byte) (value >> 32); 225 buffer [position++] = (byte) (value >> 40); 226 buffer [position++] = (byte) (value >> 48); 227 buffer [position++] = (byte) (value >> 56); 228 229 if (position > length) 230 length = position; 231 } 232 233 public void WriteInt64 (long value) 234 { 235 WriteUInt64 ((ulong) value); 236 } 237 238 public void WriteCompressedUInt32 (uint value) 239 { 240 if (value < 0x80) 241 WriteByte ((byte) value); 242 else if (value < 0x4000) { 243 WriteByte ((byte) (0x80 | (value >> 8))); 244 WriteByte ((byte) (value & 0xff)); 245 } else { 246 WriteByte ((byte) ((value >> 24) | 0xc0)); 247 WriteByte ((byte) ((value >> 16) & 0xff)); 248 WriteByte ((byte) ((value >> 8) & 0xff)); 249 WriteByte ((byte) (value & 0xff)); 250 } 251 } 252 253 public void WriteCompressedInt32 (int value) 254 { 255 if (value >= 0) { 256 WriteCompressedUInt32 ((uint) (value << 1)); 257 return; 258 } 259 260 if (value > -0x40) 261 value = 0x40 + value; 262 else if (value >= -0x2000) 263 value = 0x2000 + value; 264 else if (value >= -0x20000000) 265 value = 0x20000000 + value; 266 267 WriteCompressedUInt32 ((uint) ((value << 1) | 1)); 268 } 269 270 public void WriteBytes (byte [] bytes) 271 { 272 var length = bytes.Length; 273 if (position + length > buffer.Length) 274 Grow (length); 275 276 Buffer.BlockCopy (bytes, 0, buffer, position, length); 277 position += length; 278 279 if (position > this.length) 280 this.length = position; 281 } 282 283 public void WriteBytes (int length) 284 { 285 if (position + length > buffer.Length) 286 Grow (length); 287 288 position += length; 289 290 if (position > this.length) 291 this.length = position; 292 } 293 294 public void WriteBytes (ByteBuffer buffer) 295 { 296 if (position + buffer.length > this.buffer.Length) 297 Grow (buffer.length); 298 299 Buffer.BlockCopy (buffer.buffer, 0, this.buffer, position, buffer.length); 300 position += buffer.length; 301 302 if (position > this.length) 303 this.length = position; 304 } 305 306 public void WriteSingle (float value) 307 { 308 var bytes = BitConverter.GetBytes (value); 309 310 if (!BitConverter.IsLittleEndian) 311 Array.Reverse (bytes); 312 313 WriteBytes (bytes); 314 } 315 316 public void WriteDouble (double value) 317 { 318 var bytes = BitConverter.GetBytes (value); 319 320 if (!BitConverter.IsLittleEndian) 321 Array.Reverse (bytes); 322 323 WriteBytes (bytes); 324 } 325 326 void Grow (int desired) 327 { 328 var current = this.buffer; 329 var current_length = current.Length; 330 331 var buffer = new byte [System.Math.Max (current_length + desired, current_length * 2)]; 332 Buffer.BlockCopy (current, 0, buffer, 0, current_length); 333 this.buffer = buffer; 334 } 335 } 336}