~ubuntu-branches/ubuntu/oneiric/cecil/oneiric

« back to all changes in this revision

Viewing changes to Mono.Cecil/Mono.Cecil.Metadata/MetadataWriter.cs

  • Committer: Bazaar Package Importer
  • Author(s): Iain Lane, Iain Lane, Jo Shields
  • Date: 2011-08-07 22:38:20 UTC
  • mfrom: (1.1.7 upstream) (6.1.6 experimental)
  • Revision ID: james.westby@ubuntu.com-20110807223820-nfdm4q0pk2smjm11
Tags: 0.9.5+dfsg-1
[ Iain Lane ]
* [411dc78] Update to use my d.o email address
* [74bedaf] Disable clilibs; this is an unstable library
  apps grow unnecessary depends otherwise
* [5288c1f] Mangle debian version in watch file to take care of repacking.
  Also update watch file to look at new github location for tarballs
* [8f7110f] Relax version restriction on cli-common-dev; anything from 0.8
  will do

[ Jo Shields ]
* [e846eb8] Imported Upstream version 0.9.5+dfsg
* [3017d96] Bump build dependencies, as we're building for Mono 2.10 now.
* [27c2cff] Set to DebSrc 3.0, so we can apply patches via Quilt.
* [d0447b3] Update build to use XBuild, not manual compiler invocation.
* [08d2b92] Patch to avoid building tests (which rely on NUnit 2.4)
* [fa5a033] Update install file to include all new assemblies and locations.
* [43bd1e2] Since upstream no longer ships a pcfile, add our own.
* [942ead4] Don't try to ship a Changelog when none exists.
* [ba8232d] Erase obj/ folders in clean rule.
* [090af34] Exclude modulerefs on Windowsy libraries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// MetadataWriter.cs
3
 
//
4
 
// Author:
5
 
//   Jb Evain (jbevain@gmail.com)
6
 
//
7
 
// (C) 2005 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
 
namespace Mono.Cecil.Metadata {
30
 
 
31
 
        using System;
32
 
        using System.Collections;
33
 
        using System.IO;
34
 
        using System.Text;
35
 
 
36
 
        using Mono.Cecil;
37
 
        using Mono.Cecil.Binary;
38
 
 
39
 
        internal sealed class MetadataWriter : BaseMetadataVisitor {
40
 
 
41
 
                AssemblyDefinition m_assembly;
42
 
                MetadataRoot m_root;
43
 
                TargetRuntime m_runtime;
44
 
                ImageWriter m_imgWriter;
45
 
                MetadataTableWriter m_tableWriter;
46
 
                MemoryBinaryWriter m_binaryWriter;
47
 
 
48
 
                IDictionary m_stringCache;
49
 
                MemoryBinaryWriter m_stringWriter;
50
 
 
51
 
                IDictionary m_guidCache;
52
 
                MemoryBinaryWriter m_guidWriter;
53
 
 
54
 
                IDictionary m_usCache;
55
 
                MemoryBinaryWriter m_usWriter;
56
 
 
57
 
                IDictionary m_blobCache;
58
 
                MemoryBinaryWriter m_blobWriter;
59
 
 
60
 
                MemoryBinaryWriter m_tWriter;
61
 
 
62
 
                MemoryBinaryWriter m_cilWriter;
63
 
 
64
 
                MemoryBinaryWriter m_fieldDataWriter;
65
 
                MemoryBinaryWriter m_resWriter;
66
 
 
67
 
                uint m_mdStart, m_mdSize;
68
 
                uint m_resStart, m_resSize;
69
 
                uint m_snsStart, m_snsSize;
70
 
                uint m_debugHeaderStart;
71
 
                uint m_imporTableStart;
72
 
 
73
 
                uint m_entryPointToken;
74
 
 
75
 
                RVA m_cursor = new RVA (0x2050);
76
 
 
77
 
                public MemoryBinaryWriter CilWriter {
78
 
                        get { return m_cilWriter; }
79
 
                }
80
 
 
81
 
