Buffers.cs 10 KB

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