BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / IKVM.Reflection / Writer / ByteBuffer.cs
1 /*
2   Copyright (C) 2008 Jeroen Frijters
3
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.
7
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:
11
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.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Text;
27 using IKVM.Reflection.Metadata;
28
29 namespace IKVM.Reflection.Writer
30 {
31         sealed class ByteBuffer
32         {
33                 private byte[] buffer;
34                 private int pos;
35                 private int __length;   // __length is only valid if > pos, otherwise pos is the current length
36
37                 internal ByteBuffer(int initialCapacity)
38                 {
39                         buffer = new byte[initialCapacity];
40                 }
41
42                 private ByteBuffer(byte[] wrap, int length)
43                 {
44                         this.buffer = wrap;
45                         this.pos = length;
46                 }
47
48                 internal int Position
49                 {
50                         get { return pos; }
51                         set
52                         {
53                                 if (value > this.Length || value > buffer.Length)
54                                         throw new ArgumentOutOfRangeException();
55                                 __length = Math.Max(__length, pos);
56                                 pos = value;
57                         }
58                 }
59
60                 internal int Length
61                 {
62                         get { return Math.Max(pos, __length); }
63                 }
64
65                 private void Grow(int minGrow)
66                 {
67                         byte[] newbuf = new byte[Math.Max(buffer.Length + minGrow, buffer.Length * 2)];
68                         Buffer.BlockCopy(buffer, 0, newbuf, 0, buffer.Length);
69                         buffer = newbuf;
70                 }
71
72                 // NOTE this does not advance the position
73                 internal int GetInt32AtCurrentPosition()
74                 {
75                         return buffer[pos]
76                                 + (buffer[pos + 1] << 8)
77                                 + (buffer[pos + 2] << 16)
78                                 + (buffer[pos + 3] << 24);
79                 }
80
81                 // NOTE this does not advance the position
82                 internal byte GetByteAtCurrentPosition()
83                 {
84                         return buffer[pos];
85                 }
86
87                 internal void Write(byte[] value)
88                 {
89                         if (pos + value.Length > buffer.Length)
90                                 Grow(value.Length);
91                         Buffer.BlockCopy(value, 0, buffer, pos, value.Length);
92                         pos += value.Length;
93                 }
94
95                 internal void Write(byte value)
96                 {
97                         if (pos == buffer.Length)
98                                 Grow(1);
99                         buffer[pos++] = value;
100                 }
101
102                 internal void Write(sbyte value)
103                 {
104                         Write((byte)value);
105                 }
106
107                 internal void Write(ushort value)
108                 {
109                         Write((short)value);
110                 }
111
112                 internal void Write(short value)
113                 {
114                         if (pos + 2 > buffer.Length)
115                                 Grow(2);
116                         buffer[pos++] = (byte)value;
117                         buffer[pos++] = (byte)(value >> 8);
118                 }
119
120                 internal void Write(uint value)
121                 {
122                         Write((int)value);
123                 }
124         
125                 internal void Write(int value)
126                 {
127                         if (pos + 4 > buffer.Length)
128                                 Grow(4);
129                         buffer[pos++] = (byte)value;
130                         buffer[pos++] = (byte)(value >> 8);
131                         buffer[pos++] = (byte)(value >> 16);
132                         buffer[pos++] = (byte)(value >> 24);
133                 }
134
135                 internal void Write(ulong value)
136                 {
137                         Write((long)value);
138                 }
139
140                 internal void Write(long value)
141                 {
142                         if (pos + 8 > buffer.Length)
143                                 Grow(8);
144                         buffer[pos++] = (byte)value;
145                         buffer[pos++] = (byte)(value >> 8);
146                         buffer[pos++] = (byte)(value >> 16);
147                         buffer[pos++] = (byte)(value >> 24);
148                         buffer[pos++] = (byte)(value >> 32);
149                         buffer[pos++] = (byte)(value >> 40);
150                         buffer[pos++] = (byte)(value >> 48);
151                         buffer[pos++] = (byte)(value >> 56);
152                 }
153
154                 internal void Write(float value)
155                 {
156                         Write(SingleConverter.SingleToInt32Bits(value));
157                 }
158
159                 internal void Write(double value)
160                 {
161                         Write(BitConverter.DoubleToInt64Bits(value));
162                 }
163
164                 internal void Write(string str)
165                 {
166                         if (str == null)
167                         {
168                                 Write((byte)0xFF);
169                         }
170                         else
171                         {
172                                 byte[] buf = Encoding.UTF8.GetBytes(str);
173                                 WriteCompressedInt(buf.Length);
174                                 Write(buf);
175                         }
176                 }
177
178                 internal void WriteCompressedInt(int value)
179                 {
180                         if (value <= 0x7F)
181                         {
182                                 Write((byte)value);
183                         }
184                         else if (value <= 0x3FFF)
185                         {
186                                 Write((byte)(0x80 | (value >> 8)));
187                                 Write((byte)value);
188                         }
189                         else
190                         {
191                                 Write((byte)(0xC0 | (value >> 24)));
192                                 Write((byte)(value >> 16));
193                                 Write((byte)(value >> 8));
194                                 Write((byte)value);
195                         }
196                 }
197
198                 internal void Write(ByteBuffer bb)
199                 {
200                         if (pos + bb.Length > buffer.Length)
201                                 Grow(bb.Length);
202                         Buffer.BlockCopy(bb.buffer, 0, buffer, pos, bb.Length);
203                         pos += bb.Length;
204                 }
205
206                 internal void WriteTo(System.IO.Stream stream)
207                 {
208                         stream.Write(buffer, 0, this.Length);
209                 }
210
211                 internal void Clear()
212                 {
213                         pos = 0;
214                         __length = 0;
215                 }
216
217                 internal void Align(int alignment)
218                 {
219                         if (pos + alignment > buffer.Length)
220                                 Grow(alignment);
221                         int newpos = (pos + alignment - 1) & ~(alignment - 1);
222                         while (pos < newpos)
223                                 buffer[pos++] = 0;
224                 }
225
226                 internal void WriteTypeDefOrRefEncoded(int token)
227                 {
228                         switch (token >> 24)
229                         {
230                                 case TypeDefTable.Index:
231                                         WriteCompressedInt((token & 0xFFFFFF) << 2 | 0);
232                                         break;
233                                 case TypeRefTable.Index:
234                                         WriteCompressedInt((token & 0xFFFFFF) << 2 | 1);
235                                         break;
236                                 case TypeSpecTable.Index:
237                                         WriteCompressedInt((token & 0xFFFFFF) << 2 | 2);
238                                         break;
239                                 default:
240                                         throw new InvalidOperationException();
241                         }
242                 }
243
244                 internal void Write(System.IO.Stream stream)
245                 {
246                         const int chunkSize = 8192;
247                         for (; ; )
248                         {
249                                 if (pos + chunkSize > buffer.Length)
250                                         Grow(chunkSize);
251                                 int read = stream.Read(buffer, pos, chunkSize);
252                                 if (read <= 0)
253                                 {
254                                         break;
255                                 }
256                                 pos += read;
257                         }
258                 }
259
260                 internal byte[] ToArray()
261                 {
262                         byte[] buf = new byte[pos];
263                         Buffer.BlockCopy(buffer, 0, buf, 0, pos);
264                         return buf;
265                 }
266
267                 internal static ByteBuffer Wrap(byte[] buf)
268                 {
269                         return new ByteBuffer(buf, buf.Length);
270                 }
271
272                 internal static ByteBuffer Wrap(byte[] buf, int length)
273                 {
274                         return new ByteBuffer(buf, length);
275                 }
276
277                 internal bool Match(int pos, ByteBuffer bb2, int pos2, int len)
278                 {
279                         for (int i = 0; i < len; i++)
280                         {
281                                 if (buffer[pos + i] != bb2.buffer[pos2 + i])
282                                 {
283                                         return false;
284                                 }
285                         }
286                         return true;
287                 }
288
289                 internal int Hash()
290                 {
291                         int hash = 0;
292                         int len = this.Length;
293                         for (int i = 0; i < len; i++)
294                         {
295                                 hash *= 37;
296                                 hash ^= buffer[i];
297                         }
298                         return hash;
299                 }
300
301                 internal IKVM.Reflection.Reader.ByteReader GetBlob(int offset)
302                 {
303                         return IKVM.Reflection.Reader.ByteReader.FromBlob(buffer, offset);
304                 }
305         }
306 }