                public uint DebugHeaderPosition {
82
 
                        get { return m_debugHeaderStart; }
83
 
                }
84
 
 
85
 
                public uint ImportTablePosition {
86
 
                        get { return m_imporTableStart; }
87
 
                }
88
 
 
89
 
                public uint EntryPointToken {
90
 
                        get { return m_entryPointToken; }
91
 
                        set { m_entryPointToken = value; }
92
 
                }
93
 
 
94
 
                public MetadataWriter (AssemblyDefinition asm, MetadataRoot root,
95
 
                        AssemblyKind kind, TargetRuntime rt, BinaryWriter writer)
96
 
                {
97
 
                        m_assembly = asm;
98
 
                        m_root = root;
99
 
                        m_runtime = rt;
100
 
                        m_imgWriter = new ImageWriter (this, kind, writer);
101
 
                        m_binaryWriter = m_imgWriter.GetTextWriter ();
102
 
 
103
 
                        m_stringCache = new Hashtable ();
104
 
                        m_stringWriter = new MemoryBinaryWriter (Encoding.UTF8);
105
 
                        m_stringWriter.Write ((byte) 0);
106
 
 
107
 
                        m_guidCache = new Hashtable ();
108
 
                        m_guidWriter = new MemoryBinaryWriter ();
109
 
 
110
 
                        m_usCache = new Hashtable ();
111
 
                        m_usWriter = new MemoryBinaryWriter (Encoding.Unicode);
112
 
                        m_usWriter.Write ((byte) 0);
113
 
 
114
 
                        m_blobCache = new Hashtable ();
115
 
                        m_blobWriter = new MemoryBinaryWriter ();
116
 
                        m_blobWriter.Write ((byte) 0);
117
 
 
118
 
                        m_tWriter = new MemoryBinaryWriter ();
119
 
                        m_tableWriter = new MetadataTableWriter (this, m_tWriter);
120
 
 
121
 
                        m_cilWriter = new MemoryBinaryWriter ();
122
 
 
123
 
                        m_fieldDataWriter = new MemoryBinaryWriter ();
124
 
                        m_resWriter = new MemoryBinaryWriter ();
125
 
                }
126
 
 
127
 
                public MetadataRoot GetMetadataRoot ()
128
 
                {
129
 
                        return m_root;
130
 
                }
131
 
 
132
 
                public ImageWriter GetImageWriter ()
133
 
                {
134
 
                        return m_imgWriter;
135
 
                }
136
 
 
137
 
                public MemoryBinaryWriter GetWriter ()
138
 
                {
139
 
                        return m_binaryWriter;
140
 
                }
141
 
 
142
 
                public MetadataTableWriter GetTableVisitor ()
143
 
                {
144
 
                        return m_tableWriter;
145
 
                }
146
 
 
147
 
                public void AddData (int length)
148
 
                {
149
 
                        m_cursor += new RVA ((uint) length);
150
 
                }
151
 
 
152
 
                public RVA GetDataCursor ()
153
 
                {
154
 
                        return m_cursor;
155
 
                }
156
 
 
157
 
                public uint AddString (string str)
158
 
                {
159
 
                        if (str == null || str.Length == 0)
160
 
                                return 0;
161
 
 
162
 
                        if (m_stringCache.Contains (str))
163
 
                                return (uint) m_stringCache [str];
164
 
 
165
 
                        uint pointer = (uint) m_stringWriter.BaseStream.Position;
166
 
                        m_stringCache [str] = pointer;
167
 
                        m_stringWriter.Write (Encoding.UTF8.GetBytes (str));
168
 
                        m_stringWriter.Write ('\0');
169
 
                        return pointer;
170
 
                }
171
 
 
172
 
                public uint AddBlob (byte [] data)
173
 
