2 Copyright (C) 2008 Jeroen Frijters
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
25 using System.Collections.Generic;
27 using IKVM.Reflection.Metadata;
29 namespace IKVM.Reflection.Writer
31 sealed class ByteBuffer
33 private byte[] buffer;
35 private int __length; // __length is only valid if > pos, otherwise pos is the current length
37 internal ByteBuffer(int initialCapacity)
39 buffer = new byte[initialCapacity];
42 private ByteBuffer(byte[] wrap, int length)
53 if (value > this.Length || value > buffer.Length)
54 throw new ArgumentOutOfRangeException();
55 __length = Math.Max(__length, pos);
62 get { return Math.Max(pos, __length); }
65 // insert count bytes at the current position (without advancing the current position)
66 internal void Insert(int count)
70 int len = this.Length;
71 int free = buffer.Length - len;
76 Buffer.BlockCopy(buffer, pos, buffer, pos + count, len - pos);
77 __length = Math.Max(__length, pos) + count;
81 throw new ArgumentOutOfRangeException("count");
85 private void Grow(int minGrow)
87 byte[] newbuf = new byte[Math.Max(buffer.Length + minGrow, buffer.Length * 2)];
88 Buffer.BlockCopy(buffer, 0, newbuf, 0, buffer.Length);
92 // NOTE this does not advance the position
93 internal int GetInt32AtCurrentPosition()
96 + (buffer[pos + 1] << 8)
97 + (buffer[pos + 2] << 16)
98 + (buffer[pos + 3] << 24);
101 // NOTE this does not advance the position
102 internal byte GetByteAtCurrentPosition()
107 // return the number of bytes that the compressed int at the current position takes
108 internal int GetCompressedUIntLength()
110 switch (buffer[pos] & 0xC0)
121 internal void Write(byte[] value)
123 if (pos + value.Length > buffer.Length)
125 Buffer.BlockCopy(value, 0, buffer, pos, value.Length);
129 internal void Write(byte value)
131 if (pos == buffer.Length)
133 buffer[pos++] = value;
136 internal void Write(sbyte value)
141 internal void Write(ushort value)
146 internal void Write(short value)
148 if (pos + 2 > buffer.Length)
150 buffer[pos++] = (byte)value;
151 buffer[pos++] = (byte)(value >> 8);
154 internal void Write(uint value)
159 internal void Write(int value)
161 if (pos + 4 > buffer.Length)
163 buffer[pos++] = (byte)value;
164 buffer[pos++] = (byte)(value >> 8);
165 buffer[pos++] = (byte)(value >> 16);
166 buffer[pos++] = (byte)(value >> 24);
169 internal void Write(ulong value)
174 internal void Write(long value)
176 if (pos + 8 > buffer.Length)
178 buffer[pos++] = (byte)value;
179 buffer[pos++] = (byte)(value >> 8);
180 buffer[pos++] = (byte)(value >> 16);
181 buffer[pos++] = (byte)(value >> 24);
182 buffer[pos++] = (byte)(value >> 32);
183 buffer[pos++] = (byte)(value >> 40);
184 buffer[pos++] = (byte)(value >> 48);
185 buffer[pos++] = (byte)(value >> 56);
188 internal void Write(float value)
190 Write(SingleConverter.SingleToInt32Bits(value));
193 internal void Write(double value)
195 Write(BitConverter.DoubleToInt64Bits(value));
198 internal void Write(string str)
206 byte[] buf = Encoding.UTF8.GetBytes(str);
207 WriteCompressedUInt(buf.Length);
212 internal void WriteCompressedUInt(int value)
218 else if (value <= 0x3FFF)
220 Write((byte)(0x80 | (value >> 8)));
225 Write((byte)(0xC0 | (value >> 24)));
226 Write((byte)(value >> 16));
227 Write((byte)(value >> 8));
232 internal void WriteCompressedInt(int value)
236 WriteCompressedUInt(value << 1);
238 else if (value >= -64)
240 value = ((value << 1) & 0x7F) | 1;
243 else if (value >= -8192)
245 value = ((value << 1) & 0x3FFF) | 1;
246 Write((byte)(0x80 | (value >> 8)));
251 value = ((value << 1) & 0x1FFFFFFF) | 1;
252 Write((byte)(0xC0 | (value >> 24)));
253 Write((byte)(value >> 16));
254 Write((byte)(value >> 8));
259 internal void Write(ByteBuffer bb)
261 if (pos + bb.Length > buffer.Length)
263 Buffer.BlockCopy(bb.buffer, 0, buffer, pos, bb.Length);
267 internal void WriteTo(System.IO.Stream stream)
269 stream.Write(buffer, 0, this.Length);
272 internal void Clear()
278 internal void Align(int alignment)
280 if (pos + alignment > buffer.Length)
282 int newpos = (pos + alignment - 1) & ~(alignment - 1);
287 internal void WriteTypeDefOrRefEncoded(int token)
291 case TypeDefTable.Index:
292 WriteCompressedUInt((token & 0xFFFFFF) << 2 | 0);
294 case TypeRefTable.Index:
295 WriteCompressedUInt((token & 0xFFFFFF) << 2 | 1);
297 case TypeSpecTable.Index:
298 WriteCompressedUInt((token & 0xFFFFFF) << 2 | 2);
301 throw new InvalidOperationException();
305 internal void Write(System.IO.Stream stream)
307 const int chunkSize = 8192;
310 if (pos + chunkSize > buffer.Length)
312 int read = stream.Read(buffer, pos, chunkSize);
321 internal byte[] ToArray()
323 int len = this.Length;
324 byte[] buf = new byte[len];
325 Buffer.BlockCopy(buffer, 0, buf, 0, len);
329 internal static ByteBuffer Wrap(byte[] buf)
331 return new ByteBuffer(buf, buf.Length);
334 internal static ByteBuffer Wrap(byte[] buf, int length)
336 return new ByteBuffer(buf, length);
339 internal bool Match(int pos, ByteBuffer bb2, int pos2, int len)
341 for (int i = 0; i < len; i++)
343 if (buffer[pos + i] != bb2.buffer[pos2 + i])
354 int len = this.Length;
355 for (int i = 0; i < len; i++)
363 internal IKVM.Reflection.Reader.ByteReader GetBlob(int offset)
365 return IKVM.Reflection.Reader.ByteReader.FromBlob(buffer, offset);