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 System.Diagnostics;
28
using IKVM.Reflection.Metadata;
30
namespace IKVM.Reflection.Writer
34
protected bool frozen;
35
protected int unalignedlength;
37
internal void Write(MetadataWriter mw)
39
int pos = mw.Position;
41
Debug.Assert(mw.Position == pos + unalignedlength);
42
int align = Length - unalignedlength;
43
for (int i = 0; i < align; i++)
51
get { return Length > 65535; }
59
throw new InvalidOperationException();
60
return (unalignedlength + 3) & ~3;
64
protected abstract void WriteImpl(MetadataWriter mw);
67
abstract class SimpleHeap : Heap
69
internal void Freeze()
72
throw new InvalidOperationException();
74
unalignedlength = GetLength();
77
protected abstract int GetLength();
80
sealed class TableHeap : Heap
82
internal void Freeze(MetadataWriter mw)
85
throw new InvalidOperationException();
87
unalignedlength = GetLength(mw);
90
protected override void WriteImpl(MetadataWriter mw)
92
Table[] tables = mw.ModuleBuilder.GetTables();
94
mw.Write(0); // Reserved
95
int ver = mw.ModuleBuilder.MDStreamVersion;
96
mw.Write((byte)(ver >> 16)); // MajorVersion
97
mw.Write((byte)ver); // MinorVersion
99
if (mw.ModuleBuilder.Strings.IsBig)
103
if (mw.ModuleBuilder.Guids.IsBig)
107
if (mw.ModuleBuilder.Blobs.IsBig)
111
mw.Write(heapSizes);// HeapSizes
112
// LAMESPEC spec says reserved, but .NET 2.0 Ref.Emit sets it to 0x10
113
mw.Write((byte)0x10); // Reserved
116
foreach (Table table in tables)
118
if (table != null && table.RowCount > 0)
124
mw.Write(valid); // Valid
125
mw.Write(0x0016003301FA00L); // Sorted
127
foreach (Table table in tables)
129
if (table != null && table.RowCount > 0)
131
mw.Write(table.RowCount);
135
foreach (Table table in tables)
137
if (table != null && table.RowCount > 0)
139
int pos = mw.Position;
141
Debug.Assert(mw.Position - pos == table.GetLength(mw));
144
// unexplained extra padding
148
private static int GetLength(MetadataWriter mw)
150
int len = 4 + 4 + 8 + 8;
151
foreach (Table table in mw.ModuleBuilder.GetTables())
153
if (table != null && table.RowCount > 0)
155
len += 4; // row count
156
len += table.GetLength(mw);
159
// note that we pad one extra (unexplained) byte
164
sealed class StringHeap : SimpleHeap
166
private List<string> list = new List<string>();
167
private Dictionary<string, int> strings = new Dictionary<string, int>();
168
private int nextOffset;
170
internal StringHeap()
175
internal int Add(string str)
177
Debug.Assert(!frozen);
179
if (!strings.TryGetValue(str, out offset))
182
nextOffset += System.Text.Encoding.UTF8.GetByteCount(str) + 1;
184
strings.Add(str, offset);
189
internal string Find(int index)
191
foreach (KeyValuePair<string, int> kv in strings)
193
if (kv.Value == index)
201
protected override int GetLength()
206
protected override void WriteImpl(MetadataWriter mw)
208
foreach (string str in list)
210
mw.Write(System.Text.Encoding.UTF8.GetBytes(str));
216
sealed class UserStringHeap : SimpleHeap
218
private List<string> list = new List<string>();
219
private Dictionary<string, int> strings = new Dictionary<string, int>();
220
private int nextOffset;
222
internal UserStringHeap()
227
internal bool IsEmpty
229
get { return nextOffset == 1; }
232
internal int Add(string str)
234
Debug.Assert(!frozen);
236
if (!strings.TryGetValue(str, out offset))
238
int length = str.Length * 2 + 1 + MetadataWriter.GetCompressedUIntLength(str.Length * 2 + 1);
239
if (nextOffset + length > 0xFFFFFF)
241
throw new FileFormatLimitationExceededException("No logical space left to create more user strings.", FileFormatLimitationExceededException.META_E_STRINGSPACE_FULL);
244
nextOffset += length;
246
strings.Add(str, offset);
251
protected override int GetLength()
256
protected override void WriteImpl(MetadataWriter mw)
259
foreach (string str in list)
261
mw.WriteCompressedUInt(str.Length * 2 + 1);
262
byte hasSpecialChars = 0;
263
foreach (char ch in str)
265
mw.Write((ushort)ch);
266
if (hasSpecialChars == 0 && (ch < 0x20 || ch > 0x7E))
269
|| (ch >= 0x01 && ch <= 0x08)
270
|| (ch >= 0x0E && ch <= 0x1F)
278
mw.Write(hasSpecialChars);
283
sealed class GuidHeap : SimpleHeap
285
private List<Guid> list = new List<Guid>();
291
internal int Add(Guid guid)
293
Debug.Assert(!frozen);
298
protected override int GetLength()
300
return list.Count * 16;
303
protected override void WriteImpl(MetadataWriter mw)
305
foreach (Guid guid in list)
307
mw.Write(guid.ToByteArray());
312
sealed class BlobHeap : SimpleHeap
314
private Key[] map = new Key[8179];
315
private readonly ByteBuffer buf = new ByteBuffer(32);
330
internal int Add(ByteBuffer bb)
332
Debug.Assert(!frozen);
333
int bblen = bb.Length;
338
int lenlen = MetadataWriter.GetCompressedUIntLength(bblen);
339
int hash = bb.Hash();
340
int index = (hash & 0x7FFFFFFF) % map.Length;
343
while (keys[index].offset != 0)
345
if (keys[index].hash == hash
346
&& keys[index].len == bblen
347
&& buf.Match(keys[index].offset + lenlen, bb, 0, bblen))
349
return keys[index].offset;
353
if (keys[index].next == null)
355
keys[index].next = new Key[4];
356
keys = keys[index].next;
360
keys = keys[index].next;
362
last = keys.Length - 1;
366
int offset = buf.Position;
367
buf.WriteCompressedUInt(bblen);
369
keys[index].len = bblen;
370
keys[index].hash = hash;
371
keys[index].offset = offset;
375
protected override int GetLength()
380
protected override void WriteImpl(MetadataWriter mw)
385
internal bool IsEmpty
387
get { return buf.Position == 1; }
390
internal IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex)
392
return buf.GetBlob(blobIndex);