                {
174
 
                        if (data == null || data.Length == 0)
175
 
                                return 0;
176
 
 
177
 
                        // using CompactFramework compatible version of
178
 
                        // Convert.ToBase64String
179
 
                        string key = Convert.ToBase64String (data, 0, data.Length);
180
 
                        if (m_blobCache.Contains (key))
181
 
                                return (uint) m_blobCache [key];
182
 
 
183
 
                        uint pointer = (uint) m_blobWriter.BaseStream.Position;
184
 
                        m_blobCache [key] = pointer;
185
 
                        Utilities.WriteCompressedInteger (m_blobWriter, data.Length);
186
 
                        m_blobWriter.Write (data);
187
 
                        return pointer;
188
 
                }
189
 
 
190
 
                public uint AddGuid (Guid g)
191
 
                {
192
 
                        if (m_guidCache.Contains (g))
193
 
                                return (uint) m_guidCache [g];
194
 
 
195
 
                        uint pointer = (uint) m_guidWriter.BaseStream.Position;
196
 
                        m_guidCache [g] = pointer;
197
 
                        m_guidWriter.Write (g.ToByteArray ());
198
 
                        return pointer + 1;
199
 
                }
200
 
 
201
 
                public uint AddUserString (string str)
202
 
                {
203
 
                        if (str == null)
204
 
                                return 0;
205
 
 
206
 
                        if (m_usCache.Contains (str))
207
 
                                return (uint) m_usCache [str];
208
 
 
209
 
                        uint pointer = (uint) m_usWriter.BaseStream.Position;
210
 
                        m_usCache [str] = pointer;
211
 
                        byte [] us = Encoding.Unicode.GetBytes (str);
212
 
                        Utilities.WriteCompressedInteger (m_usWriter, us.Length + 1);
213
 
                        m_usWriter.Write (us);
214
 
                        m_usWriter.Write ((byte) (RequiresSpecialHandling (us) ? 1 : 0));
215
 
                        return pointer;
216
 
                }
217
 
 
218
 
                static bool RequiresSpecialHandling (byte [] chars)
219
 
                {
220
 
                        for (int i = 0; i < chars.Length; i++) {
221
 
                                byte c = chars [i];
222
 
                                if ((i % 2) == 1)
223
 
                                        if (c != 0)
224
 
                                                return true;
225
 
 
226
 
                                if (InRange (0x01, 0x08, c) ||
227
 
                                        InRange (0x0e, 0x1f, c) ||
228
 
                                        c == 0x27 ||
229
 
                                        c == 0x2d ||
230
 
                                        c == 0x7f) {
231
 
 
232
 
                                        return true;
233
 
                                }
234
 
                        }
235
 
 
236
 
                        return false;
237
 
                }
238
 
 
239
 
                static bool InRange (int left, int right, int value)
240
 
                {
241
 
                        return left <= value && value <= right;
242
 
                }
243
 
 
244
 
                void CreateStream (string name)
245
 
                {
246
 
                        MetadataStream stream = new MetadataStream ();
247
 
                        stream.Header.Name = name;
248
 
                        stream.Heap = MetadataHeap.HeapFactory (stream);
249
 
                        m_root.Streams.Add (stream);
250
 
                }
251
 
 
252
 
                void SetHeapSize (MetadataHeap heap, MemoryBinaryWriter data, byte flag)
253
 
                {
254
 
                        if (data.BaseStream.Length > 65536) {
255
 
                                m_root.Streams.TablesHeap.HeapSizes |= flag;
256
 
                                heap.IndexSize = 4;
257
 
                        } else
258
 
                                heap.IndexSize = 2;
259
 
                }
260
 
 
261
 
                public uint AddResource (byte [] data)
262
 
                {
263
 
                        uint offset = (uint) m_resWriter.BaseStream.Position;
264
 
                        m_resWriter.Write (data.Length);
265
 
                        m_resWriter.Write (data);
266
 
                        m_resWriter.QuadAlign ();
267
 
                        return offset;
268
 
                }
269
 
 
270
 
                public void AddFieldInitData (byte [] data)
271
 
