Buffers.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. //
  2. // Author:
  3. // Jb Evain (jbevain@gmail.com)
  4. //
  5. // Copyright (c) 2008 - 2015 Jb Evain
  6. // Copyright (c) 2008 - 2011 Novell, Inc.
  7. //
  8. // Licensed under the MIT/X11 license.
  9. //
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Text;
  13. using ILRuntime.Mono.Cecil.PE;
  14. using RVA = System.UInt32;
  15. namespace ILRuntime.Mono.Cecil.Metadata {
  16. sealed class TableHeapBuffer : HeapBuffer {
  17. readonly ModuleDefinition module;
  18. readonly MetadataBuilder metadata;
  19. readonly internal TableInformation [] table_infos = new TableInformation [Mixin.TableCount];
  20. readonly internal MetadataTable [] tables = new MetadataTable [Mixin.TableCount];
  21. bool large_string;
  22. bool large_blob;
  23. bool large_guid;
  24. readonly int [] coded_index_sizes = new int [Mixin.CodedIndexCount];
  25. readonly Func<Table, int> counter;
  26. internal uint [] string_offsets;
  27. public override bool IsEmpty {
  28. get { return false; }
  29. }
  30. public TableHeapBuffer (ModuleDefinition module, MetadataBuilder metadata)
  31. : base (24)
  32. {
  33. this.module = module;
  34. this.metadata = metadata;
  35. this.counter = GetTableLength;
  36. }
  37. int GetTableLength (Table table)
  38. {
  39. return (int) table_infos [(int) table].Length;
  40. }
  41. public TTable GetTable<TTable> (Table table) where TTable : MetadataTable, new ()
  42. {
  43. var md_table = (TTable) tables [(int) table];
  44. if (md_table != null)
  45. return md_table;
  46. md_table = new TTable ();
  47. tables [(int) table] = md_table;
  48. return md_table;
  49. }
  50. public void WriteBySize (uint value, int size)
  51. {
  52. if (size == 4)
  53. WriteUInt32 (value);
  54. else
  55. WriteUInt16 ((ushort) value);
  56. }
  57. public void WriteBySize (uint value, bool large)
  58. {
  59. if (large)
  60. WriteUInt32 (value);
  61. else
  62. WriteUInt16 ((ushort) value);
  63. }
  64. public void WriteString (uint @string)
  65. {
  66. WriteBySize (string_offsets [@string], large_string);
  67. }
  68. public void WriteBlob (uint blob)
  69. {
  70. WriteBySize (blob, large_blob);
  71. }
  72. public void WriteGuid (uint guid)
  73. {
  74. WriteBySize (guid, large_guid);
  75. }
  76. public void WriteRID (uint rid, Table table)
  77. {
  78. WriteBySize (rid, table_infos [(int) table].IsLarge);
  79. }
  80. int GetCodedIndexSize (CodedIndex coded_index)
  81. {
  82. var index = (int) coded_index;
  83. var size = coded_index_sizes [index];
  84. if (size != 0)
  85. return size;
  86. return coded_index_sizes [index] = coded_index.GetSize (counter);
  87. }
  88. public void WriteCodedRID (uint rid, CodedIndex coded_index)
  89. {
  90. WriteBySize (rid, GetCodedIndexSize (coded_index));
  91. }
  92. public void WriteTableHeap ()
  93. {
  94. WriteUInt32 (0); // Reserved
  95. WriteByte (GetTableHeapVersion ()); // MajorVersion
  96. WriteByte (0); // MinorVersion
  97. WriteByte (GetHeapSizes ()); // HeapSizes
  98. WriteByte (10); // Reserved2
  99. WriteUInt64 (GetValid ()); // Valid
  100. WriteUInt64 (0xc416003301fa00); // Sorted
  101. WriteRowCount ();
  102. WriteTables ();
  103. }
  104. void WriteRowCount ()
  105. {
  106. for (int i = 0; i < tables.Length; i++) {
  107. var table = tables [i];
  108. if (table == null || table.Length == 0)
  109. continue;
  110. WriteUInt32 ((uint) table.Length);
  111. }
  112. }
  113. void WriteTables ()
  114. {
  115. for (int i = 0; i < tables.Length; i++) {
  116. var table = tables [i];
  117. if (table == null || table.Length == 0)
  118. continue;
  119. table.Write (this);
  120. }
  121. }
  122. ulong GetValid ()
  123. {
  124. ulong valid = 0;
  125. for (int i = 0; i < tables.Length; i++) {
  126. var table = tables [i];
  127. if (table == null || table.Length == 0)
  128. continue;
  129. table.Sort ();
  130. valid |= (1UL << i);
  131. }
  132. return valid;
  133. }
  134. public void ComputeTableInformations ()
  135. {
  136. if (metadata.metadata_builder != null)
  137. ComputeTableInformations (metadata.metadata_builder.table_heap);
  138. ComputeTableInformations (metadata.table_heap);
  139. }
  140. void ComputeTableInformations (TableHeapBuffer table_heap)
  141. {
  142. var tables = table_heap.tables;
  143. for (int i = 0; i < tables.Length; i++) {
  144. var table = tables [i];
  145. if (table != null && table.Length > 0)
  146. table_infos [i].Length = (uint) table.Length;
  147. }
  148. }
  149. byte GetHeapSizes ()
  150. {
  151. byte heap_sizes = 0;
  152. if (metadata.string_heap.IsLarge) {
  153. large_string = true;
  154. heap_sizes |= 0x01;
  155. }
  156. if (metadata.guid_heap.IsLarge) {
  157. large_guid = true;
  158. heap_sizes |= 0x02;
  159. }
  160. if (metadata.blob_heap.IsLarge) {
  161. large_blob = true;
  162. heap_sizes |= 0x04;
  163. }
  164. return heap_sizes;
  165. }
  166. byte GetTableHeapVersion ()
  167. {
  168. switch (module.Runtime) {
  169. case TargetRuntime.Net_1_0:
  170. case TargetRuntime.Net_1_1:
  171. return 1;
  172. default:
  173. return 2;
  174. }
  175. }
  176. public void FixupData (RVA data_rva)
  177. {
  178. var table = GetTable<FieldRVATable> (Table.FieldRVA);
  179. if (table.length == 0)
  180. return;
  181. var field_idx_size = GetTable<FieldTable> (Table.Field).IsLarge ? 4 : 2;
  182. var previous = this.position;
  183. base.position = table.position;
  184. for (int i = 0; i < table.length; i++) {
  185. var rva = ReadUInt32 ();
  186. base.position -= 4;
  187. WriteUInt32 (rva + data_rva);
  188. base.position += field_idx_size;
  189. }
  190. base.position = previous;
  191. }
  192. }
  193. sealed class ResourceBuffer : ByteBuffer {
  194. public ResourceBuffer ()
  195. : base (0)
  196. {
  197. }
  198. public uint AddResource (byte [] resource)
  199. {
  200. var offset = (uint) this.position;
  201. WriteInt32 (resource.Length);
  202. WriteBytes (resource);
  203. return offset;
  204. }
  205. }
  206. sealed class DataBuffer : ByteBuffer {
  207. public DataBuffer ()
  208. : base (0)
  209. {
  210. }
  211. public RVA AddData (byte [] data)
  212. {
  213. var rva = (RVA) position;
  214. WriteBytes (data);
  215. return rva;
  216. }
  217. }
  218. abstract class HeapBuffer : ByteBuffer {
  219. public bool IsLarge {
  220. get { return base.length > 65535; }
  221. }
  222. public abstract bool IsEmpty { get; }
  223. protected HeapBuffer (int length)
  224. : base (length)
  225. {
  226. }
  227. }
  228. sealed class GuidHeapBuffer : HeapBuffer {
  229. readonly Dictionary<Guid, uint> guids = new Dictionary<Guid, uint> ();
  230. public override bool IsEmpty {
  231. get { return length == 0; }
  232. }
  233. public GuidHeapBuffer ()
  234. : base (16)
  235. {
  236. }
  237. public uint GetGuidIndex (Guid guid)
  238. {
  239. uint index;
  240. if (guids.TryGetValue (guid, out index))
  241. return index;
  242. index = (uint) guids.Count + 1;
  243. WriteGuid (guid);
  244. guids.Add (guid, index);
  245. return index;
  246. }
  247. void WriteGuid (Guid guid)
  248. {
  249. WriteBytes (guid.ToByteArray ());
  250. }
  251. }
  252. class StringHeapBuffer : HeapBuffer {
  253. protected Dictionary<string, uint> strings = new Dictionary<string, uint> (StringComparer.Ordinal);
  254. public sealed override bool IsEmpty {
  255. get { return length <= 1; }
  256. }
  257. public StringHeapBuffer ()
  258. : base (1)
  259. {
  260. WriteByte (0);
  261. }
  262. public virtual uint GetStringIndex (string @string)
  263. {
  264. uint index;
  265. if (strings.TryGetValue (@string, out index))
  266. return index;
  267. index = (uint) strings.Count + 1;
  268. strings.Add (@string, index);
  269. return index;
  270. }
  271. public uint [] WriteStrings ()
  272. {
  273. var sorted = SortStrings (strings);
  274. strings = null;
  275. // Add 1 for empty string whose index and offset are both 0
  276. var string_offsets = new uint [sorted.Count + 1];
  277. string_offsets [0] = 0;
  278. // Find strings that can be folded
  279. var previous = string.Empty;
  280. foreach (var entry in sorted) {
  281. var @string = entry.Key;
  282. var index = entry.Value;
  283. var position = base.position;
  284. if (previous.EndsWith (@string, StringComparison.Ordinal) && !IsLowSurrogateChar (entry.Key [0])) {
  285. // Map over the tail of prev string. Watch for null-terminator of prev string.
  286. string_offsets [index] = (uint) (position - (Encoding.UTF8.GetByteCount (entry.Key) + 1));
  287. } else {
  288. string_offsets [index] = (uint) position;
  289. WriteString (@string);
  290. }
  291. previous = entry.Key;
  292. }
  293. return string_offsets;
  294. }
  295. static List<KeyValuePair<string, uint>> SortStrings (Dictionary<string, uint> strings)
  296. {
  297. var sorted = new List<KeyValuePair<string, uint>> (strings);
  298. sorted.Sort (new SuffixSort ());
  299. return sorted;
  300. }
  301. static bool IsLowSurrogateChar (int c)
  302. {
  303. return unchecked((uint)(c - 0xDC00)) <= 0xDFFF - 0xDC00;
  304. }
  305. protected virtual void WriteString (string @string)
  306. {
  307. WriteBytes (Encoding.UTF8.GetBytes (@string));
  308. WriteByte (0);
  309. }
  310. // Sorts strings such that a string is followed immediately by all strings
  311. // that are a suffix of it.
  312. private class SuffixSort : IComparer<KeyValuePair<string, uint>> {
  313. public int Compare(KeyValuePair<string, uint> xPair, KeyValuePair<string, uint> yPair)
  314. {
  315. var x = xPair.Key;
  316. var y = yPair.Key;
  317. for (int i = x.Length - 1, j = y.Length - 1; i >= 0 & j >= 0; i--, j--) {
  318. if (x [i] < y [j]) {
  319. return -1;
  320. }
  321. if (x [i] > y [j]) {
  322. return +1;
  323. }
  324. }
  325. return y.Length.CompareTo (x.Length);
  326. }
  327. }
  328. }
  329. sealed class BlobHeapBuffer : HeapBuffer {
  330. readonly Dictionary<ByteBuffer, uint> blobs = new Dictionary<ByteBuffer, uint> (new ByteBufferEqualityComparer ());
  331. public override bool IsEmpty {
  332. get { return length <= 1; }
  333. }
  334. public BlobHeapBuffer ()
  335. : base (1)
  336. {
  337. WriteByte (0);
  338. }
  339. public uint GetBlobIndex (ByteBuffer blob)
  340. {
  341. uint index;
  342. if (blobs.TryGetValue (blob, out index))
  343. return index;
  344. index = (uint) base.position;
  345. WriteBlob (blob);
  346. blobs.Add (blob, index);
  347. return index;
  348. }
  349. void WriteBlob (ByteBuffer blob)
  350. {
  351. WriteCompressedUInt32 ((uint) blob.length);
  352. WriteBytes (blob);
  353. }
  354. }
  355. sealed class UserStringHeapBuffer : StringHeapBuffer {
  356. public override uint GetStringIndex (string @string)
  357. {
  358. uint index;
  359. if (strings.TryGetValue (@string, out index))
  360. return index;
  361. index = (uint) base.position;
  362. WriteString (@string);
  363. strings.Add (@string, index);
  364. return index;
  365. }
  366. protected override void WriteString (string @string)
  367. {
  368. WriteCompressedUInt32 ((uint) @string.Length * 2 + 1);
  369. byte special = 0;
  370. for (int i = 0; i < @string.Length; i++) {
  371. var @char = @string [i];
  372. WriteUInt16 (@char);
  373. if (special == 1)
  374. continue;
  375. if (@char < 0x20 || @char > 0x7e) {
  376. if (@char > 0x7e
  377. || (@char >= 0x01 && @char <= 0x08)
  378. || (@char >= 0x0e && @char <= 0x1f)
  379. || @char == 0x27
  380. || @char == 0x2d) {
  381. special = 1;
  382. }
  383. }
  384. }
  385. WriteByte (special);
  386. }
  387. }
  388. sealed class PdbHeapBuffer : HeapBuffer {
  389. public override bool IsEmpty {
  390. get { return false; }
  391. }
  392. public PdbHeapBuffer ()
  393. : base (0)
  394. {
  395. }
  396. }
  397. }