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