                {
272
 
                        m_fieldDataWriter.Write (data);
273
 
                        m_fieldDataWriter.QuadAlign ();
274
 
                }
275
 
 
276
 
                uint GetStrongNameSignatureSize ()
277
 
                {
278
 
                        if (m_assembly.Name.PublicKey != null) {
279
 
                                // in fx 2.0 the key may be from 384 to 16384 bits
280
 
                                // so we must calculate the signature size based on
281
 
                                // the size of the public key (minus the 32 byte header)
282
 
                                int size = m_assembly.Name.PublicKey.Length;
283
 
                                if (size > 32)
284
 
                                        return (uint) (size - 32);
285
 
                                // note: size == 16 for the ECMA "key" which is replaced
286
 
                                // by the runtime with a 1024 bits key (128 bytes)
287
 
                        }
288
 
                        return 128; // default strongname signature size
289
 
                }
290
 
 
291
 
                public override void VisitMetadataRoot (MetadataRoot root)
292
 
                {
293
 
                        WriteMemStream (m_cilWriter);
294
 
                        WriteMemStream (m_fieldDataWriter);
295
 
                        m_resStart = (uint) m_binaryWriter.BaseStream.Position;
296
 
                        WriteMemStream (m_resWriter);
297
 
                        m_resSize = (uint) (m_binaryWriter.BaseStream.Position - m_resStart);
298
 
 
299
 
                        // for now, we only reserve the place for the strong name signature
300
 
                        if ((m_assembly.Name.Flags & AssemblyFlags.PublicKey) > 0) {
301
 
                                m_snsStart = (uint) m_binaryWriter.BaseStream.Position;
302
 
                                m_snsSize = GetStrongNameSignatureSize ();
303
 
                                m_binaryWriter.Write (new byte [m_snsSize]);
304
 
                                m_binaryWriter.QuadAlign ();
305
 
                        }
306
 
 
307
 
                        // save place for debug header
308
 
                        if (m_imgWriter.GetImage ().DebugHeader != null) {
309
 
                                m_debugHeaderStart = (uint) m_binaryWriter.BaseStream.Position;
310
 
                                m_binaryWriter.Write (new byte [m_imgWriter.GetImage ().DebugHeader.GetSize ()]);
311
 
                                m_binaryWriter.QuadAlign ();
312
 
                        }
313
 
 
314
 
                        m_mdStart = (uint) m_binaryWriter.BaseStream.Position;
315
 
 
316
 
                        if (m_stringWriter.BaseStream.Length > 1) {
317
 
                                CreateStream (MetadataStream.Strings);
318
 
                                SetHeapSize (root.Streams.StringsHeap, m_stringWriter, 0x01);
319
 
                                m_stringWriter.QuadAlign ();
320
 
                        }
321
 
 
322
 
                        if (m_guidWriter.BaseStream.Length > 0) {
323
 
                                CreateStream (MetadataStream.GUID);
324
 
                                SetHeapSize (root.Streams.GuidHeap, m_guidWriter, 0x02);
325
 
                        }
326
 
 
327
 
                        if (m_blobWriter.BaseStream.Length > 1) {
328
 
                                CreateStream (MetadataStream.Blob);
329
 
                                SetHeapSize (root.Streams.BlobHeap, m_blobWriter, 0x04);
330
 
                                m_blobWriter.QuadAlign ();
331
 
                        }
332
 
 
333
 
                        if (m_usWriter.BaseStream.Length > 2) {
334
 
                                CreateStream (MetadataStream.UserStrings);
335
 
                                m_usWriter.QuadAlign ();
336
 
                        }
337
 
 
338
 
                        m_root.Header.MajorVersion = 1;
339
 
                        m_root.Header.MinorVersion = 1;
340
 
 
341
 
                        switch (m_runtime) {
342
 
                        case TargetRuntime.NET_1_0 :
343
 
                                m_root.Header.Version = "v1.0.3705";
344
 
                                break;
345
 
                        case TargetRuntime.NET_1_1 :
346
 
                                m_root.Header.Version = "v1.1.4322";
347
 
                                break;
348
 
                        case TargetRuntime.NET_2_0 :
349
 
                                m_root.Header.Version = "v2.0.50727";
350
 
                                break;
351
 
                        }
352
 
 
353
 
                        m_root.Streams.TablesHeap.Tables.Accept (m_tableWriter);
354
 
 
355
 
                        if (m_tWriter.BaseStream.Length == 0)
356
 
                                m_root.Streams.Remove (m_root.Streams.TablesHeap.GetStream ());
357
 
                }
358
 
 
359
 
