123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- //
- // Author:
- // Jb Evain (jbevain@gmail.com)
- //
- // Copyright (c) 2008 - 2015 Jb Evain
- // Copyright (c) 2008 - 2011 Novell, Inc.
- //
- // Licensed under the MIT/X11 license.
- //
- using System;
- using System.Collections.Generic;
- using System.Text;
- using ILRuntime.Mono.Cecil.PE;
- using RVA = System.UInt32;
- namespace ILRuntime.Mono.Cecil.Metadata {
- sealed class TableHeapBuffer : HeapBuffer {
- readonly ModuleDefinition module;
- readonly MetadataBuilder metadata;
- readonly internal TableInformation [] table_infos = new TableInformation [Mixin.TableCount];
- readonly internal MetadataTable [] tables = new MetadataTable [Mixin.TableCount];
- bool large_string;
- bool large_blob;
- bool large_guid;
- readonly int [] coded_index_sizes = new int [Mixin.CodedIndexCount];
- readonly Func<Table, int> counter;
- internal uint [] string_offsets;
- public override bool IsEmpty {
- get { return false; }
- }
- public TableHeapBuffer (ModuleDefinition module, MetadataBuilder metadata)
- : base (24)
- {
- this.module = module;
- this.metadata = metadata;
- this.counter = GetTableLength;
- }
- int GetTableLength (Table table)
- {
- return (int) table_infos [(int) table].Length;
- }
- public TTable GetTable<TTable> (Table table) where TTable : MetadataTable, new ()
- {
- var md_table = (TTable) tables [(int) table];
- if (md_table != null)
- return md_table;
- md_table = new TTable ();
- tables [(int) table] = md_table;
- return md_table;
- }
- public void WriteBySize (uint value, int size)
- {
- if (size == 4)
- WriteUInt32 (value);
- else
- WriteUInt16 ((ushort) value);
- }
- public void WriteBySize (uint value, bool large)
- {
- if (large)
- WriteUInt32 (value);
- else
- WriteUInt16 ((ushort) value);
- }
- public void WriteString (uint @string)
- {
- WriteBySize (string_offsets [@string], large_string);
- }
- public void WriteBlob (uint blob)
- {
- WriteBySize (blob, large_blob);
- }
- public void WriteGuid (uint guid)
- {
- WriteBySize (guid, large_guid);
- }
- public void WriteRID (uint rid, Table table)
- {
- WriteBySize (rid, table_infos [(int) table].IsLarge);
- }
- int GetCodedIndexSize (CodedIndex coded_index)
- {
- var index = (int) coded_index;
- var size = coded_index_sizes [index];
- if (size != 0)
- return size;
- return coded_index_sizes [index] = coded_index.GetSize (counter);
- }
- public void WriteCodedRID (uint rid, CodedIndex coded_index)
- {
- WriteBySize (rid, GetCodedIndexSize (coded_index));
- }
- public void WriteTableHeap ()
- {
- WriteUInt32 (0); // Reserved
- WriteByte (GetTableHeapVersion ()); // MajorVersion
- WriteByte (0); // MinorVersion
- WriteByte (GetHeapSizes ()); // HeapSizes
- WriteByte (10); // Reserved2
- WriteUInt64 (GetValid ()); // Valid
- WriteUInt64 (0xc416003301fa00); // Sorted
- WriteRowCount ();
- WriteTables ();
- }
- void WriteRowCount ()
- {
- for (int i = 0; i < tables.Length; i++) {
- var table = tables [i];
- if (table == null || table.Length == 0)
- continue;
- WriteUInt32 ((uint) table.Length);
- }
- }
- void WriteTables ()
- {
- for (int i = 0; i < tables.Length; i++) {
- var table = tables [i];
- if (table == null || table.Length == 0)
- continue;
- table.Write (this);
- }
- }
- ulong GetValid ()
- {
- ulong valid = 0;
- for (int i = 0; i < tables.Length; i++) {
- var table = tables [i];
- if (table == null || table.Length == 0)
- continue;
- table.Sort ();
- valid |= (1UL << i);
- }
- return valid;
- }
- public void ComputeTableInformations ()
- {
- if (metadata.metadata_builder != null)
- ComputeTableInformations (metadata.metadata_builder.table_heap);
- ComputeTableInformations (metadata.table_heap);
- }
- void ComputeTableInformations (TableHeapBuffer table_heap)
- {
- var tables = table_heap.tables;
- for (int i = 0; i < tables.Length; i++) {
- var table = tables [i];
- if (table != null && table.Length > 0)
- table_infos [i].Length = (uint) table.Length;
- }
- }
- byte GetHeapSizes ()
- {
- byte heap_sizes = 0;
- if (metadata.string_heap.IsLarge) {
- large_string = true;
- heap_sizes |= 0x01;
- }
- if (metadata.guid_heap.IsLarge) {
- large_guid = true;
- heap_sizes |= 0x02;
- }
- if (metadata.blob_heap.IsLarge) {
- large_blob = true;
- heap_sizes |= 0x04;
- }
- return heap_sizes;
- }
- byte GetTableHeapVersion ()
- {
- switch (module.Runtime) {
- case TargetRuntime.Net_1_0:
- case TargetRuntime.Net_1_1:
- return 1;
- default:
- return 2;
- }
- }
- public void FixupData (RVA data_rva)
- {
- var table = GetTable<FieldRVATable> (Table.FieldRVA);
- if (table.length == 0)
- return;
- var field_idx_size = GetTable<FieldTable> (Table.Field).IsLarge ? 4 : 2;
- var previous = this.position;
- base.position = table.position;
- for (int i = 0; i < table.length; i++) {
- var rva = ReadUInt32 ();
- base.position -= 4;
- WriteUInt32 (rva + data_rva);
- base.position += field_idx_size;
- }
- base.position = previous;
- }
- }
- sealed class ResourceBuffer : ByteBuffer {
- public ResourceBuffer ()
- : base (0)
- {
- }
- public uint AddResource (byte [] resource)
- {
- var offset = (uint) this.position;
- WriteInt32 (resource.Length);
- WriteBytes (resource);
- return offset;
- }
- }
- sealed class DataBuffer : ByteBuffer {
- public DataBuffer ()
- : base (0)
- {
- }
- public RVA AddData (byte [] data)
- {
- var rva = (RVA) position;
- WriteBytes (data);
- return rva;
- }
- }
- abstract class HeapBuffer : ByteBuffer {
- public bool IsLarge {
- get { return base.length > 65535; }
- }
- public abstract bool IsEmpty { get; }
- protected HeapBuffer (int length)
- : base (length)
- {
- }
- }
- sealed class GuidHeapBuffer : HeapBuffer {
- readonly Dictionary<Guid, uint> guids = new Dictionary<Guid, uint> ();
- public override bool IsEmpty {
- get { return length == 0; }
- }
- public GuidHeapBuffer ()
- : base (16)
- {
- }
- public uint GetGuidIndex (Guid guid)
- {
- uint index;
- if (guids.TryGetValue (guid, out index))
- return index;
- index = (uint) guids.Count + 1;
- WriteGuid (guid);
- guids.Add (guid, index);
- return index;
- }
- void WriteGuid (Guid guid)
- {
- WriteBytes (guid.ToByteArray ());
- }
- }
- class StringHeapBuffer : HeapBuffer {
- protected Dictionary<string, uint> strings = new Dictionary<string, uint> (StringComparer.Ordinal);
- public sealed override bool IsEmpty {
- get { return length <= 1; }
- }
- public StringHeapBuffer ()
- : base (1)
- {
- WriteByte (0);
- }
- public virtual uint GetStringIndex (string @string)
- {
- uint index;
- if (strings.TryGetValue (@string, out index))
- return index;
- index = (uint) strings.Count + 1;
- strings.Add (@string, index);
- return index;
- }
- public uint [] WriteStrings ()
- {
- var sorted = SortStrings (strings);
- strings = null;
- // Add 1 for empty string whose index and offset are both 0
- var string_offsets = new uint [sorted.Count + 1];
- string_offsets [0] = 0;
- // Find strings that can be folded
- var previous = string.Empty;
- foreach (var entry in sorted) {
- var @string = entry.Key;
- var index = entry.Value;
- var position = base.position;
- if (previous.EndsWith (@string, StringComparison.Ordinal) && !IsLowSurrogateChar (entry.Key [0])) {
- // Map over the tail of prev string. Watch for null-terminator of prev string.
- string_offsets [index] = (uint) (position - (Encoding.UTF8.GetByteCount (entry.Key) + 1));
- } else {
- string_offsets [index] = (uint) position;
- WriteString (@string);
- }
- previous = entry.Key;
- }
- return string_offsets;
- }
- static List<KeyValuePair<string, uint>> SortStrings (Dictionary<string, uint> strings)
- {
- var sorted = new List<KeyValuePair<string, uint>> (strings);
- sorted.Sort (new SuffixSort ());
- return sorted;
- }
- static bool IsLowSurrogateChar (int c)
- {
- return unchecked((uint)(c - 0xDC00)) <= 0xDFFF - 0xDC00;
- }
- protected virtual void WriteString (string @string)
- {
- WriteBytes (Encoding.UTF8.GetBytes (@string));
- WriteByte (0);
- }
- // Sorts strings such that a string is followed immediately by all strings
- // that are a suffix of it.
- private class SuffixSort : IComparer<KeyValuePair<string, uint>> {
- public int Compare(KeyValuePair<string, uint> xPair, KeyValuePair<string, uint> yPair)
- {
- var x = xPair.Key;
- var y = yPair.Key;
- for (int i = x.Length - 1, j = y.Length - 1; i >= 0 & j >= 0; i--, j--) {
- if (x [i] < y [j]) {
- return -1;
- }
- if (x [i] > y [j]) {
- return +1;
- }
- }
- return y.Length.CompareTo (x.Length);
- }
- }
- }
- sealed class BlobHeapBuffer : HeapBuffer {
- readonly Dictionary<ByteBuffer, uint> blobs = new Dictionary<ByteBuffer, uint> (new ByteBufferEqualityComparer ());
- public override bool IsEmpty {
- get { return length <= 1; }
- }
- public BlobHeapBuffer ()
- : base (1)
- {
- WriteByte (0);
- }
- public uint GetBlobIndex (ByteBuffer blob)
- {
- uint index;
- if (blobs.TryGetValue (blob, out index))
- return index;
- index = (uint) base.position;
- WriteBlob (blob);
- blobs.Add (blob, index);
- return index;
- }
- void WriteBlob (ByteBuffer blob)
- {
- WriteCompressedUInt32 ((uint) blob.length);
- WriteBytes (blob);
- }
- }
- sealed class UserStringHeapBuffer : StringHeapBuffer {
- public override uint GetStringIndex (string @string)
- {
- uint index;
- if (strings.TryGetValue (@string, out index))
- return index;
- index = (uint) base.position;
- WriteString (@string);
- strings.Add (@string, index);
- return index;
- }
- protected override void WriteString (string @string)
- {
- WriteCompressedUInt32 ((uint) @string.Length * 2 + 1);
- byte special = 0;
- for (int i = 0; i < @string.Length; i++) {
- var @char = @string [i];
- WriteUInt16 (@char);
- if (special == 1)
- continue;
- if (@char < 0x20 || @char > 0x7e) {
- if (@char > 0x7e
- || (@char >= 0x01 && @char <= 0x08)
- || (@char >= 0x0e && @char <= 0x1f)
- || @char == 0x27
- || @char == 0x2d) {
- special = 1;
- }
- }
- }
- WriteByte (special);
- }
- }
- sealed class PdbHeapBuffer : HeapBuffer {
- public override bool IsEmpty {
- get { return false; }
- }
- public PdbHeapBuffer ()
- : base (0)
- {
- }
- }
- }
|