                public override void VisitMetadataRootHeader (MetadataRoot.MetadataRootHeader header)
360
 
                {
361
 
                        m_binaryWriter.Write (header.Signature);
362
 
                        m_binaryWriter.Write (header.MajorVersion);
363
 
                        m_binaryWriter.Write (header.MinorVersion);
364
 
                        m_binaryWriter.Write (header.Reserved);
365
 
                        m_binaryWriter.Write (header.Version.Length + 3 & (~3));
366
 
                        m_binaryWriter.Write (Encoding.ASCII.GetBytes (header.Version));
367
 
                        m_binaryWriter.QuadAlign ();
368
 
                        m_binaryWriter.Write (header.Flags);
369
 
                        m_binaryWriter.Write ((ushort) m_root.Streams.Count);
370
 
                }
371
 
 
372
 
                public override void VisitMetadataStreamCollection (MetadataStreamCollection streams)
373
 
                {
374
 
                        foreach (MetadataStream stream in streams) {
375
 
                                MetadataStream.MetadataStreamHeader header = stream.Header;
376
 
 
377
 
                                header.Offset = (uint) (m_binaryWriter.BaseStream.Position);
378
 
                                m_binaryWriter.Write (header.Offset);
379
 
                                MemoryBinaryWriter container;
380
 
                                string name = header.Name;
381
 
                                uint size = 0;
382
 
                                switch (header.Name) {
383
 
                                case MetadataStream.Tables :
384
 
                                        container = m_tWriter;
385
 
                                        size += 24; // header
386
 
                                        break;
387
 
                                case MetadataStream.Strings :
388
 
                                        name += "\0\0\0\0";
389
 
                                        container = m_stringWriter;
390
 
                                        break;
391
 
                                case MetadataStream.GUID :
392
 
                                        container = m_guidWriter;
393
 
                                        break;
394
 
                                case MetadataStream.Blob :
395
 
                                        container = m_blobWriter;
396
 
                                        break;
397
 
                                case MetadataStream.UserStrings :
398
 
                                        container = m_usWriter;
399
 
                                        break;
400
 
                                default :
401
 
                                        throw new MetadataFormatException ("Unknown stream kind");
402
 
                                }
403
 
 
404
 
                                size += (uint) (container.BaseStream.Length + 3 & (~3));
405
 
                                m_binaryWriter.Write (size);
406
 
                                m_binaryWriter.Write (Encoding.ASCII.GetBytes (name));
407
 
                                m_binaryWriter.QuadAlign ();
408
 
                        }
409
 
                }
410
 
 
411
 
                void WriteMemStream (MemoryBinaryWriter writer)
412
 
                {
413
 
                        m_binaryWriter.Write (writer);
414
 
                        m_binaryWriter.QuadAlign ();
415
 
                }
416
 
 
417
 
                void PatchStreamHeaderOffset (MetadataHeap heap)
418
 
                {
419
 
                        long pos = m_binaryWriter.BaseStream.Position;
420
 
                        m_binaryWriter.BaseStream.Position = heap.GetStream ().Header.Offset;
421
 
                        m_binaryWriter.Write ((uint) (pos - m_mdStart));
422
 
                        m_binaryWriter.BaseStream.Position = pos;
423
 
                }
424
 
 
425
 
                public override void VisitGuidHeap (GuidHeap heap)
426
 
                {
427
 
                        PatchStreamHeaderOffset (heap);
428
 
                        WriteMemStream (m_guidWriter);
429
 
                }
430
 
 
431
 
                public override void VisitStringsHeap (StringsHeap heap)
432
 
                {
433
 
                        PatchStreamHeaderOffset (heap);
434
 
                        WriteMemStream (m_stringWriter);
435
 
                }
436
 
 
437
 
                public override void VisitTablesHeap (TablesHeap heap)
438
 
                {
439
 
                        PatchStreamHeaderOffset (heap);
440
 
                        m_binaryWriter.Write (heap.Reserved);
441
 
                        switch (m_runtime) {
442
 
                        case TargetRuntime.NET_1_0 :
443
 
                        case TargetRuntime.NET_1_1 :
444
 
                                heap.MajorVersion = 1;
445
 
                                heap.MinorVersion = 0;
446
 
                                break;
447
 
                        case TargetRuntime.NET_2_0 :
448
 
                                heap.MajorVersion = 2;
449
 
                                heap.MinorVersion = 0;
450
 
                                break;
451
 
                        }
452
 
                        m_binaryWriter.Write (heap.MajorVersion);
453
 
                        m_binaryWriter.Write (heap.MinorVersion);
454
 
                        m_binaryWriter.Write (heap.HeapSizes);
455
 
                        m_binaryWriter.Write (heap.Reserved2);
456
 
                        m_binaryWriter.Write (heap.Valid);
457
 
                        m_binaryWriter.Write (heap.Sorted);
458
 
                        WriteMemStream (m_tWriter);
459
 
                }
460
 
 
461
 
                public override void VisitBlobHeap (BlobHeap heap)
462
 
                {
463
 
                        PatchStreamHeaderOffset (heap);
464
 
                        WriteMemStream (m_blobWriter);
465
 
                }
466
 
 
467
 
                public override void VisitUserStringsHeap (UserStringsHeap heap)
468
 
                {
469
 
                        PatchStreamHeaderOffset (heap);
470
 
                        WriteMemStream (m_usWriter);
471
 
                }
472
 
 
473
 
                void PatchHeader ()
474
 
                {
475
 
                        Image img = m_imgWriter.GetImage ();
476
 
 
477
 
                        img.CLIHeader.EntryPointToken = m_entryPointToken;
478
 
 
479
 
                        if (m_mdSize > 0)
480
 
                                img.CLIHeader.Metadata = new DataDirectory (
481
 
                                        img.TextSection.VirtualAddress + m_mdStart, m_imporTableStart - m_mdStart);
482
 
 
483
 
                        if (m_resSize > 0)
484
 
                                img.CLIHeader.Resources = new DataDirectory (
485
 
                                        img.TextSection.VirtualAddress + m_resStart, m_resSize);
486
 
 
487
 
                        if (m_snsStart > 0)
488
 
                                img.CLIHeader.StrongNameSignature = new DataDirectory (
489
 
                                        img.TextSection.VirtualAddress + m_snsStart, m_snsSize);
490
 
 
491
 
                        if (m_debugHeaderStart > 0)
492
 
                                img.PEOptionalHeader.DataDirectories.Debug = new DataDirectory (
493
 
                                        img.TextSection.VirtualAddress + m_debugHeaderStart, 0x1c);
494
 
                }
495
 
 
496
 
                public override void TerminateMetadataRoot (MetadataRoot root)
497
 
                {
498
 
                        m_mdSize = (uint) (m_binaryWriter.BaseStream.Position - m_mdStart);
499
 
                        m_imporTableStart = (uint) m_binaryWriter.BaseStream.Position;
500
 
                        m_binaryWriter.Write (new byte [0x60]); // imports
501
 
                        m_imgWriter.Initialize ();
502
 
                        PatchHeader ();
503
 
                        root.GetImage ().Accept (m_imgWriter);
504
 
                }
505
 
        }
506
 
}