diff --git a/Mono.Cecil.20/Mono.Cecil.20.csproj b/Mono.Cecil.20/Mono.Cecil.20.csproj
index fa034e72..043c58a1 100644
--- a/Mono.Cecil.20/Mono.Cecil.20.csproj
+++ b/Mono.Cecil.20/Mono.Cecil.20.csproj
@@ -1,177 +1,20 @@
-
-
+
- Debug
- AnyCPU
- {D3785D8B-4D85-4546-8763-47FC848C13E0}
- Library
- Properties
+ {D68133BD-1E63-496E-9EDE-4FBDBF77B486}
Mono.Cecil
- Mono.Cecil.20
- v2.0
- 512
-
-
+ Mono.Cecil
-
- true
- full
- false
- ..\bin\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
\ No newline at end of file
+
+
+
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/Code.cs b/Mono.Cecil.20/Mono.Cecil.Cil/Code.cs
similarity index 69%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/Code.cs
rename to Mono.Cecil.20/Mono.Cecil.Cil/Code.cs
index fa88b63d..cd929fcc 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/Code.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/Code.cs
@@ -1,29 +1,11 @@
//
-// Code.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
namespace Mono.Cecil.Cil {
diff --git a/Mono.Cecil.20/Mono.Cecil.Cil/CodeReader.cs b/Mono.Cecil.20/Mono.Cecil.Cil/CodeReader.cs
new file mode 100644
index 00000000..73cf923c
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/CodeReader.cs
@@ -0,0 +1,645 @@
+//
+// 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 Mono.Cecil.PE;
+using Mono.Collections.Generic;
+
+using RVA = System.UInt32;
+
+namespace Mono.Cecil.Cil {
+
+ sealed class CodeReader : BinaryStreamReader {
+
+ readonly internal MetadataReader reader;
+
+ int start;
+
+ MethodDefinition method;
+ MethodBody body;
+
+ int Offset {
+ get { return Position - start; }
+ }
+
+ public CodeReader (MetadataReader reader)
+ : base (reader.image.Stream.value)
+ {
+ this.reader = reader;
+ }
+
+ public int MoveTo (MethodDefinition method)
+ {
+ this.method = method;
+ this.reader.context = method;
+ var position = this.Position;
+ this.Position = (int) reader.image.ResolveVirtualAddress ((uint) method.RVA);
+ return position;
+ }
+
+ void MoveBackTo (int position)
+ {
+ this.reader.context = null;
+ this.Position = position;
+ }
+
+ public MethodBody ReadMethodBody (MethodDefinition method)
+ {
+ var position = MoveTo (method);
+ this.body = new MethodBody (method);
+
+ ReadMethodBody ();
+
+ MoveBackTo (position);
+ return this.body;
+ }
+
+ void ReadMethodBody ()
+ {
+ var flags = ReadByte ();
+ switch (flags & 0x3) {
+ case 0x2: // tiny
+ body.code_size = flags >> 2;
+ body.MaxStackSize = 8;
+ ReadCode ();
+ break;
+ case 0x3: // fat
+ Advance (-1);
+ ReadFatMethod ();
+ break;
+ default:
+ throw new InvalidOperationException ();
+ }
+
+ var symbol_reader = reader.module.symbol_reader;
+
+ //if (symbol_reader != null && method.debug_info == null)
+ if (symbol_reader != null)
+ method.debug_info = symbol_reader.Read (method);
+ else
+ method.debug_info = null;
+
+ if (method.debug_info != null)
+ ReadDebugInfo ();
+ }
+
+ void ReadDebugInfo ()
+ {
+ if (method.debug_info.sequence_points != null)
+ ReadSequencePoints ();
+
+ if (method.debug_info.scope != null)
+ ReadScope (method.debug_info.scope);
+
+ if (method.custom_infos != null)
+ ReadCustomDebugInformations (method);
+ }
+
+ void ReadCustomDebugInformations (MethodDefinition method)
+ {
+ var custom_infos = method.custom_infos;
+
+ for (int i = 0; i < custom_infos.Count; i++) {
+ var state_machine_scope = custom_infos [i] as StateMachineScopeDebugInformation;
+ if (state_machine_scope != null)
+ ReadStateMachineScope (state_machine_scope);
+
+ var async_method = custom_infos [i] as AsyncMethodBodyDebugInformation;
+ if (async_method != null)
+ ReadAsyncMethodBody (async_method);
+ }
+ }
+
+ void ReadAsyncMethodBody (AsyncMethodBodyDebugInformation async_method)
+ {
+ if (async_method.catch_handler.Offset > -1)
+ async_method.catch_handler = new InstructionOffset (GetInstruction (async_method.catch_handler.Offset));
+
+ if (!async_method.yields.IsNullOrEmpty ())
+ for (int i = 0; i < async_method.yields.Count; i++)
+ async_method.yields [i] = new InstructionOffset (GetInstruction (async_method.yields [i].Offset));
+
+ if (!async_method.resumes.IsNullOrEmpty ())
+ for (int i = 0; i < async_method.resumes.Count; i++)
+ async_method.resumes [i] = new InstructionOffset (GetInstruction (async_method.resumes [i].Offset));
+ }
+
+ void ReadStateMachineScope (StateMachineScopeDebugInformation state_machine_scope)
+ {
+ state_machine_scope.start = new InstructionOffset (GetInstruction (state_machine_scope.start.Offset));
+
+ var end_instruction = GetInstruction (state_machine_scope.end.Offset);
+ state_machine_scope.end = end_instruction == null
+ ? new InstructionOffset ()
+ : new InstructionOffset (end_instruction);
+ }
+
+ void ReadSequencePoints ()
+ {
+ var symbol = method.debug_info;
+
+ for (int i = 0; i < symbol.sequence_points.Count; i++) {
+ var sequence_point = symbol.sequence_points [i];
+ var instruction = GetInstruction (sequence_point.Offset);
+ if (instruction != null)
+ sequence_point.offset = new InstructionOffset (instruction);
+ }
+ }
+
+ void ReadScopes (Collection scopes)
+ {
+ for (int i = 0; i < scopes.Count; i++)
+ ReadScope (scopes [i]);
+ }
+
+ void ReadScope (ScopeDebugInformation scope)
+ {
+ var start_instruction = GetInstruction (scope.Start.Offset);
+ if (start_instruction != null)
+ scope.Start = new InstructionOffset (start_instruction);
+
+ var end_instruction = GetInstruction (scope.End.Offset);
+ scope.End = end_instruction != null
+ ? new InstructionOffset (end_instruction)
+ : new InstructionOffset ();
+
+ if (!scope.variables.IsNullOrEmpty ()) {
+ for (int i = 0; i < scope.variables.Count; i++) {
+ var variable_info = scope.variables [i];
+ var variable = GetVariable (variable_info.Index);
+ if (variable != null)
+ variable_info.index = new VariableIndex (variable);
+ }
+ }
+
+ if (!scope.scopes.IsNullOrEmpty ())
+ ReadScopes (scope.scopes);
+ }
+
+ void ReadFatMethod ()
+ {
+ var flags = ReadUInt16 ();
+ body.max_stack_size = ReadUInt16 ();
+ body.code_size = (int) ReadUInt32 ();
+ body.local_var_token = new MetadataToken (ReadUInt32 ());
+ body.init_locals = (flags & 0x10) != 0;
+
+ if (body.local_var_token.RID != 0)
+ body.variables = ReadVariables (body.local_var_token);
+
+ ReadCode ();
+
+ if ((flags & 0x8) != 0)
+ ReadSection ();
+ }
+
+ public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token)
+ {
+ var position = reader.position;
+ var variables = reader.ReadVariables (local_var_token);
+ reader.position = position;
+
+ return variables;
+ }
+
+ void ReadCode ()
+ {
+ start = Position;
+ var code_size = body.code_size;
+
+ if (code_size < 0 || Length <= (uint) (code_size + Position))
+ code_size = 0;
+
+ var end = start + code_size;
+ var instructions = body.instructions = new InstructionCollection (method, (code_size + 1) / 2);
+
+ while (Position < end) {
+ var offset = Position - start;
+ var opcode = ReadOpCode ();
+ var current = new Instruction (method, offset, opcode);
+
+ if (opcode.OperandType != OperandType.InlineNone)
+ current.operand = ReadOperand (current);
+
+ instructions.Add (current);
+ }
+
+ ResolveBranches (instructions);
+ }
+
+ OpCode ReadOpCode ()
+ {
+ var il_opcode = ReadByte ();
+ return il_opcode != 0xfe
+ ? OpCodes.OneByteOpCode [il_opcode]
+ : OpCodes.TwoBytesOpCode [ReadByte ()];
+ }
+
+ object ReadOperand (Instruction instruction)
+ {
+ switch (instruction.opcode.OperandType) {
+ case OperandType.InlineSwitch:
+ var length = ReadInt32 ();
+ var base_offset = Offset + (4 * length);
+ var branches = new int [length];
+ for (int i = 0; i < length; i++)
+ branches [i] = base_offset + ReadInt32 ();
+ return branches;
+ case OperandType.ShortInlineBrTarget:
+ return ReadSByte () + Offset;
+ case OperandType.InlineBrTarget:
+ return ReadInt32 () + Offset;
+ case OperandType.ShortInlineI:
+ if (instruction.opcode == OpCodes.Ldc_I4_S)
+ return ReadSByte ();
+
+ return ReadByte ();
+ case OperandType.InlineI:
+ return ReadInt32 ();
+ case OperandType.ShortInlineR:
+ return ReadSingle ();
+ case OperandType.InlineR:
+ return ReadDouble ();
+ case OperandType.InlineI8:
+ return ReadInt64 ();
+ case OperandType.ShortInlineVar:
+ return GetVariable (ReadByte ());
+ case OperandType.InlineVar:
+ return GetVariable (ReadUInt16 ());
+ case OperandType.ShortInlineArg:
+ return GetParameter (ReadByte ());
+ case OperandType.InlineArg:
+ return GetParameter (ReadUInt16 ());
+ case OperandType.InlineSig:
+ return GetCallSite (ReadToken ());
+ case OperandType.InlineString:
+ return GetString (ReadToken ());
+ case OperandType.InlineTok:
+ case OperandType.InlineType:
+ case OperandType.InlineMethod:
+ case OperandType.InlineField:
+ return reader.LookupToken (ReadToken ());
+ default:
+ throw new NotSupportedException ();
+ }
+ }
+
+ public string GetString (MetadataToken token)
+ {
+ return reader.image.UserStringHeap.Read (token.RID);
+ }
+
+ public ParameterDefinition GetParameter (int index)
+ {
+ return body.GetParameter (index);
+ }
+
+ public VariableDefinition GetVariable (int index)
+ {
+ return body.GetVariable (index);
+ }
+
+ public CallSite GetCallSite (MetadataToken token)
+ {
+ return reader.ReadCallSite (token);
+ }
+
+ void ResolveBranches (Collection instructions)
+ {
+ var items = instructions.items;
+ var size = instructions.size;
+
+ for (int i = 0; i < size; i++) {
+ var instruction = items [i];
+ switch (instruction.opcode.OperandType) {
+ case OperandType.ShortInlineBrTarget:
+ case OperandType.InlineBrTarget:
+ instruction.operand = GetInstruction ((int) instruction.operand);
+ break;
+ case OperandType.InlineSwitch:
+ var offsets = (int []) instruction.operand;
+ var branches = new Instruction [offsets.Length];
+ for (int j = 0; j < offsets.Length; j++)
+ branches [j] = GetInstruction (offsets [j]);
+
+ instruction.operand = branches;
+ break;
+ }
+ }
+ }
+
+ Instruction GetInstruction (int offset)
+ {
+ return GetInstruction (body.Instructions, offset);
+ }
+
+ static Instruction GetInstruction (Collection instructions, int offset)
+ {
+ var size = instructions.size;
+ var items = instructions.items;
+ if (offset < 0 || offset > items [size - 1].offset)
+ return null;
+
+ int min = 0;
+ int max = size - 1;
+ while (min <= max) {
+ int mid = min + ((max - min) / 2);
+ var instruction = items [mid];
+ var instruction_offset = instruction.offset;
+
+ if (offset == instruction_offset)
+ return instruction;
+
+ if (offset < instruction_offset)
+ max = mid - 1;
+ else
+ min = mid + 1;
+ }
+
+ return null;
+ }
+
+ void ReadSection ()
+ {
+ Align (4);
+
+ const byte fat_format = 0x40;
+ const byte more_sects = 0x80;
+
+ var flags = ReadByte ();
+ if ((flags & fat_format) == 0)
+ ReadSmallSection ();
+ else
+ ReadFatSection ();
+
+ if ((flags & more_sects) != 0)
+ ReadSection ();
+ }
+
+ void ReadSmallSection ()
+ {
+ var count = ReadByte () / 12;
+ Advance (2);
+
+ ReadExceptionHandlers (
+ count,
+ () => (int) ReadUInt16 (),
+ () => (int) ReadByte ());
+ }
+
+ void ReadFatSection ()
+ {
+ Advance (-1);
+ var count = (ReadInt32 () >> 8) / 24;
+
+ ReadExceptionHandlers (
+ count,
+ ReadInt32,
+ ReadInt32);
+ }
+
+ // inline ?
+ void ReadExceptionHandlers (int count, Func read_entry, Func read_length)
+ {
+ for (int i = 0; i < count; i++) {
+ var handler = new ExceptionHandler (
+ (ExceptionHandlerType) (read_entry () & 0x7));
+
+ handler.TryStart = GetInstruction (read_entry ());
+ handler.TryEnd = GetInstruction (handler.TryStart.Offset + read_length ());
+
+ handler.HandlerStart = GetInstruction (read_entry ());
+ handler.HandlerEnd = GetInstruction (handler.HandlerStart.Offset + read_length ());
+
+ ReadExceptionHandlerSpecific (handler);
+
+ this.body.ExceptionHandlers.Add (handler);
+ }
+ }
+
+ void ReadExceptionHandlerSpecific (ExceptionHandler handler)
+ {
+ switch (handler.HandlerType) {
+ case ExceptionHandlerType.Catch:
+ handler.CatchType = (TypeReference) reader.LookupToken (ReadToken ());
+ break;
+ case ExceptionHandlerType.Filter:
+ handler.FilterStart = GetInstruction (ReadInt32 ());
+ break;
+ default:
+ Advance (4);
+ break;
+ }
+ }
+
+ public MetadataToken ReadToken ()
+ {
+ return new MetadataToken (ReadUInt32 ());
+ }
+
+#if !READ_ONLY
+
+ public ByteBuffer PatchRawMethodBody (MethodDefinition method, CodeWriter writer, out int code_size, out MetadataToken local_var_token)
+ {
+ var position = MoveTo (method);
+
+ var buffer = new ByteBuffer ();
+
+ var flags = ReadByte ();
+
+ switch (flags & 0x3) {
+ case 0x2: // tiny
+ buffer.WriteByte (flags);
+ local_var_token = MetadataToken.Zero;
+ code_size = flags >> 2;
+ PatchRawCode (buffer, code_size, writer);
+ break;
+ case 0x3: // fat
+ Advance (-1);
+ PatchRawFatMethod (buffer, writer, out code_size, out local_var_token);
+ break;
+ default:
+ throw new NotSupportedException ();
+ }
+
+ MoveBackTo (position);
+
+ return buffer;
+ }
+
+ void PatchRawFatMethod (ByteBuffer buffer, CodeWriter writer, out int code_size, out MetadataToken local_var_token)
+ {
+ var flags = ReadUInt16 ();
+ buffer.WriteUInt16 (flags);
+ buffer.WriteUInt16 (ReadUInt16 ());
+ code_size = ReadInt32 ();
+ buffer.WriteInt32 (code_size);
+ local_var_token = ReadToken ();
+
+ if (local_var_token.RID > 0) {
+ var variables = ReadVariables (local_var_token);
+ buffer.WriteUInt32 (variables != null
+ ? writer.GetStandAloneSignature (variables).ToUInt32 ()
+ : 0);
+ } else
+ buffer.WriteUInt32 (0);
+
+ PatchRawCode (buffer, code_size, writer);
+
+ if ((flags & 0x8) != 0)
+ PatchRawSection (buffer, writer.metadata);
+ }
+
+ void PatchRawCode (ByteBuffer buffer, int code_size, CodeWriter writer)
+ {
+ var metadata = writer.metadata;
+ buffer.WriteBytes (ReadBytes (code_size));
+ var end = buffer.position;
+ buffer.position -= code_size;
+
+ while (buffer.position < end) {
+ OpCode opcode;
+ var il_opcode = buffer.ReadByte ();
+ if (il_opcode != 0xfe) {
+ opcode = OpCodes.OneByteOpCode [il_opcode];
+ } else {
+ var il_opcode2 = buffer.ReadByte ();
+ opcode = OpCodes.TwoBytesOpCode [il_opcode2];
+ }
+
+ switch (opcode.OperandType) {
+ case OperandType.ShortInlineI:
+ case OperandType.ShortInlineBrTarget:
+ case OperandType.ShortInlineVar:
+ case OperandType.ShortInlineArg:
+ buffer.position += 1;
+ break;
+ case OperandType.InlineVar:
+ case OperandType.InlineArg:
+ buffer.position += 2;
+ break;
+ case OperandType.InlineBrTarget:
+ case OperandType.ShortInlineR:
+ case OperandType.InlineI:
+ buffer.position += 4;
+ break;
+ case OperandType.InlineI8:
+ case OperandType.InlineR:
+ buffer.position += 8;
+ break;
+ case OperandType.InlineSwitch:
+ var length = buffer.ReadInt32 ();
+ buffer.position += length * 4;
+ break;
+ case OperandType.InlineString:
+ var @string = GetString (new MetadataToken (buffer.ReadUInt32 ()));
+ buffer.position -= 4;
+ buffer.WriteUInt32 (
+ new MetadataToken (
+ TokenType.String,
+ metadata.user_string_heap.GetStringIndex (@string)).ToUInt32 ());
+ break;
+ case OperandType.InlineSig:
+ var call_site = GetCallSite (new MetadataToken (buffer.ReadUInt32 ()));
+ buffer.position -= 4;
+ buffer.WriteUInt32 (writer.GetStandAloneSignature (call_site).ToUInt32 ());
+ break;
+ case OperandType.InlineTok:
+ case OperandType.InlineType:
+ case OperandType.InlineMethod:
+ case OperandType.InlineField:
+ var provider = reader.LookupToken (new MetadataToken (buffer.ReadUInt32 ()));
+ buffer.position -= 4;
+ buffer.WriteUInt32 (metadata.LookupToken (provider).ToUInt32 ());
+ break;
+ }
+ }
+ }
+
+ void PatchRawSection (ByteBuffer buffer, MetadataBuilder metadata)
+ {
+ var position = Position;
+ Align (4);
+ buffer.WriteBytes (Position - position);
+
+ const byte fat_format = 0x40;
+ const byte more_sects = 0x80;
+
+ var flags = ReadByte ();
+ if ((flags & fat_format) == 0) {
+ buffer.WriteByte (flags);
+ PatchRawSmallSection (buffer, metadata);
+ } else
+ PatchRawFatSection (buffer, metadata);
+
+ if ((flags & more_sects) != 0)
+ PatchRawSection (buffer, metadata);
+ }
+
+ void PatchRawSmallSection (ByteBuffer buffer, MetadataBuilder metadata)
+ {
+ var length = ReadByte ();
+ buffer.WriteByte (length);
+ Advance (2);
+
+ buffer.WriteUInt16 (0);
+
+ var count = length / 12;
+
+ PatchRawExceptionHandlers (buffer, metadata, count, false);
+ }
+
+ void PatchRawFatSection (ByteBuffer buffer, MetadataBuilder metadata)
+ {
+ Advance (-1);
+ var length = ReadInt32 ();
+ buffer.WriteInt32 (length);
+
+ var count = (length >> 8) / 24;
+
+ PatchRawExceptionHandlers (buffer, metadata, count, true);
+ }
+
+ void PatchRawExceptionHandlers (ByteBuffer buffer, MetadataBuilder metadata, int count, bool fat_entry)
+ {
+ const int fat_entry_size = 16;
+ const int small_entry_size = 6;
+
+ for (int i = 0; i < count; i++) {
+ ExceptionHandlerType handler_type;
+ if (fat_entry) {
+ var type = ReadUInt32 ();
+ handler_type = (ExceptionHandlerType) (type & 0x7);
+ buffer.WriteUInt32 (type);
+ } else {
+ var type = ReadUInt16 ();
+ handler_type = (ExceptionHandlerType) (type & 0x7);
+ buffer.WriteUInt16 (type);
+ }
+
+ buffer.WriteBytes (ReadBytes (fat_entry ? fat_entry_size : small_entry_size));
+
+ switch (handler_type) {
+ case ExceptionHandlerType.Catch:
+ var exception = reader.LookupToken (ReadToken ());
+ buffer.WriteUInt32 (metadata.LookupToken (exception).ToUInt32 ());
+ break;
+ default:
+ buffer.WriteUInt32 (ReadUInt32 ());
+ break;
+ }
+ }
+ }
+
+#endif
+
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Cil/CodeWriter.cs b/Mono.Cecil.20/Mono.Cecil.Cil/CodeWriter.cs
new file mode 100644
index 00000000..2003f104
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/CodeWriter.cs
@@ -0,0 +1,659 @@
+//
+// 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 Mono.Collections.Generic;
+
+using Mono.Cecil.Metadata;
+using Mono.Cecil.PE;
+
+using RVA = System.UInt32;
+
+#if !READ_ONLY
+
+namespace Mono.Cecil.Cil {
+
+ sealed class CodeWriter : ByteBuffer {
+
+ readonly RVA code_base;
+ internal readonly MetadataBuilder metadata;
+ readonly Dictionary standalone_signatures;
+ readonly Dictionary tiny_method_bodies;
+
+ MethodBody body;
+
+ public CodeWriter (MetadataBuilder metadata)
+ : base (0)
+ {
+ this.code_base = metadata.text_map.GetNextRVA (TextSegment.CLIHeader);
+ this.metadata = metadata;
+ this.standalone_signatures = new Dictionary ();
+ this.tiny_method_bodies = new Dictionary (new ByteBufferEqualityComparer ());
+ }
+
+ public RVA WriteMethodBody (MethodDefinition method)
+ {
+ RVA rva;
+
+ if (IsUnresolved (method)) {
+ if (method.rva == 0)
+ return 0;
+
+ rva = WriteUnresolvedMethodBody (method);
+ } else {
+ if (IsEmptyMethodBody (method.Body))
+ return 0;
+
+ rva = WriteResolvedMethodBody (method);
+ }
+
+ return rva;
+ }
+
+ static bool IsEmptyMethodBody (MethodBody body)
+ {
+ return body.instructions.IsNullOrEmpty ()
+ && body.variables.IsNullOrEmpty ();
+ }
+
+ static bool IsUnresolved (MethodDefinition method)
+ {
+ return method.HasBody && method.HasImage && method.body == null;
+ }
+
+ RVA WriteUnresolvedMethodBody (MethodDefinition method)
+ {
+ var code_reader = metadata.module.reader.code;
+
+ int code_size;
+ MetadataToken local_var_token;
+ var raw_body = code_reader.PatchRawMethodBody (method, this, out code_size, out local_var_token);
+ var fat_header = (raw_body.buffer [0] & 0x3) == 0x3;
+ if (fat_header)
+ Align (4);
+
+ var rva = BeginMethod ();
+
+ if (fat_header || !GetOrMapTinyMethodBody (raw_body, ref rva)) {
+ WriteBytes (raw_body);
+ }
+
+ if (method.debug_info == null)
+ return rva;
+
+ var symbol_writer = metadata.symbol_writer;
+ if (symbol_writer != null) {
+ method.debug_info.code_size = code_size;
+ method.debug_info.local_var_token = local_var_token;
+ symbol_writer.Write (method.debug_info);
+ }
+
+ return rva;
+ }
+
+ RVA WriteResolvedMethodBody(MethodDefinition method)
+ {
+ RVA rva;
+
+ body = method.Body;
+ ComputeHeader ();
+ if (RequiresFatHeader ()) {
+ Align (4);
+ rva = BeginMethod ();
+ WriteFatHeader ();
+ WriteInstructions ();
+
+ if (body.HasExceptionHandlers)
+ WriteExceptionHandlers ();
+ } else {
+ rva = BeginMethod ();
+ WriteByte ((byte) (0x2 | (body.CodeSize << 2))); // tiny
+ WriteInstructions ();
+
+ var start_position = (int) (rva - code_base);
+ var body_size = position - start_position;
+ var body_bytes = new byte [body_size];
+
+ Array.Copy (buffer, start_position, body_bytes, 0, body_size);
+
+ if (GetOrMapTinyMethodBody (new ByteBuffer (body_bytes), ref rva))
+ position = start_position;
+ }
+
+ var symbol_writer = metadata.symbol_writer;
+ if (symbol_writer != null && method.debug_info != null) {
+ method.debug_info.code_size = body.CodeSize;
+ method.debug_info.local_var_token = body.local_var_token;
+ symbol_writer.Write (method.debug_info);
+ }
+
+ return rva;
+ }
+
+ bool GetOrMapTinyMethodBody (ByteBuffer body, ref RVA rva)
+ {
+ RVA existing_rva;
+ if (tiny_method_bodies.TryGetValue (body, out existing_rva)) {
+ rva = existing_rva;
+ return true;
+ }
+
+ tiny_method_bodies.Add (body, rva);
+ return false;
+ }
+
+ void WriteFatHeader ()
+ {
+ var body = this.body;
+ byte flags = 0x3; // fat
+ if (body.InitLocals)
+ flags |= 0x10; // init locals
+ if (body.HasExceptionHandlers)
+ flags |= 0x8; // more sections
+
+ WriteByte (flags);
+ WriteByte (0x30);
+ WriteInt16 ((short) body.max_stack_size);
+ WriteInt32 (body.code_size);
+ body.local_var_token = body.HasVariables
+ ? GetStandAloneSignature (body.Variables)
+ : MetadataToken.Zero;
+ WriteMetadataToken (body.local_var_token);
+ }
+
+ void WriteInstructions ()
+ {
+ var instructions = body.Instructions;
+ var items = instructions.items;
+ var size = instructions.size;
+
+ for (int i = 0; i < size; i++) {
+ var instruction = items [i];
+ WriteOpCode (instruction.opcode);
+ WriteOperand (instruction);
+ }
+ }
+
+ void WriteOpCode (OpCode opcode)
+ {
+ if (opcode.Size == 1) {
+ WriteByte (opcode.Op2);
+ } else {
+ WriteByte (opcode.Op1);
+ WriteByte (opcode.Op2);
+ }
+ }
+
+ void WriteOperand (Instruction instruction)
+ {
+ var opcode = instruction.opcode;
+ var operand_type = opcode.OperandType;
+ if (operand_type == OperandType.InlineNone)
+ return;
+
+ var operand = instruction.operand;
+ if (operand == null && !(operand_type == OperandType.InlineBrTarget || operand_type == OperandType.ShortInlineBrTarget)) {
+ throw new ArgumentException ();
+ }
+
+ switch (operand_type) {
+ case OperandType.InlineSwitch: {
+ var targets = (Instruction []) operand;
+ WriteInt32 (targets.Length);
+ var diff = instruction.Offset + opcode.Size + (4 * (targets.Length + 1));
+ for (int i = 0; i < targets.Length; i++)
+ WriteInt32 (GetTargetOffset (targets [i]) - diff);
+ break;
+ }
+ case OperandType.ShortInlineBrTarget: {
+ var target = (Instruction) operand;
+ var offset = target != null ? GetTargetOffset (target) : body.code_size;
+ WriteSByte ((sbyte) (offset - (instruction.Offset + opcode.Size + 1)));
+ break;
+ }
+ case OperandType.InlineBrTarget: {
+ var target = (Instruction) operand;
+ var offset = target != null ? GetTargetOffset (target) : body.code_size;
+ WriteInt32 (offset - (instruction.Offset + opcode.Size + 4));
+ break;
+ }
+ case OperandType.ShortInlineVar:
+ WriteByte ((byte) GetVariableIndex ((VariableDefinition) operand));
+ break;
+ case OperandType.ShortInlineArg:
+ WriteByte ((byte) GetParameterIndex ((ParameterDefinition) operand));
+ break;
+ case OperandType.InlineVar:
+ WriteInt16 ((short) GetVariableIndex ((VariableDefinition) operand));
+ break;
+ case OperandType.InlineArg:
+ WriteInt16 ((short) GetParameterIndex ((ParameterDefinition) operand));
+ break;
+ case OperandType.InlineSig:
+ WriteMetadataToken (GetStandAloneSignature ((CallSite) operand));
+ break;
+ case OperandType.ShortInlineI:
+ if (opcode == OpCodes.Ldc_I4_S)
+ WriteSByte ((sbyte) operand);
+ else
+ WriteByte ((byte) operand);
+ break;
+ case OperandType.InlineI:
+ WriteInt32 ((int) operand);
+ break;
+ case OperandType.InlineI8:
+ WriteInt64 ((long) operand);
+ break;
+ case OperandType.ShortInlineR:
+ WriteSingle ((float) operand);
+ break;
+ case OperandType.InlineR:
+ WriteDouble ((double) operand);
+ break;
+ case OperandType.InlineString:
+ WriteMetadataToken (
+ new MetadataToken (
+ TokenType.String,
+ GetUserStringIndex ((string) operand)));
+ break;
+ case OperandType.InlineType:
+ case OperandType.InlineField:
+ case OperandType.InlineMethod:
+ case OperandType.InlineTok:
+ WriteMetadataToken (metadata.LookupToken ((IMetadataTokenProvider) operand));
+ break;
+ default:
+ throw new ArgumentException ();
+ }
+ }
+
+ int GetTargetOffset (Instruction instruction)
+ {
+ if (instruction == null) {
+ var last = body.instructions [body.instructions.size - 1];
+ return last.offset + last.GetSize ();
+ }
+
+ return instruction.offset;
+ }
+
+ uint GetUserStringIndex (string @string)
+ {
+ if (@string == null)
+ return 0;
+
+ return metadata.user_string_heap.GetStringIndex (@string);
+ }
+
+ static int GetVariableIndex (VariableDefinition variable)
+ {
+ return variable.Index;
+ }
+
+ int GetParameterIndex (ParameterDefinition parameter)
+ {
+ if (body.method.HasThis) {
+ if (parameter == body.this_parameter)
+ return 0;
+
+ return parameter.Index + 1;
+ }
+
+ return parameter.Index;
+ }
+
+ bool RequiresFatHeader ()
+ {
+ var body = this.body;
+ return body.CodeSize >= 64
+ || body.InitLocals
+ || body.HasVariables
+ || body.HasExceptionHandlers
+ || body.MaxStackSize > 8;
+ }
+
+ void ComputeHeader ()
+ {
+ int offset = 0;
+ var instructions = body.instructions;
+ var items = instructions.items;
+ var count = instructions.size;
+ var stack_size = 0;
+ var max_stack = 0;
+ Dictionary stack_sizes = null;
+
+ if (body.HasExceptionHandlers)
+ ComputeExceptionHandlerStackSize (ref stack_sizes);
+
+ for (int i = 0; i < count; i++) {
+ var instruction = items [i];
+ instruction.offset = offset;
+ offset += instruction.GetSize ();
+
+ ComputeStackSize (instruction, ref stack_sizes, ref stack_size, ref max_stack);
+ }
+
+ body.code_size = offset;
+ body.max_stack_size = max_stack;
+ }
+
+ void ComputeExceptionHandlerStackSize (ref Dictionary stack_sizes)
+ {
+ var exception_handlers = body.ExceptionHandlers;
+
+ for (int i = 0; i < exception_handlers.Count; i++) {
+ var exception_handler = exception_handlers [i];
+
+ switch (exception_handler.HandlerType) {
+ case ExceptionHandlerType.Catch:
+ AddExceptionStackSize (exception_handler.HandlerStart, ref stack_sizes);
+ break;
+ case ExceptionHandlerType.Filter:
+ AddExceptionStackSize (exception_handler.FilterStart, ref stack_sizes);
+ AddExceptionStackSize (exception_handler.HandlerStart, ref stack_sizes);
+ break;
+ }
+ }
+ }
+
+ static void AddExceptionStackSize (Instruction handler_start, ref Dictionary stack_sizes)
+ {
+ if (handler_start == null)
+ return;
+
+ if (stack_sizes == null)
+ stack_sizes = new Dictionary ();
+
+ stack_sizes [handler_start] = 1;
+ }
+
+ static void ComputeStackSize (Instruction instruction, ref Dictionary stack_sizes, ref int stack_size, ref int max_stack)
+ {
+ int computed_size;
+ if (stack_sizes != null && stack_sizes.TryGetValue (instruction, out computed_size))
+ stack_size = computed_size;
+
+ max_stack = System.Math.Max (max_stack, stack_size);
+ ComputeStackDelta (instruction, ref stack_size);
+ max_stack = System.Math.Max (max_stack, stack_size);
+
+ CopyBranchStackSize (instruction, ref stack_sizes, stack_size);
+ ComputeStackSize (instruction, ref stack_size);
+ }
+
+ static void CopyBranchStackSize (Instruction instruction, ref Dictionary stack_sizes, int stack_size)
+ {
+ if (stack_size == 0)
+ return;
+
+ switch (instruction.opcode.OperandType) {
+ case OperandType.ShortInlineBrTarget:
+ case OperandType.InlineBrTarget:
+ CopyBranchStackSize (ref stack_sizes, (Instruction) instruction.operand, stack_size);
+ break;
+ case OperandType.InlineSwitch:
+ var targets = (Instruction []) instruction.operand;
+ for (int i = 0; i < targets.Length; i++)
+ CopyBranchStackSize (ref stack_sizes, targets [i], stack_size);
+ break;
+ }
+ }
+
+ static void CopyBranchStackSize (ref Dictionary stack_sizes, Instruction target, int stack_size)
+ {
+ if (stack_sizes == null)
+ stack_sizes = new Dictionary ();
+
+ int branch_stack_size = stack_size;
+
+ int computed_size;
+ if (stack_sizes.TryGetValue (target, out computed_size))
+ branch_stack_size = System.Math.Max (branch_stack_size, computed_size);
+
+ stack_sizes [target] = branch_stack_size;
+ }
+
+ static void ComputeStackSize (Instruction instruction, ref int stack_size)
+ {
+ switch (instruction.opcode.FlowControl) {
+ case FlowControl.Branch:
+ case FlowControl.Break:
+ case FlowControl.Throw:
+ case FlowControl.Return:
+ stack_size = 0;
+ break;
+ }
+ }
+
+ static void ComputeStackDelta (Instruction instruction, ref int stack_size)
+ {
+ switch (instruction.opcode.FlowControl) {
+ case FlowControl.Call: {
+ var method = (IMethodSignature) instruction.operand;
+ // pop 'this' argument
+ if (method.HasImplicitThis() && instruction.opcode.Code != Code.Newobj)
+ stack_size--;
+ // pop normal arguments
+ if (method.HasParameters)
+ stack_size -= method.Parameters.Count;
+ // pop function pointer
+ if (instruction.opcode.Code == Code.Calli)
+ stack_size--;
+ // push return value
+ if (method.ReturnType.etype != ElementType.Void || instruction.opcode.Code == Code.Newobj)
+ stack_size++;
+ break;
+ }
+ default:
+ ComputePopDelta (instruction.opcode.StackBehaviourPop, ref stack_size);
+ ComputePushDelta (instruction.opcode.StackBehaviourPush, ref stack_size);
+ break;
+ }
+ }
+
+ static void ComputePopDelta (StackBehaviour pop_behavior, ref int stack_size)
+ {
+ switch (pop_behavior) {
+ case StackBehaviour.Popi:
+ case StackBehaviour.Popref:
+ case StackBehaviour.Pop1:
+ stack_size--;
+ break;
+ case StackBehaviour.Pop1_pop1:
+ case StackBehaviour.Popi_pop1:
+ case StackBehaviour.Popi_popi:
+ case StackBehaviour.Popi_popi8:
+ case StackBehaviour.Popi_popr4:
+ case StackBehaviour.Popi_popr8:
+ case StackBehaviour.Popref_pop1:
+ case StackBehaviour.Popref_popi:
+ stack_size -= 2;
+ break;
+ case StackBehaviour.Popi_popi_popi:
+ case StackBehaviour.Popref_popi_popi:
+ case StackBehaviour.Popref_popi_popi8:
+ case StackBehaviour.Popref_popi_popr4:
+ case StackBehaviour.Popref_popi_popr8:
+ case StackBehaviour.Popref_popi_popref:
+ stack_size -= 3;
+ break;
+ case StackBehaviour.PopAll:
+ stack_size = 0;
+ break;
+ }
+ }
+
+ static void ComputePushDelta (StackBehaviour push_behaviour, ref int stack_size)
+ {
+ switch (push_behaviour) {
+ case StackBehaviour.Push1:
+ case StackBehaviour.Pushi:
+ case StackBehaviour.Pushi8:
+ case StackBehaviour.Pushr4:
+ case StackBehaviour.Pushr8:
+ case StackBehaviour.Pushref:
+ stack_size++;
+ break;
+ case StackBehaviour.Push1_push1:
+ stack_size += 2;
+ break;
+ }
+ }
+
+ void WriteExceptionHandlers ()
+ {
+ Align (4);
+
+ var handlers = body.ExceptionHandlers;
+
+ if (handlers.Count < 0x15 && !RequiresFatSection (handlers))
+ WriteSmallSection (handlers);
+ else
+ WriteFatSection (handlers);
+ }
+
+ static bool RequiresFatSection (Collection handlers)
+ {
+ for (int i = 0; i < handlers.Count; i++) {
+ var handler = handlers [i];
+
+ if (IsFatRange (handler.TryStart, handler.TryEnd))
+ return true;
+
+ if (IsFatRange (handler.HandlerStart, handler.HandlerEnd))
+ return true;
+
+ if (handler.HandlerType == ExceptionHandlerType.Filter
+ && IsFatRange (handler.FilterStart, handler.HandlerStart))
+ return true;
+ }
+
+ return false;
+ }
+
+ static bool IsFatRange (Instruction start, Instruction end)
+ {
+ if (start == null)
+ throw new ArgumentException ();
+
+ if (end == null)
+ return true;
+
+ return end.Offset - start.Offset > 255 || start.Offset > 65535;
+ }
+
+ void WriteSmallSection (Collection handlers)
+ {
+ const byte eh_table = 0x1;
+
+ WriteByte (eh_table);
+ WriteByte ((byte) (handlers.Count * 12 + 4));
+ WriteBytes (2);
+
+ WriteExceptionHandlers (
+ handlers,
+ i => WriteUInt16 ((ushort) i),
+ i => WriteByte ((byte) i));
+ }
+
+ void WriteFatSection (Collection handlers)
+ {
+ const byte eh_table = 0x1;
+ const byte fat_format = 0x40;
+
+ WriteByte (eh_table | fat_format);
+
+ int size = handlers.Count * 24 + 4;
+ WriteByte ((byte) (size & 0xff));
+ WriteByte ((byte) ((size >> 8) & 0xff));
+ WriteByte ((byte) ((size >> 16) & 0xff));
+
+ WriteExceptionHandlers (handlers, WriteInt32, WriteInt32);
+ }
+
+ void WriteExceptionHandlers (Collection handlers, Action write_entry, Action write_length)
+ {
+ for (int i = 0; i < handlers.Count; i++) {
+ var handler = handlers [i];
+
+ write_entry ((int) handler.HandlerType);
+
+ write_entry (handler.TryStart.Offset);
+ write_length (GetTargetOffset (handler.TryEnd) - handler.TryStart.Offset);
+
+ write_entry (handler.HandlerStart.Offset);
+ write_length (GetTargetOffset (handler.HandlerEnd) - handler.HandlerStart.Offset);
+
+ WriteExceptionHandlerSpecific (handler);
+ }
+ }
+
+ void WriteExceptionHandlerSpecific (ExceptionHandler handler)
+ {
+ switch (handler.HandlerType) {
+ case ExceptionHandlerType.Catch:
+ WriteMetadataToken (metadata.LookupToken (handler.CatchType));
+ break;
+ case ExceptionHandlerType.Filter:
+ WriteInt32 (handler.FilterStart.Offset);
+ break;
+ default:
+ WriteInt32 (0);
+ break;
+ }
+ }
+
+ public MetadataToken GetStandAloneSignature (Collection variables)
+ {
+ var signature = metadata.GetLocalVariableBlobIndex (variables);
+
+ return GetStandAloneSignatureToken (signature);
+ }
+
+ public MetadataToken GetStandAloneSignature (CallSite call_site)
+ {
+ var signature = metadata.GetCallSiteBlobIndex (call_site);
+ var token = GetStandAloneSignatureToken (signature);
+ call_site.MetadataToken = token;
+ return token;
+ }
+
+ MetadataToken GetStandAloneSignatureToken (uint signature)
+ {
+ MetadataToken token;
+ if (standalone_signatures.TryGetValue (signature, out token))
+ return token;
+
+ token = new MetadataToken (TokenType.Signature, metadata.AddStandAloneSignature (signature));
+ standalone_signatures.Add (signature, token);
+ return token;
+ }
+
+ RVA BeginMethod ()
+ {
+ return (RVA)(code_base + position);
+ }
+
+ void WriteMetadataToken (MetadataToken token)
+ {
+ WriteUInt32 (token.ToUInt32 ());
+ }
+
+ void Align (int align)
+ {
+ align--;
+ WriteBytes (((position + align) & ~align) - position);
+ }
+ }
+}
+
+#endif
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/Document.cs b/Mono.Cecil.20/Mono.Cecil.Cil/Document.cs
similarity index 53%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/Document.cs
rename to Mono.Cecil.20/Mono.Cecil.Cil/Document.cs
index 1dbdc447..2c2d21e1 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/Document.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/Document.cs
@@ -1,29 +1,11 @@
//
-// Document.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
using System;
@@ -39,6 +21,7 @@ public enum DocumentHashAlgorithm {
None,
MD5,
SHA1,
+ SHA256,
}
public enum DocumentLanguage {
@@ -62,7 +45,7 @@ public enum DocumentLanguageVendor {
Microsoft,
}
- public sealed class Document {
+ public sealed class Document : DebugInformation {
string url;
@@ -107,6 +90,7 @@ public Document (string url)
{
this.url = url;
this.hash = Empty.Array;
+ this.token = new MetadataToken (TokenType.Document);
}
}
}
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/ExceptionHandler.cs b/Mono.Cecil.20/Mono.Cecil.Cil/ExceptionHandler.cs
similarity index 52%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/ExceptionHandler.cs
rename to Mono.Cecil.20/Mono.Cecil.Cil/ExceptionHandler.cs
index c61ff235..6bdb1aa3 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/ExceptionHandler.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/ExceptionHandler.cs
@@ -1,29 +1,11 @@
//
-// ExceptionHandler.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
namespace Mono.Cecil.Cil {
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/ILProcessor.cs b/Mono.Cecil.20/Mono.Cecil.Cil/ILProcessor.cs
similarity index 69%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/ILProcessor.cs
rename to Mono.Cecil.20/Mono.Cecil.Cil/ILProcessor.cs
index 64368e62..0e81fdea 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/ILProcessor.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/ILProcessor.cs
@@ -1,29 +1,11 @@
//
-// ILProcessor.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
using System;
@@ -49,94 +31,94 @@ internal ILProcessor (MethodBody body)
public Instruction Create (OpCode opcode)
{
- return Instruction.Create (opcode);
+ return Instruction.Create (body.method, opcode);
}
public Instruction Create (OpCode opcode, TypeReference type)
{
- return Instruction.Create (opcode, type);
+ return Instruction.Create (body.method, opcode, type);
}
public Instruction Create (OpCode opcode, CallSite site)
{
- return Instruction.Create (opcode, site);
+ return Instruction.Create (body.method, opcode, site);
}
public Instruction Create (OpCode opcode, MethodReference method)
{
- return Instruction.Create (opcode, method);
+ return Instruction.Create (body.method, opcode, method);
}
public Instruction Create (OpCode opcode, FieldReference field)
{
- return Instruction.Create (opcode, field);
+ return Instruction.Create (body.method, opcode, field);
}
public Instruction Create (OpCode opcode, string value)
{
- return Instruction.Create (opcode, value);
+ return Instruction.Create (body.method, opcode, value);
}
public Instruction Create (OpCode opcode, sbyte value)
{
- return Instruction.Create (opcode, value);
+ return Instruction.Create (body.method, opcode, value);
}
public Instruction Create (OpCode opcode, byte value)
{
if (opcode.OperandType == OperandType.ShortInlineVar)
- return Instruction.Create (opcode, body.Variables [value]);
+ return Instruction.Create (body.method, opcode, body.Variables [value]);
if (opcode.OperandType == OperandType.ShortInlineArg)
- return Instruction.Create (opcode, Mixin.GetParameter (body,value));
+ return Instruction.Create (body.method, opcode, body.GetParameter (value));
- return Instruction.Create (opcode, value);
+ return Instruction.Create (body.method, opcode, value);
}
public Instruction Create (OpCode opcode, int value)
{
if (opcode.OperandType == OperandType.InlineVar)
- return Instruction.Create (opcode, body.Variables [value]);
+ return Instruction.Create (body.method, opcode, body.Variables [value]);
if (opcode.OperandType == OperandType.InlineArg)
- return Instruction.Create (opcode, Mixin.GetParameter (body,value));
+ return Instruction.Create (body.method, opcode, body.GetParameter (value));
- return Instruction.Create (opcode, value);
+ return Instruction.Create (body.method, opcode, value);
}
public Instruction Create (OpCode opcode, long value)
{
- return Instruction.Create (opcode, value);
+ return Instruction.Create (body.method, opcode, value);
}
public Instruction Create (OpCode opcode, float value)
{
- return Instruction.Create (opcode, value);
+ return Instruction.Create (body.method, opcode, value);
}
public Instruction Create (OpCode opcode, double value)
{
- return Instruction.Create (opcode, value);
+ return Instruction.Create (body.method, opcode, value);
}
public Instruction Create (OpCode opcode, Instruction target)
{
- return Instruction.Create (opcode, target);
+ return Instruction.Create (body.method, opcode, target);
}
public Instruction Create (OpCode opcode, Instruction [] targets)
{
- return Instruction.Create (opcode, targets);
+ return Instruction.Create (body.method, opcode, targets);
}
public Instruction Create (OpCode opcode, VariableDefinition variable)
{
- return Instruction.Create (opcode, variable);
+ return Instruction.Create (body.method, opcode, variable);
}
public Instruction Create (OpCode opcode, ParameterDefinition parameter)
{
- return Instruction.Create (opcode, parameter);
+ return Instruction.Create (body.method, opcode, parameter);
}
public void Emit (OpCode opcode)
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/Instruction.cs b/Mono.Cecil.20/Mono.Cecil.Cil/Instruction.cs
similarity index 63%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/Instruction.cs
rename to Mono.Cecil.20/Mono.Cecil.Cil/Instruction.cs
index c28d4c99..0225f50c 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/Instruction.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/Instruction.cs
@@ -1,29 +1,11 @@
//
-// Instruction.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
using System;
@@ -40,7 +22,9 @@ public sealed class Instruction {
internal Instruction previous;
internal Instruction next;
- SequencePoint sequence_point;
+ internal MethodDefinition method;
+
+ SequencePoint sequence_point;
public int Offset {
get { return offset; }
@@ -67,21 +51,29 @@ public Instruction Next {
set { next = value; }
}
- public SequencePoint SequencePoint {
- get { return sequence_point; }
- set { sequence_point = value; }
+ public SequencePoint SequencePoint
+ {
+ get {
+ if (sequence_point == null)
+ {
+ sequence_point = method.DebugInformation.GetSequencePoint(this);
+ }
+ return sequence_point;
+ }
}
- internal Instruction (int offset, OpCode opCode)
+ internal Instruction (MethodDefinition method,int offset, OpCode opCode)
{
this.offset = offset;
this.opcode = opCode;
+ this.method = method;
}
- internal Instruction (OpCode opcode, object operand)
+ internal Instruction (MethodDefinition method,OpCode opcode, object operand)
{
this.opcode = opcode;
this.operand = operand;
+ this.method = method;
}
public int GetSize ()
@@ -164,15 +156,15 @@ static void AppendLabel (StringBuilder builder, Instruction instruction)
builder.Append (instruction.offset.ToString ("x4"));
}
- public static Instruction Create (OpCode opcode)
+ public static Instruction Create (MethodDefinition method, OpCode opcode)
{
if (opcode.OperandType != OperandType.InlineNone)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, null);
+ return new Instruction (method, opcode, null);
}
- public static Instruction Create (OpCode opcode, TypeReference type)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, TypeReference type)
{
if (type == null)
throw new ArgumentNullException ("type");
@@ -180,20 +172,20 @@ public static Instruction Create (OpCode opcode, TypeReference type)
opcode.OperandType != OperandType.InlineTok)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, type);
+ return new Instruction (method, opcode, type);
}
- public static Instruction Create (OpCode opcode, CallSite site)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, CallSite site)
{
if (site == null)
throw new ArgumentNullException ("site");
if (opcode.Code != Code.Calli)
throw new ArgumentException ("code");
- return new Instruction (opcode, site);
+ return new Instruction (method, opcode, site);
}
- public static Instruction Create (OpCode opcode, MethodReference method)
+ public static Instruction Create (MethodDefinition method_, OpCode opcode, MethodReference method)
{
if (method == null)
throw new ArgumentNullException ("method");
@@ -201,10 +193,10 @@ public static Instruction Create (OpCode opcode, MethodReference method)
opcode.OperandType != OperandType.InlineTok)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, method);
+ return new Instruction (method_,opcode, method);
}
- public static Instruction Create (OpCode opcode, FieldReference field)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, FieldReference field)
{
if (field == null)
throw new ArgumentNullException ("field");
@@ -212,70 +204,70 @@ public static Instruction Create (OpCode opcode, FieldReference field)
opcode.OperandType != OperandType.InlineTok)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, field);
+ return new Instruction (method, opcode, field);
}
- public static Instruction Create (OpCode opcode, string value)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, string value)
{
if (value == null)
throw new ArgumentNullException ("value");
if (opcode.OperandType != OperandType.InlineString)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, value);
+ return new Instruction (method, opcode, value);
}
- public static Instruction Create (OpCode opcode, sbyte value)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, sbyte value)
{
if (opcode.OperandType != OperandType.ShortInlineI &&
opcode != OpCodes.Ldc_I4_S)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, value);
+ return new Instruction (method, opcode, value);
}
- public static Instruction Create (OpCode opcode, byte value)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, byte value)
{
if (opcode.OperandType != OperandType.ShortInlineI ||
opcode == OpCodes.Ldc_I4_S)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, value);
+ return new Instruction (method, opcode, value);
}
- public static Instruction Create (OpCode opcode, int value)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, int value)
{
if (opcode.OperandType != OperandType.InlineI)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, value);
+ return new Instruction (method, opcode, value);
}
- public static Instruction Create (OpCode opcode, long value)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, long value)
{
if (opcode.OperandType != OperandType.InlineI8)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, value);
+ return new Instruction (method, opcode, value);
}
- public static Instruction Create (OpCode opcode, float value)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, float value)
{
if (opcode.OperandType != OperandType.ShortInlineR)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, value);
+ return new Instruction (method, opcode, value);
}
- public static Instruction Create (OpCode opcode, double value)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, double value)
{
if (opcode.OperandType != OperandType.InlineR)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, value);
+ return new Instruction (method, opcode, value);
}
- public static Instruction Create (OpCode opcode, Instruction target)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, Instruction target)
{
if (target == null)
throw new ArgumentNullException ("target");
@@ -283,20 +275,20 @@ public static Instruction Create (OpCode opcode, Instruction target)
opcode.OperandType != OperandType.ShortInlineBrTarget)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, target);
+ return new Instruction (method, opcode, target);
}
- public static Instruction Create (OpCode opcode, Instruction [] targets)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, Instruction [] targets)
{
if (targets == null)
throw new ArgumentNullException ("targets");
if (opcode.OperandType != OperandType.InlineSwitch)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, targets);
+ return new Instruction (method, opcode, targets);
}
- public static Instruction Create (OpCode opcode, VariableDefinition variable)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, VariableDefinition variable)
{
if (variable == null)
throw new ArgumentNullException ("variable");
@@ -304,10 +296,10 @@ public static Instruction Create (OpCode opcode, VariableDefinition variable)
opcode.OperandType != OperandType.InlineVar)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, variable);
+ return new Instruction (method, opcode, variable);
}
- public static Instruction Create (OpCode opcode, ParameterDefinition parameter)
+ public static Instruction Create (MethodDefinition method, OpCode opcode, ParameterDefinition parameter)
{
if (parameter == null)
throw new ArgumentNullException ("parameter");
@@ -315,7 +307,7 @@ public static Instruction Create (OpCode opcode, ParameterDefinition parameter)
opcode.OperandType != OperandType.InlineArg)
throw new ArgumentException ("opcode");
- return new Instruction (opcode, parameter);
+ return new Instruction (method, opcode, parameter);
}
}
}
diff --git a/Mono.Cecil.20/Mono.Cecil.Cil/MethodBody.cs b/Mono.Cecil.20/Mono.Cecil.Cil/MethodBody.cs
new file mode 100644
index 00000000..eb8baf5b
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/MethodBody.cs
@@ -0,0 +1,248 @@
+//
+// 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.Threading;
+
+using Mono.Collections.Generic;
+
+namespace Mono.Cecil.Cil {
+
+ public sealed class MethodBody {
+
+ readonly internal MethodDefinition method;
+
+ internal ParameterDefinition this_parameter;
+ internal int max_stack_size;
+ internal int code_size;
+ internal bool init_locals;
+ internal MetadataToken local_var_token;
+
+ internal Collection instructions;
+ internal Collection exceptions;
+ internal Collection variables;
+
+ public MethodDefinition Method {
+ get { return method; }
+ }
+
+ public int MaxStackSize {
+ get { return max_stack_size; }
+ set { max_stack_size = value; }
+ }
+
+ public int CodeSize {
+ get { return code_size; }
+ }
+
+ public bool InitLocals {
+ get { return init_locals; }
+ set { init_locals = value; }
+ }
+
+ public MetadataToken LocalVarToken {
+ get { return local_var_token; }
+ set { local_var_token = value; }
+ }
+
+ public Collection Instructions {
+ get { return instructions ?? (instructions = new InstructionCollection (method)); }
+ }
+
+ public bool HasExceptionHandlers {
+ get { return !exceptions.IsNullOrEmpty (); }
+ }
+
+ public Collection ExceptionHandlers {
+ get { return exceptions ?? (exceptions = new Collection ()); }
+ }
+
+ public bool HasVariables {
+ get { return !variables.IsNullOrEmpty (); }
+ }
+
+ public Collection Variables {
+ get { return variables ?? (variables = new VariableDefinitionCollection ()); }
+ }
+
+ public ParameterDefinition ThisParameter {
+ get {
+ if (method == null || method.DeclaringType == null)
+ throw new NotSupportedException ();
+
+ if (!method.HasThis)
+ return null;
+
+ if (this_parameter == null)
+ Interlocked.CompareExchange (ref this_parameter, CreateThisParameter (method), null);
+
+ return this_parameter;
+ }
+ }
+
+ static ParameterDefinition CreateThisParameter (MethodDefinition method)
+ {
+ var parameter_type = method.DeclaringType as TypeReference;
+
+ if (parameter_type.HasGenericParameters) {
+ var instance = new GenericInstanceType (parameter_type);
+ for (int i = 0; i < parameter_type.GenericParameters.Count; i++)
+ instance.GenericArguments.Add (parameter_type.GenericParameters [i]);
+
+ parameter_type = instance;
+
+ }
+
+ if (parameter_type.IsValueType || parameter_type.IsPrimitive)
+ parameter_type = new ByReferenceType (parameter_type);
+
+ return new ParameterDefinition (parameter_type, method);
+ }
+
+ public MethodBody (MethodDefinition method)
+ {
+ this.method = method;
+ }
+
+ public ILProcessor GetILProcessor ()
+ {
+ return new ILProcessor (this);
+ }
+ }
+
+ sealed class VariableDefinitionCollection : Collection {
+
+ internal VariableDefinitionCollection ()
+ {
+ }
+
+ internal VariableDefinitionCollection (int capacity)
+ : base (capacity)
+ {
+ }
+
+ protected override void OnAdd (VariableDefinition item, int index)
+ {
+ item.index = index;
+ }
+
+ protected override void OnInsert (VariableDefinition item, int index)
+ {
+ item.index = index;
+
+ for (int i = index; i < size; i++)
+ items [i].index = i + 1;
+ }
+
+ protected override void OnSet (VariableDefinition item, int index)
+ {
+ item.index = index;
+ }
+
+ protected override void OnRemove (VariableDefinition item, int index)
+ {
+ item.index = -1;
+
+ for (int i = index + 1; i < size; i++)
+ items [i].index = i - 1;
+ }
+ }
+
+ class InstructionCollection : Collection {
+
+ readonly MethodDefinition method;
+
+ internal InstructionCollection (MethodDefinition method)
+ {
+ this.method = method;
+ }
+
+ internal InstructionCollection (MethodDefinition method, int capacity)
+ : base (capacity)
+ {
+ this.method = method;
+ }
+
+ protected override void OnAdd (Instruction item, int index)
+ {
+ if (index == 0)
+ return;
+
+ var previous = items [index - 1];
+ previous.next = item;
+ item.previous = previous;
+ }
+
+ protected override void OnInsert (Instruction item, int index)
+ {
+ if (size == 0)
+ return;
+
+ var current = items [index];
+ if (current == null) {
+ var last = items [index - 1];
+ last.next = item;
+ item.previous = last;
+ return;
+ }
+
+ var previous = current.previous;
+ if (previous != null) {
+ previous.next = item;
+ item.previous = previous;
+ }
+
+ current.previous = item;
+ item.next = current;
+ }
+
+ protected override void OnSet (Instruction item, int index)
+ {
+ var current = items [index];
+
+ item.previous = current.previous;
+ item.next = current.next;
+
+ current.previous = null;
+ current.next = null;
+ }
+
+ protected override void OnRemove (Instruction item, int index)
+ {
+ var previous = item.previous;
+ if (previous != null)
+ previous.next = item.next;
+
+ var next = item.next;
+ if (next != null)
+ next.previous = item.previous;
+
+ RemoveSequencePoint (item);
+
+ item.previous = null;
+ item.next = null;
+ }
+
+ void RemoveSequencePoint (Instruction instruction)
+ {
+ var debug_info = method.debug_info;
+ if (debug_info == null || !debug_info.HasSequencePoints)
+ return;
+
+ var sequence_points = debug_info.sequence_points;
+ for (int i = 0; i < sequence_points.Count; i++) {
+ if (sequence_points [i].Offset == instruction.offset) {
+ sequence_points.RemoveAt (i);
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/OpCode.cs b/Mono.Cecil.20/Mono.Cecil.Cil/OpCode.cs
similarity index 91%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/OpCode.cs
rename to Mono.Cecil.20/Mono.Cecil.Cil/OpCode.cs
index 1a144213..81ab0e12 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/OpCode.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/OpCode.cs
@@ -1,31 +1,15 @@
//
-// OpCode.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
+using System;
+
namespace Mono.Cecil.Cil {
public enum FlowControl {
@@ -104,7 +88,7 @@ public enum StackBehaviour {
Varpush,
}
- public struct OpCode {
+ public struct OpCode : IEquatable {
readonly byte op1;
readonly byte op2;
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/OpCodes.cs b/Mono.Cecil.20/Mono.Cecil.Cil/OpCodes.cs
similarity index 98%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/OpCodes.cs
rename to Mono.Cecil.20/Mono.Cecil.Cil/OpCodes.cs
index 85712ec8..ba0468d3 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Cil/OpCodes.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/OpCodes.cs
@@ -1,29 +1,11 @@
//
-// OpCodes.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
namespace Mono.Cecil.Cil {
diff --git a/Mono.Cecil.20/Mono.Cecil.Cil/PortablePdb.cs b/Mono.Cecil.20/Mono.Cecil.Cil/PortablePdb.cs
new file mode 100644
index 00000000..717249e9
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/PortablePdb.cs
@@ -0,0 +1,611 @@
+//
+// 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.IO;
+using System.IO.Compression;
+
+using Mono.Cecil.Metadata;
+using Mono.Cecil.PE;
+
+namespace Mono.Cecil.Cil {
+
+ public sealed class PortablePdbReaderProvider : ISymbolReaderProvider {
+
+ public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName)
+ {
+ Mixin.CheckModule (module);
+ Mixin.CheckFileName (fileName);
+
+ var file = File.OpenRead (Mixin.GetPdbFileName (fileName));
+ return GetSymbolReader (module, Disposable.Owned (file as Stream), file.Name);
+ }
+
+ public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream)
+ {
+ Mixin.CheckModule (module);
+ Mixin.CheckStream (symbolStream);
+
+ return GetSymbolReader (module, Disposable.NotOwned (symbolStream), symbolStream.GetFileName ());
+ }
+
+ ISymbolReader GetSymbolReader (ModuleDefinition module, Disposable symbolStream, string fileName)
+ {
+ return new PortablePdbReader (ImageReader.ReadPortablePdb (symbolStream, fileName), module);
+ }
+ }
+
+ public sealed class PortablePdbReader : ISymbolReader {
+
+ readonly Image image;
+ readonly ModuleDefinition module;
+ readonly MetadataReader reader;
+ readonly MetadataReader debug_reader;
+
+ bool IsEmbedded { get { return reader.image == debug_reader.image; } }
+
+ internal PortablePdbReader (Image image, ModuleDefinition module)
+ {
+ this.image = image;
+ this.module = module;
+ this.reader = module.reader;
+ this.debug_reader = new MetadataReader (image, module, this.reader);
+ }
+
+#if !READ_ONLY
+ public ISymbolWriterProvider GetWriterProvider ()
+ {
+ return new PortablePdbWriterProvider ();
+ }
+#endif
+
+ public bool ProcessDebugHeader (ImageDebugHeader header)
+ {
+ if (image == module.Image)
+ return true;
+
+ var entry = header.GetCodeViewEntry ();
+ if (entry == null)
+ return false;
+
+ var data = entry.Data;
+
+ if (data.Length < 24)
+ return false;
+
+ var magic = ReadInt32 (data, 0);
+ if (magic != 0x53445352)
+ return false;
+
+ var buffer = new byte [16];
+ Buffer.BlockCopy (data, 4, buffer, 0, 16);
+
+ var module_guid = new Guid (buffer);
+
+ Buffer.BlockCopy (image.PdbHeap.Id, 0, buffer, 0, 16);
+
+ var pdb_guid = new Guid (buffer);
+
+ if (module_guid != pdb_guid)
+ return false;
+
+ ReadModule ();
+ return true;
+ }
+
+ static int ReadInt32 (byte [] bytes, int start)
+ {
+ return (bytes [start]
+ | (bytes [start + 1] << 8)
+ | (bytes [start + 2] << 16)
+ | (bytes [start + 3] << 24));
+ }
+
+ void ReadModule ()
+ {
+ module.custom_infos = debug_reader.GetCustomDebugInformation (module);
+ }
+
+ public MethodDebugInformation Read (MethodDefinition method)
+ {
+ var info = new MethodDebugInformation (method);
+ ReadSequencePoints (info);
+ ReadScope (info);
+ ReadStateMachineKickOffMethod (info);
+ ReadCustomDebugInformations (info);
+ return info;
+ }
+
+ void ReadSequencePoints (MethodDebugInformation method_info)
+ {
+ method_info.sequence_points = debug_reader.ReadSequencePoints (method_info.method);
+ }
+
+ void ReadScope (MethodDebugInformation method_info)
+ {
+ method_info.scope = debug_reader.ReadScope (method_info.method);
+ }
+
+ void ReadStateMachineKickOffMethod (MethodDebugInformation method_info)
+ {
+ method_info.kickoff_method = debug_reader.ReadStateMachineKickoffMethod (method_info.method);
+ }
+
+ void ReadCustomDebugInformations (MethodDebugInformation info)
+ {
+ info.method.custom_infos = debug_reader.GetCustomDebugInformation (info.method);
+ }
+
+ public void Dispose ()
+ {
+ if (IsEmbedded)
+ return;
+
+ image.Dispose ();
+ }
+ }
+
+ public sealed class EmbeddedPortablePdbReaderProvider : ISymbolReaderProvider {
+
+ public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName)
+ {
+ Mixin.CheckModule (module);
+ Mixin.CheckFileName (fileName);
+
+ var header = module.GetDebugHeader ();
+ var entry = header.GetEmbeddedPortablePdbEntry ();
+ if (entry == null)
+ throw new InvalidOperationException ();
+
+ return new EmbeddedPortablePdbReader (
+ (PortablePdbReader) new PortablePdbReaderProvider ().GetSymbolReader (module, GetPortablePdbStream (entry)));
+ }
+
+ static Stream GetPortablePdbStream (ImageDebugHeaderEntry entry)
+ {
+ var compressed_stream = new MemoryStream (entry.Data);
+ var reader = new BinaryStreamReader (compressed_stream);
+ reader.ReadInt32 (); // signature
+ var length = reader.ReadInt32 ();
+ var decompressed_stream = new MemoryStream (length);
+
+ using (var deflate_stream = new DeflateStream (compressed_stream, CompressionMode.Decompress, leaveOpen: true))
+ deflate_stream.CopyTo (decompressed_stream);
+
+ return decompressed_stream;
+ }
+
+ public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream)
+ {
+ throw new NotSupportedException ();
+ }
+ }
+
+ public sealed class EmbeddedPortablePdbReader : ISymbolReader
+ {
+ private readonly PortablePdbReader reader;
+
+ internal EmbeddedPortablePdbReader (PortablePdbReader reader)
+ {
+ if (reader == null)
+ throw new ArgumentNullException ();
+
+ this.reader = reader;
+ }
+
+#if !READ_ONLY
+ public ISymbolWriterProvider GetWriterProvider ()
+ {
+ return new EmbeddedPortablePdbWriterProvider ();
+ }
+#endif
+ public bool ProcessDebugHeader (ImageDebugHeader header)
+ {
+ return reader.ProcessDebugHeader (header);
+ }
+
+ public MethodDebugInformation Read (MethodDefinition method)
+ {
+ return reader.Read (method);
+ }
+
+ public void Dispose ()
+ {
+ reader.Dispose ();
+ }
+ }
+
+
+#if !READ_ONLY
+
+ public sealed class PortablePdbWriterProvider : ISymbolWriterProvider
+ {
+ public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName)
+ {
+ Mixin.CheckModule (module);
+ Mixin.CheckFileName (fileName);
+
+ var file = File.OpenWrite (Mixin.GetPdbFileName (fileName));
+ return GetSymbolWriter (module, Disposable.Owned (file as Stream));
+ }
+
+ public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream)
+ {
+ Mixin.CheckModule (module);
+ Mixin.CheckStream (symbolStream);
+
+ return GetSymbolWriter (module, Disposable.NotOwned (symbolStream));
+ }
+
+ ISymbolWriter GetSymbolWriter (ModuleDefinition module, Disposable stream)
+ {
+ var metadata = new MetadataBuilder (module, this);
+ var writer = ImageWriter.CreateDebugWriter (module, metadata, stream);
+
+ return new PortablePdbWriter (metadata, module, writer);
+ }
+ }
+
+ interface IMetadataSymbolWriter : ISymbolWriter {
+ void SetMetadata (MetadataBuilder metadata);
+ void WriteModule ();
+ }
+
+ public sealed class PortablePdbWriter : ISymbolWriter, IMetadataSymbolWriter {
+
+ readonly MetadataBuilder pdb_metadata;
+ readonly ModuleDefinition module;
+ readonly ImageWriter writer;
+
+ MetadataBuilder module_metadata;
+
+ bool IsEmbedded { get { return writer == null; } }
+
+ internal PortablePdbWriter (MetadataBuilder pdb_metadata, ModuleDefinition module)
+ {
+ this.pdb_metadata = pdb_metadata;
+ this.module = module;
+ }
+
+ internal PortablePdbWriter (MetadataBuilder pdb_metadata, ModuleDefinition module, ImageWriter writer)
+ : this (pdb_metadata, module)
+ {
+ this.writer = writer;
+ }
+
+ void IMetadataSymbolWriter.SetMetadata (MetadataBuilder metadata)
+ {
+ this.module_metadata = metadata;
+
+ if (module_metadata != pdb_metadata)
+ this.pdb_metadata.metadata_builder = metadata;
+ }
+
+ void IMetadataSymbolWriter.WriteModule ()
+ {
+ pdb_metadata.AddCustomDebugInformations (module);
+ }
+
+ public ISymbolReaderProvider GetReaderProvider ()
+ {
+ return new PortablePdbReaderProvider ();
+ }
+
+ public ImageDebugHeader GetDebugHeader ()
+ {
+ if (IsEmbedded)
+ return new ImageDebugHeader ();
+
+ var directory = new ImageDebugDirectory () {
+ MajorVersion = 256,
+ MinorVersion = 20557,
+ Type = ImageDebugType.CodeView,
+ TimeDateStamp = (int) module.timestamp,
+ };
+
+ var buffer = new ByteBuffer ();
+ // RSDS
+ buffer.WriteUInt32 (0x53445352);
+ // Module ID
+ buffer.WriteBytes (module.Mvid.ToByteArray ());
+ // PDB Age
+ buffer.WriteUInt32 (1);
+ // PDB Path
+ var filename = writer.BaseStream.GetFileName ();
+ if (!string.IsNullOrEmpty (filename))
+ filename = Path.GetFileName (filename);
+
+ buffer.WriteBytes (System.Text.Encoding.UTF8.GetBytes (filename));
+ buffer.WriteByte (0);
+
+ var data = new byte [buffer.length];
+ Buffer.BlockCopy (buffer.buffer, 0, data, 0, buffer.length);
+ directory.SizeOfData = data.Length;
+
+ return new ImageDebugHeader (new ImageDebugHeaderEntry (directory, data));
+ }
+
+ public void Write (MethodDebugInformation info)
+ {
+ CheckMethodDebugInformationTable ();
+
+ pdb_metadata.AddMethodDebugInformation (info);
+ }
+
+ void CheckMethodDebugInformationTable ()
+ {
+ var mdi = pdb_metadata.table_heap.GetTable (Table.MethodDebugInformation);
+ if (mdi.length > 0)
+ return;
+
+ // The MethodDebugInformation table has the same length as the Method table
+ mdi.rows = new Row [module_metadata.method_rid - 1];
+ mdi.length = mdi.rows.Length;
+ }
+
+ public void Dispose ()
+ {
+ if (IsEmbedded)
+ return;
+
+ WritePdbFile ();
+ }
+
+ void WritePdbFile ()
+ {
+ WritePdbHeap ();
+
+ WriteTableHeap ();
+
+ writer.BuildMetadataTextMap ();
+ writer.WriteMetadataHeader ();
+ writer.WriteMetadata ();
+
+ writer.Flush ();
+ writer.stream.Dispose ();
+ }
+
+ void WritePdbHeap ()
+ {
+ var pdb_heap = pdb_metadata.pdb_heap;
+
+ pdb_heap.WriteBytes (module.Mvid.ToByteArray ());
+ pdb_heap.WriteUInt32 (module_metadata.timestamp);
+
+ pdb_heap.WriteUInt32 (module_metadata.entry_point.ToUInt32 ());
+
+ var table_heap = module_metadata.table_heap;
+ var tables = table_heap.tables;
+
+ ulong valid = 0;
+ for (int i = 0; i < tables.Length; i++) {
+ if (tables [i] == null || tables [i].Length == 0)
+ continue;
+
+ valid |= (1UL << i);
+ }
+
+ pdb_heap.WriteUInt64 (valid);
+
+ for (int i = 0; i < tables.Length; i++) {
+ if (tables [i] == null || tables [i].Length == 0)
+ continue;
+
+ pdb_heap.WriteUInt32 ((uint) tables [i].Length);
+ }
+ }
+
+ void WriteTableHeap ()
+ {
+ pdb_metadata.table_heap.string_offsets = pdb_metadata.string_heap.WriteStrings ();
+ pdb_metadata.table_heap.ComputeTableInformations ();
+ pdb_metadata.table_heap.WriteTableHeap ();
+ }
+ }
+
+ public sealed class EmbeddedPortablePdbWriterProvider : ISymbolWriterProvider {
+
+ public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName)
+ {
+ Mixin.CheckModule (module);
+ Mixin.CheckFileName (fileName);
+
+ var stream = new MemoryStream ();
+ var pdb_writer = (PortablePdbWriter) new PortablePdbWriterProvider ().GetSymbolWriter (module, stream);
+ return new EmbeddedPortablePdbWriter (stream, pdb_writer);
+ }
+
+ public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream)
+ {
+ throw new NotSupportedException ();
+ }
+ }
+
+ public sealed class EmbeddedPortablePdbWriter : ISymbolWriter, IMetadataSymbolWriter {
+
+ readonly Stream stream;
+ readonly PortablePdbWriter writer;
+
+ internal EmbeddedPortablePdbWriter (Stream stream, PortablePdbWriter writer)
+ {
+ this.stream = stream;
+ this.writer = writer;
+ }
+
+ public ISymbolReaderProvider GetReaderProvider ()
+ {
+ return new EmbeddedPortablePdbReaderProvider ();
+ }
+
+ public ImageDebugHeader GetDebugHeader ()
+ {
+ writer.Dispose ();
+
+ var directory = new ImageDebugDirectory {
+ Type = ImageDebugType.EmbeddedPortablePdb,
+ };
+
+ var data = new MemoryStream ();
+
+ var w = new BinaryStreamWriter (data);
+ w.WriteByte (0x4d);
+ w.WriteByte (0x50);
+ w.WriteByte (0x44);
+ w.WriteByte (0x42);
+
+ w.WriteInt32 ((int) stream.Length);
+
+ stream.Position = 0;
+
+ using (var compress_stream = new DeflateStream (data, CompressionMode.Compress, leaveOpen: true))
+ stream.CopyTo (compress_stream);
+
+ directory.SizeOfData = (int) data.Length;
+
+ return new ImageDebugHeader (new [] {
+ writer.GetDebugHeader ().Entries [0],
+ new ImageDebugHeaderEntry (directory, data.ToArray ())
+ });
+ }
+
+ public void Write (MethodDebugInformation info)
+ {
+ writer.Write (info);
+ }
+
+ public void Dispose ()
+ {
+ }
+
+ void IMetadataSymbolWriter.SetMetadata (MetadataBuilder metadata)
+ {
+ ((IMetadataSymbolWriter) writer).SetMetadata (metadata);
+ }
+
+ void IMetadataSymbolWriter.WriteModule ()
+ {
+ ((IMetadataSymbolWriter) writer).WriteModule ();
+ }
+ }
+
+#endif
+
+ static class PdbGuidMapping {
+
+ static readonly Dictionary guid_language = new Dictionary ();
+ static readonly Dictionary language_guid = new Dictionary ();
+
+ static PdbGuidMapping ()
+ {
+ AddMapping (DocumentLanguage.C, new Guid ("63a08714-fc37-11d2-904c-00c04fa302a1"));
+ AddMapping (DocumentLanguage.Cpp, new Guid ("3a12d0b7-c26c-11d0-b442-00a0244a1dd2"));
+ AddMapping (DocumentLanguage.CSharp, new Guid ("3f5162f8-07c6-11d3-9053-00c04fa302a1"));
+ AddMapping (DocumentLanguage.Basic, new Guid ("3a12d0b8-c26c-11d0-b442-00a0244a1dd2"));
+ AddMapping (DocumentLanguage.Java, new Guid ("3a12d0b4-c26c-11d0-b442-00a0244a1dd2"));
+ AddMapping (DocumentLanguage.Cobol, new Guid ("af046cd1-d0e1-11d2-977c-00a0c9b4d50c"));
+ AddMapping (DocumentLanguage.Pascal, new Guid ("af046cd2-d0e1-11d2-977c-00a0c9b4d50c"));
+ AddMapping (DocumentLanguage.Cil, new Guid ("af046cd3-d0e1-11d2-977c-00a0c9b4d50c"));
+ AddMapping (DocumentLanguage.JScript, new Guid ("3a12d0b6-c26c-11d0-b442-00a0244a1dd2"));
+ AddMapping (DocumentLanguage.Smc, new Guid ("0d9b9f7b-6611-11d3-bd2a-0000f80849bd"));
+ AddMapping (DocumentLanguage.MCpp, new Guid ("4b35fde8-07c6-11d3-9053-00c04fa302a1"));
+ AddMapping (DocumentLanguage.FSharp, new Guid ("ab4f38c9-b6e6-43ba-be3b-58080b2ccce3"));
+ }
+
+ static void AddMapping (DocumentLanguage language, Guid guid)
+ {
+ guid_language.Add (guid, language);
+ language_guid.Add (language, guid);
+ }
+
+ static readonly Guid type_text = new Guid ("5a869d0b-6611-11d3-bd2a-0000f80849bd");
+
+ public static DocumentType ToType (this Guid guid)
+ {
+ if (guid == type_text)
+ return DocumentType.Text;
+
+ return DocumentType.Other;
+ }
+
+ public static Guid ToGuid (this DocumentType type)
+ {
+ if (type == DocumentType.Text)
+ return type_text;
+
+ return new Guid ();
+ }
+
+ static readonly Guid hash_md5 = new Guid ("406ea660-64cf-4c82-b6f0-42d48172a799");
+ static readonly Guid hash_sha1 = new Guid ("ff1816ec-aa5e-4d10-87f7-6f4963833460");
+ static readonly Guid hash_sha256 = new Guid ("8829d00f-11b8-4213-878b-770e8597ac16");
+
+ public static DocumentHashAlgorithm ToHashAlgorithm (this Guid guid)
+ {
+ if (guid == hash_md5)
+ return DocumentHashAlgorithm.MD5;
+
+ if (guid == hash_sha1)
+ return DocumentHashAlgorithm.SHA1;
+
+ if (guid == hash_sha256)
+ return DocumentHashAlgorithm.SHA256;
+
+ return DocumentHashAlgorithm.None;
+ }
+
+ public static Guid ToGuid (this DocumentHashAlgorithm hash_algo)
+ {
+ if (hash_algo == DocumentHashAlgorithm.MD5)
+ return hash_md5;
+
+ if (hash_algo == DocumentHashAlgorithm.SHA1)
+ return hash_sha1;
+
+ return new Guid ();
+ }
+
+ public static DocumentLanguage ToLanguage (this Guid guid)
+ {
+ DocumentLanguage language;
+ if (!guid_language.TryGetValue (guid, out language))
+ return DocumentLanguage.Other;
+
+ return language;
+ }
+
+ public static Guid ToGuid (this DocumentLanguage language)
+ {
+ Guid guid;
+ if (!language_guid.TryGetValue (language, out guid))
+ return new Guid ();
+
+ return guid;
+ }
+
+ static readonly Guid vendor_ms = new Guid ("994b45c4-e6e9-11d2-903f-00c04fa302a1");
+
+ public static DocumentLanguageVendor ToVendor (this Guid guid)
+ {
+ if (guid == vendor_ms)
+ return DocumentLanguageVendor.Microsoft;
+
+ return DocumentLanguageVendor.Other;
+ }
+
+ public static Guid ToGuid (this DocumentLanguageVendor vendor)
+ {
+ if (vendor == DocumentLanguageVendor.Microsoft)
+ return vendor_ms;
+
+ return new Guid ();
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Cil/SequencePoint.cs b/Mono.Cecil.20/Mono.Cecil.Cil/SequencePoint.cs
new file mode 100644
index 00000000..725d307a
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/SequencePoint.cs
@@ -0,0 +1,76 @@
+//
+// 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;
+
+namespace Mono.Cecil.Cil {
+
+ public sealed class SequencePoint {
+
+ internal InstructionOffset offset;
+ Document document;
+
+ int start_line;
+ int start_column;
+ int end_line;
+ int end_column;
+
+ public int Offset {
+ get { return offset.Offset; }
+ }
+
+ public int StartLine {
+ get { return start_line; }
+ set { start_line = value; }
+ }
+
+ public int StartColumn {
+ get { return start_column; }
+ set { start_column = value; }
+ }
+
+ public int EndLine {
+ get { return end_line; }
+ set { end_line = value; }
+ }
+
+ public int EndColumn {
+ get { return end_column; }
+ set { end_column = value; }
+ }
+
+ public bool IsHidden {
+ get { return start_line == 0xfeefee && start_line == end_line; }
+ }
+
+ public Document Document {
+ get { return document; }
+ set { document = value; }
+ }
+
+ internal SequencePoint (int offset, Document document)
+ {
+ if (document == null)
+ throw new ArgumentNullException ("document");
+
+ this.offset = new InstructionOffset (offset);
+ this.document = document;
+ }
+
+ public SequencePoint (Instruction instruction, Document document)
+ {
+ if (document == null)
+ throw new ArgumentNullException ("document");
+
+ this.offset = new InstructionOffset (instruction);
+ this.document = document;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Cil/Symbols.cs b/Mono.Cecil.20/Mono.Cecil.Cil/Symbols.cs
new file mode 100644
index 00000000..85c5334d
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/Symbols.cs
@@ -0,0 +1,1010 @@
+//
+// 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.IO;
+using System.Runtime.InteropServices;
+using SR = System.Reflection;
+
+using Mono.Collections.Generic;
+using Mono.Cecil.Cil;
+
+namespace Mono.Cecil.Cil {
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct ImageDebugDirectory {
+ public const int Size = 28;
+
+ public int Characteristics;
+ public int TimeDateStamp;
+ public short MajorVersion;
+ public short MinorVersion;
+ public ImageDebugType Type;
+ public int SizeOfData;
+ public int AddressOfRawData;
+ public int PointerToRawData;
+ }
+
+ public enum ImageDebugType {
+ CodeView = 2,
+ Deterministic = 16,
+ EmbeddedPortablePdb = 17,
+ }
+
+ public sealed class ImageDebugHeader {
+
+ readonly ImageDebugHeaderEntry [] entries;
+
+ public bool HasEntries {
+ get { return !entries.IsNullOrEmpty (); }
+ }
+
+ public ImageDebugHeaderEntry [] Entries {
+ get { return entries; }
+ }
+
+ public ImageDebugHeader (ImageDebugHeaderEntry [] entries)
+ {
+ this.entries = entries ?? Empty.Array;
+ }
+
+ public ImageDebugHeader ()
+ : this (Empty.Array)
+ {
+ }
+
+ public ImageDebugHeader (ImageDebugHeaderEntry entry)
+ : this (new [] { entry })
+ {
+ }
+ }
+
+ public sealed class ImageDebugHeaderEntry {
+
+ ImageDebugDirectory directory;
+ readonly byte [] data;
+
+ public ImageDebugDirectory Directory {
+ get { return directory; }
+ internal set { directory = value; }
+ }
+
+ public byte [] Data {
+ get { return data; }
+ }
+
+ public ImageDebugHeaderEntry (ImageDebugDirectory directory, byte [] data)
+ {
+ this.directory = directory;
+ this.data = data ?? Empty.Array;
+ }
+ }
+
+ public sealed class ScopeDebugInformation : DebugInformation {
+
+ internal InstructionOffset start;
+ internal InstructionOffset end;
+ internal ImportDebugInformation import;
+ internal Collection scopes;
+ internal Collection variables;
+ internal Collection constants;
+
+ public InstructionOffset Start {
+ get { return start; }
+ set { start = value; }
+ }
+
+ public InstructionOffset End {
+ get { return end; }
+ set { end = value; }
+ }
+
+ public ImportDebugInformation Import {
+ get { return import; }
+ set { import = value; }
+ }
+
+ public bool HasScopes {
+ get { return !scopes.IsNullOrEmpty (); }
+ }
+
+ public Collection Scopes {
+ get { return scopes ?? (scopes = new Collection ()); }
+ }
+
+ public bool HasVariables {
+ get { return !variables.IsNullOrEmpty (); }
+ }
+
+ public Collection Variables {
+ get { return variables ?? (variables = new Collection ()); }
+ }
+
+ public bool HasConstants {
+ get { return !constants.IsNullOrEmpty (); }
+ }
+
+ public Collection Constants {
+ get { return constants ?? (constants = new Collection ()); }
+ }
+
+ internal ScopeDebugInformation ()
+ {
+ this.token = new MetadataToken (TokenType.LocalScope);
+ }
+
+ public ScopeDebugInformation (Instruction start, Instruction end)
+ : this ()
+ {
+ if (start == null)
+ throw new ArgumentNullException ("start");
+
+ this.start = new InstructionOffset (start);
+
+ if (end != null)
+ this.end = new InstructionOffset (end);
+ }
+
+ public bool TryGetName (VariableDefinition variable, out string name)
+ {
+ name = null;
+ if (variables == null || variables.Count == 0)
+ return false;
+
+ for (int i = 0; i < variables.Count; i++) {
+ if (variables [i].Index == variable.Index) {
+ name = variables [i].Name;
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ public struct InstructionOffset {
+
+ readonly Instruction instruction;
+ readonly int? offset;
+
+ public int Offset {
+ get {
+ if (instruction != null)
+ return instruction.Offset;
+ if (offset.HasValue)
+ return offset.Value;
+
+ throw new NotSupportedException ();
+ }
+ }
+
+ public bool IsEndOfMethod {
+ get { return instruction == null && !offset.HasValue; }
+ }
+
+ public InstructionOffset (Instruction instruction)
+ {
+ if (instruction == null)
+ throw new ArgumentNullException ("instruction");
+
+ this.instruction = instruction;
+ this.offset = null;
+ }
+
+ public InstructionOffset (int offset)
+ {
+ this.instruction = null;
+ this.offset = offset;
+ }
+ }
+
+ [Flags]
+ public enum VariableAttributes : ushort {
+ None = 0,
+ DebuggerHidden = 1,
+ }
+
+ public struct VariableIndex {
+ readonly VariableDefinition variable;
+ readonly int? index;
+
+ public int Index {
+ get {
+ if (variable != null)
+ return variable.Index;
+ if (index.HasValue)
+ return index.Value;
+
+ throw new NotSupportedException ();
+ }
+ }
+
+ public VariableIndex (VariableDefinition variable)
+ {
+ if (variable == null)
+ throw new ArgumentNullException ("variable");
+
+ this.variable = variable;
+ this.index = null;
+ }
+
+ public VariableIndex (int index)
+ {
+ this.variable = null;
+ this.index = index;
+ }
+ }
+
+ public abstract class DebugInformation : ICustomDebugInformationProvider {
+
+ internal MetadataToken token;
+ internal Collection custom_infos;
+
+ public MetadataToken MetadataToken {
+ get { return token; }
+ set { token = value; }
+ }
+
+ public bool HasCustomDebugInformations {
+ get { return !custom_infos.IsNullOrEmpty (); }
+ }
+
+ public Collection CustomDebugInformations {
+ get { return custom_infos ?? (custom_infos = new Collection ()); }
+ }
+
+ internal DebugInformation ()
+ {
+ }
+ }
+
+ public sealed class VariableDebugInformation : DebugInformation {
+
+ string name;
+ ushort attributes;
+ internal VariableIndex index;
+
+ public int Index {
+ get { return index.Index; }
+ }
+
+ public string Name {
+ get { return name; }
+ set { name = value; }
+ }
+
+ public VariableAttributes Attributes {
+ get { return (VariableAttributes) attributes; }
+ set { attributes = (ushort) value; }
+ }
+
+ public bool IsDebuggerHidden {
+ get { return attributes.GetAttributes ((ushort) VariableAttributes.DebuggerHidden); }
+ set { attributes = attributes.SetAttributes ((ushort) VariableAttributes.DebuggerHidden, value); }
+ }
+
+ internal VariableDebugInformation (int index, string name)
+ {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ this.index = new VariableIndex (index);
+ this.name = name;
+ }
+
+ public VariableDebugInformation (VariableDefinition variable, string name)
+ {
+ if (variable == null)
+ throw new ArgumentNullException ("variable");
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ this.index = new VariableIndex (variable);
+ this.name = name;
+ this.token = new MetadataToken (TokenType.LocalVariable);
+ }
+ }
+
+ public sealed class ConstantDebugInformation : DebugInformation {
+
+ string name;
+ TypeReference constant_type;
+ object value;
+
+ public string Name {
+ get { return name; }
+ set { name = value; }
+ }
+
+ public TypeReference ConstantType {
+ get { return constant_type; }
+ set { constant_type = value; }
+ }
+
+ public object Value {
+ get { return value; }
+ set { this.value = value; }
+ }
+
+ public ConstantDebugInformation (string name, TypeReference constant_type, object value)
+ {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ this.name = name;
+ this.constant_type = constant_type;
+ this.value = value;
+ this.token = new MetadataToken (TokenType.LocalConstant);
+ }
+ }
+
+ public enum ImportTargetKind : byte {
+ ImportNamespace = 1,
+ ImportNamespaceInAssembly = 2,
+ ImportType = 3,
+ ImportXmlNamespaceWithAlias = 4,
+ ImportAlias = 5,
+ DefineAssemblyAlias = 6,
+ DefineNamespaceAlias = 7,
+ DefineNamespaceInAssemblyAlias = 8,
+ DefineTypeAlias = 9,
+ }
+
+ public sealed class ImportTarget {
+
+ internal ImportTargetKind kind;
+
+ internal string @namespace;
+ internal TypeReference type;
+ internal AssemblyNameReference reference;
+ internal string alias;
+
+ public string Namespace {
+ get { return @namespace; }
+ set { @namespace = value; }
+ }
+
+ public TypeReference Type {
+ get { return type; }
+ set { type = value; }
+ }
+
+ public AssemblyNameReference AssemblyReference {
+ get { return reference; }
+ set { reference = value; }
+ }
+
+ public string Alias {
+ get { return alias; }
+ set { alias = value; }
+ }
+
+ public ImportTargetKind Kind {
+ get { return kind; }
+ set { kind = value; }
+ }
+
+ public ImportTarget (ImportTargetKind kind)
+ {
+ this.kind = kind;
+ }
+ }
+
+ public sealed class ImportDebugInformation : DebugInformation {
+
+ internal ImportDebugInformation parent;
+ internal Collection targets;
+
+ public bool HasTargets {
+ get { return !targets.IsNullOrEmpty (); }
+ }
+
+ public Collection Targets {
+ get { return targets ?? (targets = new Collection ()); }
+ }
+
+ public ImportDebugInformation Parent {
+ get { return parent; }
+ set { parent = value; }
+ }
+
+ public ImportDebugInformation ()
+ {
+ this.token = new MetadataToken (TokenType.ImportScope);
+ }
+ }
+
+ public interface ICustomDebugInformationProvider : IMetadataTokenProvider {
+ bool HasCustomDebugInformations { get; }
+ Collection CustomDebugInformations { get; }
+ }
+
+ public enum CustomDebugInformationKind {
+ Binary,
+ StateMachineScope,
+ DynamicVariable,
+ DefaultNamespace,
+ AsyncMethodBody,
+ EmbeddedSource,
+ SourceLink,
+ }
+
+ public abstract class CustomDebugInformation : DebugInformation {
+
+ Guid identifier;
+
+ public Guid Identifier {
+ get { return identifier; }
+ }
+
+ public abstract CustomDebugInformationKind Kind { get; }
+
+ internal CustomDebugInformation (Guid identifier)
+ {
+ this.identifier = identifier;
+ this.token = new MetadataToken (TokenType.CustomDebugInformation);
+ }
+ }
+
+ public sealed class BinaryCustomDebugInformation : CustomDebugInformation {
+
+ byte [] data;
+
+ public byte [] Data {
+ get { return data; }
+ set { data = value; }
+ }
+
+ public override CustomDebugInformationKind Kind {
+ get { return CustomDebugInformationKind.Binary; }
+ }
+
+ public BinaryCustomDebugInformation (Guid identifier, byte [] data)
+ : base (identifier)
+ {
+ this.data = data;
+ }
+ }
+
+ public sealed class AsyncMethodBodyDebugInformation : CustomDebugInformation {
+
+ internal InstructionOffset catch_handler;
+ internal Collection yields;
+ internal Collection resumes;
+ internal MethodDefinition move_next;
+
+ public InstructionOffset CatchHandler {
+ get { return catch_handler; }
+ set { catch_handler = value; }
+ }
+
+ public Collection Yields {
+ get { return yields ?? (yields = new Collection ()); }
+ }
+
+ public Collection Resumes {
+ get { return resumes ?? (resumes = new Collection ()); }
+ }
+
+ public MethodDefinition MoveNextMethod {
+ get { return move_next; }
+ set { move_next = value; }
+ }
+
+ public override CustomDebugInformationKind Kind {
+ get { return CustomDebugInformationKind.AsyncMethodBody; }
+ }
+
+ public static Guid KindIdentifier = new Guid ("{54FD2AC5-E925-401A-9C2A-F94F171072F8}");
+
+ internal AsyncMethodBodyDebugInformation (int catchHandler)
+ : base (KindIdentifier)
+ {
+ this.catch_handler = new InstructionOffset (catchHandler);
+ }
+
+ public AsyncMethodBodyDebugInformation (Instruction catchHandler)
+ : base (KindIdentifier)
+ {
+ this.catch_handler = new InstructionOffset (catchHandler);
+ }
+
+ public AsyncMethodBodyDebugInformation ()
+ : base (KindIdentifier)
+ {
+ this.catch_handler = new InstructionOffset (-1);
+ }
+ }
+
+ public sealed class StateMachineScopeDebugInformation : CustomDebugInformation {
+
+ internal InstructionOffset start;
+ internal InstructionOffset end;
+
+ public InstructionOffset Start {
+ get { return start; }
+ set { start = value; }
+ }
+
+ public InstructionOffset End {
+ get { return end; }
+ set { end = value; }
+ }
+
+ public override CustomDebugInformationKind Kind {
+ get { return CustomDebugInformationKind.StateMachineScope; }
+ }
+
+ public static Guid KindIdentifier = new Guid ("{6DA9A61E-F8C7-4874-BE62-68BC5630DF71}");
+
+ internal StateMachineScopeDebugInformation (int start, int end)
+ : base (KindIdentifier)
+ {
+ this.start = new InstructionOffset (start);
+ this.end = new InstructionOffset (end);
+ }
+
+ public StateMachineScopeDebugInformation (Instruction start, Instruction end)
+ : base (KindIdentifier)
+ {
+ this.start = new InstructionOffset (start);
+ this.end = end != null ? new InstructionOffset (end) : new InstructionOffset ();
+ }
+ }
+
+ public sealed class EmbeddedSourceDebugInformation : CustomDebugInformation {
+
+ internal byte [] content;
+ internal bool compress;
+
+ public byte [] Content {
+ get { return content; }
+ set { content = value; }
+ }
+
+ public bool Compress {
+ get { return compress; }
+ set { compress = value; }
+ }
+
+ public override CustomDebugInformationKind Kind {
+ get { return CustomDebugInformationKind.EmbeddedSource; }
+ }
+
+ public static Guid KindIdentifier = new Guid ("{0E8A571B-6926-466E-B4AD-8AB04611F5FE}");
+
+ public EmbeddedSourceDebugInformation (byte [] content, bool compress)
+ : base (KindIdentifier)
+ {
+ this.content = content;
+ this.compress = compress;
+ }
+ }
+
+ public sealed class SourceLinkDebugInformation : CustomDebugInformation {
+
+ internal string content;
+
+ public string Content {
+ get { return content; }
+ set { content = value; }
+ }
+
+ public override CustomDebugInformationKind Kind {
+ get { return CustomDebugInformationKind.SourceLink; }
+ }
+
+ public static Guid KindIdentifier = new Guid ("{CC110556-A091-4D38-9FEC-25AB9A351A6A}");
+
+ public SourceLinkDebugInformation (string content)
+ : base (KindIdentifier)
+ {
+ this.content = content;
+ }
+ }
+
+ public sealed class MethodDebugInformation : DebugInformation {
+
+ internal MethodDefinition method;
+ internal Collection sequence_points;
+ internal ScopeDebugInformation scope;
+ internal MethodDefinition kickoff_method;
+ internal int code_size;
+ internal MetadataToken local_var_token;
+
+ public MethodDefinition Method {
+ get { return method; }
+ }
+
+ public bool HasSequencePoints {
+ get { return !sequence_points.IsNullOrEmpty (); }
+ }
+
+ public Collection SequencePoints {
+ get { return sequence_points ?? (sequence_points = new Collection ()); }
+ }
+
+ public ScopeDebugInformation Scope {
+ get { return scope; }
+ set { scope = value; }
+ }
+
+ public MethodDefinition StateMachineKickOffMethod {
+ get { return kickoff_method; }
+ set { kickoff_method = value; }
+ }
+
+ internal MethodDebugInformation (MethodDefinition method)
+ {
+ if (method == null)
+ throw new ArgumentNullException ("method");
+
+ this.method = method;
+ this.token = new MetadataToken (TokenType.MethodDebugInformation, method.MetadataToken.RID);
+ }
+
+ public SequencePoint GetSequencePoint (Instruction instruction)
+ {
+ if (!HasSequencePoints)
+ return null;
+
+ for (int i = 0; i < sequence_points.Count; i++)
+ if (sequence_points [i].Offset == instruction.Offset)
+ return sequence_points [i];
+
+ return null;
+ }
+
+ public IDictionary GetSequencePointMapping ()
+ {
+ var instruction_mapping = new Dictionary ();
+ if (!HasSequencePoints || !method.HasBody)
+ return instruction_mapping;
+
+ var offset_mapping = new Dictionary (sequence_points.Count);
+
+ for (int i = 0; i < sequence_points.Count; i++) {
+ if (!offset_mapping.ContainsKey (sequence_points [i].Offset))
+ offset_mapping.Add (sequence_points [i].Offset, sequence_points [i]);
+ }
+
+ var instructions = method.Body.Instructions;
+
+ for (int i = 0; i < instructions.Count; i++) {
+ SequencePoint sequence_point;
+ if (offset_mapping.TryGetValue (instructions [i].Offset, out sequence_point))
+ instruction_mapping.Add (instructions [i], sequence_point);
+ }
+
+ return instruction_mapping;
+ }
+
+ public IEnumerable GetScopes ()
+ {
+ if (scope == null)
+ return Empty.Array;
+
+ return GetScopes (new[] { scope });
+ }
+
+ static IEnumerable GetScopes (IList scopes)
+ {
+ for (int i = 0; i < scopes.Count; i++) {
+ var scope = scopes [i];
+
+ yield return scope;
+
+ if (!scope.HasScopes)
+ continue;
+
+ foreach (var sub_scope in GetScopes (scope.Scopes))
+ yield return sub_scope;
+ }
+ }
+
+ public bool TryGetName (VariableDefinition variable, out string name)
+ {
+ name = null;
+
+ var has_name = false;
+ var unique_name = "";
+
+ foreach (var scope in GetScopes ()) {
+ string slot_name;
+ if (!scope.TryGetName (variable, out slot_name))
+ continue;
+
+ if (!has_name) {
+ has_name = true;
+ unique_name = slot_name;
+ continue;
+ }
+
+ if (unique_name != slot_name)
+ return false;
+ }
+
+ name = unique_name;
+ return has_name;
+ }
+ }
+
+ public interface ISymbolReader : IDisposable {
+#if !READ_ONLY
+ ISymbolWriterProvider GetWriterProvider ();
+#endif
+ bool ProcessDebugHeader (ImageDebugHeader header);
+ MethodDebugInformation Read (MethodDefinition method);
+ }
+
+ public interface ISymbolReaderProvider {
+ ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName);
+ ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream);
+ }
+
+ public class DefaultSymbolReaderProvider : ISymbolReaderProvider {
+
+ readonly bool throw_if_no_symbol;
+
+ public DefaultSymbolReaderProvider ()
+ : this (throwIfNoSymbol: true)
+ {
+ }
+
+ public DefaultSymbolReaderProvider (bool throwIfNoSymbol)
+ {
+ throw_if_no_symbol = throwIfNoSymbol;
+ }
+
+ public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName)
+ {
+ if (module.Image.HasDebugTables ())
+ return null;
+
+ if (module.HasDebugHeader) {
+ var header = module.GetDebugHeader ();
+ var entry = header.GetEmbeddedPortablePdbEntry ();
+ if (entry != null)
+ return new EmbeddedPortablePdbReaderProvider ().GetSymbolReader (module, fileName);
+ }
+
+ var pdb_file_name = Mixin.GetPdbFileName (fileName);
+
+ if (File.Exists (pdb_file_name)) {
+ if (Mixin.IsPortablePdb (Mixin.GetPdbFileName (fileName)))
+ return new PortablePdbReaderProvider ().GetSymbolReader (module, fileName);
+
+ try {
+ return SymbolProvider.GetReaderProvider (SymbolKind.NativePdb).GetSymbolReader (module, fileName);
+ } catch (TypeLoadException) {
+ // We might not include support for native pdbs.
+ }
+ }
+
+ var mdb_file_name = Mixin.GetMdbFileName (fileName);
+ if (File.Exists (mdb_file_name)) {
+ try {
+ return SymbolProvider.GetReaderProvider (SymbolKind.Mdb).GetSymbolReader (module, fileName);
+ } catch (TypeLoadException) {
+ // We might not include support for mdbs.
+ }
+ }
+
+ if (throw_if_no_symbol)
+ throw new FileNotFoundException (string.Format ("No symbol found for file: {0}", fileName));
+
+ return null;
+ }
+
+ public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream)
+ {
+ throw new NotSupportedException ();
+ }
+ }
+
+ enum SymbolKind {
+ NativePdb,
+ PortablePdb,
+ EmbeddedPortablePdb,
+ Mdb,
+ }
+
+ static class SymbolProvider {
+
+ static SR.AssemblyName GetSymbolAssemblyName (SymbolKind kind)
+ {
+ if (kind == SymbolKind.PortablePdb)
+ throw new ArgumentException ();
+
+ var suffix = GetSymbolNamespace (kind);
+
+ var cecil_name = typeof (SymbolProvider).Assembly ().GetName ();
+
+ var name = new SR.AssemblyName {
+ Name = cecil_name.Name + "." + suffix,
+ Version = cecil_name.Version,
+ };
+
+ name.SetPublicKeyToken (cecil_name.GetPublicKeyToken ());
+
+ return name;
+ }
+
+ static Type GetSymbolType (SymbolKind kind, string fullname)
+ {
+ var type = Type.GetType (fullname);
+ if (type != null)
+ return type;
+
+ var assembly_name = GetSymbolAssemblyName (kind);
+
+ type = Type.GetType (fullname + ", " + assembly_name.FullName);
+ if (type != null)
+ return type;
+
+ try {
+ var assembly = SR.Assembly.Load (assembly_name);
+ if (assembly != null)
+ return assembly.GetType (fullname);
+ } catch (FileNotFoundException) {
+ } catch (FileLoadException) {
+ }
+
+ return null;
+ }
+
+ public static ISymbolReaderProvider GetReaderProvider (SymbolKind kind)
+ {
+ if (kind == SymbolKind.PortablePdb)
+ return new PortablePdbReaderProvider ();
+ if (kind == SymbolKind.EmbeddedPortablePdb)
+ return new EmbeddedPortablePdbReaderProvider ();
+
+ var provider_name = GetSymbolTypeName (kind, "ReaderProvider");
+ var type = GetSymbolType (kind, provider_name);
+ if (type == null)
+ throw new TypeLoadException ("Could not find symbol provider type " + provider_name);
+
+ return (ISymbolReaderProvider) Activator.CreateInstance (type);
+ }
+
+ static string GetSymbolTypeName (SymbolKind kind, string name)
+ {
+ return "Mono.Cecil" + "." + GetSymbolNamespace (kind) + "." + kind + name;
+ }
+
+ static string GetSymbolNamespace (SymbolKind kind)
+ {
+ if (kind == SymbolKind.PortablePdb || kind == SymbolKind.EmbeddedPortablePdb)
+ return "Cil";
+ if (kind == SymbolKind.NativePdb)
+ return "Pdb";
+ if (kind == SymbolKind.Mdb)
+ return "Mdb";
+
+ throw new ArgumentException ();
+ }
+ }
+
+#if !READ_ONLY
+
+ public interface ISymbolWriter : IDisposable {
+
+ ISymbolReaderProvider GetReaderProvider ();
+ ImageDebugHeader GetDebugHeader ();
+ void Write (MethodDebugInformation info);
+ }
+
+ public interface ISymbolWriterProvider {
+
+ ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName);
+ ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream);
+ }
+
+ public class DefaultSymbolWriterProvider : ISymbolWriterProvider {
+
+ public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName)
+ {
+ var reader = module.SymbolReader;
+ if (reader == null)
+ throw new InvalidOperationException ();
+
+ if (module.Image != null && module.Image.HasDebugTables ())
+ return null;
+
+ return reader.GetWriterProvider ().GetSymbolWriter (module, fileName);
+ }
+
+ public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream)
+ {
+ throw new NotSupportedException ();
+ }
+ }
+
+#endif
+}
+
+namespace Mono.Cecil {
+
+ static partial class Mixin {
+
+ public static ImageDebugHeaderEntry GetCodeViewEntry (this ImageDebugHeader header)
+ {
+ return GetEntry (header, ImageDebugType.CodeView);
+ }
+
+ public static ImageDebugHeaderEntry GetDeterministicEntry (this ImageDebugHeader header)
+ {
+ return GetEntry (header, ImageDebugType.Deterministic);
+ }
+
+ public static ImageDebugHeader AddDeterministicEntry (this ImageDebugHeader header)
+ {
+ var entry = new ImageDebugHeaderEntry (new ImageDebugDirectory { Type = ImageDebugType.Deterministic }, Empty.Array);
+ if (header == null)
+ return new ImageDebugHeader (entry);
+
+ var entries = new ImageDebugHeaderEntry [header.Entries.Length + 1];
+ Array.Copy (header.Entries, entries, header.Entries.Length);
+ entries [entries.Length - 1] = entry;
+ return new ImageDebugHeader (entries);
+ }
+
+ public static ImageDebugHeaderEntry GetEmbeddedPortablePdbEntry (this ImageDebugHeader header)
+ {
+ return GetEntry (header, ImageDebugType.EmbeddedPortablePdb);
+ }
+
+ private static ImageDebugHeaderEntry GetEntry (this ImageDebugHeader header, ImageDebugType type)
+ {
+ if (!header.HasEntries)
+ return null;
+
+ for (var i = 0; i < header.Entries.Length; i++) {
+ var entry = header.Entries [i];
+ if (entry.Directory.Type == type)
+ return entry;
+ }
+
+ return null;
+ }
+
+ public static string GetPdbFileName (string assemblyFileName)
+ {
+ return Path.ChangeExtension (assemblyFileName, ".pdb");
+ }
+
+ public static string GetMdbFileName (string assemblyFileName)
+ {
+ return assemblyFileName + ".mdb";
+ }
+
+ public static bool IsPortablePdb (string fileName)
+ {
+ using (var file = new FileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
+ return IsPortablePdb (file);
+ }
+
+ public static bool IsPortablePdb (Stream stream)
+ {
+ const uint ppdb_signature = 0x424a5342;
+
+ if (stream.Length < 4) return false;
+ var position = stream.Position;
+ try {
+ var reader = new BinaryReader (stream);
+ return reader.ReadUInt32 () == ppdb_signature;
+ } finally {
+ stream.Position = position;
+ }
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Cil/VariableDefinition.cs b/Mono.Cecil.20/Mono.Cecil.Cil/VariableDefinition.cs
new file mode 100644
index 00000000..bd132846
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/VariableDefinition.cs
@@ -0,0 +1,29 @@
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
+//
+// Licensed under the MIT/X11 license.
+//
+
+namespace Mono.Cecil.Cil {
+
+ public sealed class VariableDefinition : VariableReference {
+
+ public bool IsPinned {
+ get { return variable_type.IsPinned; }
+ }
+
+ public VariableDefinition (TypeReference variableType)
+ : base (variableType)
+ {
+ }
+
+ public override VariableDefinition Resolve ()
+ {
+ return this;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Cil/VariableReference.cs b/Mono.Cecil.20/Mono.Cecil.Cil/VariableReference.cs
new file mode 100644
index 00000000..bc16bda0
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Cil/VariableReference.cs
@@ -0,0 +1,49 @@
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
+//
+// Licensed under the MIT/X11 license.
+//
+
+namespace Mono.Cecil.Cil {
+
+ public abstract class VariableReference {
+
+ internal int index = -1;
+ protected TypeReference variable_type;
+
+ public TypeReference VariableType {
+ get { return variable_type; }
+ set { variable_type = value; }
+ }
+
+ public int Index {
+ get { return index; }
+ }
+
+ //兼容ILRT代码,不会被使用
+ public string Name{
+ get{
+ return null;
+ }
+ }
+
+ internal VariableReference (TypeReference variable_type)
+ {
+ this.variable_type = variable_type;
+ }
+
+ public abstract VariableDefinition Resolve ();
+
+ public override string ToString ()
+ {
+ if (index >= 0)
+ return "V_" + index;
+
+ return string.Empty;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/BlobHeap.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/BlobHeap.cs
new file mode 100644
index 00000000..574a130c
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/BlobHeap.cs
@@ -0,0 +1,54 @@
+//
+// 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;
+
+namespace Mono.Cecil.Metadata {
+
+ sealed class BlobHeap : Heap {
+
+ public BlobHeap (byte [] data)
+ : base (data)
+ {
+ }
+
+ public byte [] Read (uint index)
+ {
+ if (index == 0 || index > this.data.Length - 1)
+ return Empty.Array;
+
+ int position = (int) index;
+ int length = (int) data.ReadCompressedUInt32 (ref position);
+
+ if (length > data.Length - position)
+ return Empty.Array;
+
+ var buffer = new byte [length];
+
+ Buffer.BlockCopy (data, position, buffer, 0, length);
+
+ return buffer;
+ }
+
+ public void GetView (uint signature, out byte [] buffer, out int index, out int length)
+ {
+ if (signature == 0 || signature > data.Length - 1) {
+ buffer = null;
+ index = length = 0;
+ return;
+ }
+
+ buffer = data;
+
+ index = (int) signature;
+ length = (int) buffer.ReadCompressedUInt32 (ref index);
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/Buffers.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/Buffers.cs
new file mode 100644
index 00000000..d87cb2a2
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/Buffers.cs
@@ -0,0 +1,505 @@
+//
+// 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 Mono.Cecil.PE;
+
+using RVA = System.UInt32;
+
+#if !READ_ONLY
+
+namespace 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 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 (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 (Table.FieldRVA);
+ if (table.length == 0)
+ return;
+
+ var field_idx_size = GetTable (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 guids = new Dictionary ();
+
+ 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 strings = new Dictionary (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> SortStrings (Dictionary strings)
+ {
+ var sorted = new List> (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> {
+
+ public int Compare(KeyValuePair xPair, KeyValuePair 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 blobs = new Dictionary (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)
+ {
+ }
+ }
+}
+
+#endif
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/CodedIndex.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/CodedIndex.cs
new file mode 100644
index 00000000..2026a8a7
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/CodedIndex.cs
@@ -0,0 +1,29 @@
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
+//
+// Licensed under the MIT/X11 license.
+//
+
+namespace Mono.Cecil.Metadata {
+
+ enum CodedIndex {
+ TypeDefOrRef,
+ HasConstant,
+ HasCustomAttribute,
+ HasFieldMarshal,
+ HasDeclSecurity,
+ MemberRefParent,
+ HasSemantics,
+ MethodDefOrRef,
+ MemberForwarded,
+ Implementation,
+ CustomAttributeType,
+ ResolutionScope,
+ TypeOrMethodDef,
+ HasCustomDebugInformation,
+ }
+}
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/ElementType.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/ElementType.cs
similarity index 57%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/ElementType.cs
rename to Mono.Cecil.20/Mono.Cecil.Metadata/ElementType.cs
index 72fc1cca..2190160a 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/ElementType.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/ElementType.cs
@@ -1,29 +1,11 @@
//
-// ElementType.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
namespace Mono.Cecil.Metadata {
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/GuidHeap.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/GuidHeap.cs
new file mode 100644
index 00000000..76ec9d1d
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/GuidHeap.cs
@@ -0,0 +1,36 @@
+//
+// 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;
+
+namespace Mono.Cecil.Metadata {
+
+ sealed class GuidHeap : Heap {
+
+ public GuidHeap (byte [] data)
+ : base (data)
+ {
+ }
+
+ public Guid Read (uint index)
+ {
+ const int guid_size = 16;
+
+ if (index == 0 || ((index - 1) + guid_size) > data.Length)
+ return new Guid ();
+
+ var buffer = new byte [guid_size];
+
+ Buffer.BlockCopy (this.data, (int) ((index - 1) * guid_size), buffer, 0, guid_size);
+
+ return new Guid (buffer);
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/Heap.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/Heap.cs
new file mode 100644
index 00000000..6874d796
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/Heap.cs
@@ -0,0 +1,24 @@
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
+//
+// Licensed under the MIT/X11 license.
+//
+
+namespace Mono.Cecil.Metadata {
+
+ abstract class Heap {
+
+ public int IndexSize;
+
+ readonly internal byte [] data;
+
+ protected Heap (byte [] data)
+ {
+ this.data = data;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/MetadataToken.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/MetadataToken.cs
similarity index 54%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/MetadataToken.cs
rename to Mono.Cecil.20/Mono.Cecil.Metadata/MetadataToken.cs
index bda56b0f..a8b712e7 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/MetadataToken.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/MetadataToken.cs
@@ -1,34 +1,18 @@
//
-// MetadataToken.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
+using System;
+
namespace Mono.Cecil {
- public struct MetadataToken {
+ public struct MetadataToken : IEquatable {
readonly uint token;
@@ -77,6 +61,11 @@ public override int GetHashCode ()
return (int) token;
}
+ public bool Equals (MetadataToken other)
+ {
+ return other.token == token;
+ }
+
public override bool Equals (object obj)
{
if (obj is MetadataToken) {
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/PdbHeap.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/PdbHeap.cs
new file mode 100644
index 00000000..39e275ad
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/PdbHeap.cs
@@ -0,0 +1,34 @@
+//
+// 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 Mono.Cecil.PE;
+
+using RID = System.UInt32;
+
+namespace Mono.Cecil.Metadata {
+
+ sealed class PdbHeap : Heap {
+
+ public byte [] Id;
+ public RID EntryPoint;
+ public long TypeSystemTables;
+ public uint [] TypeSystemTableRows;
+
+ public PdbHeap (byte [] data)
+ : base (data)
+ {
+ }
+
+ public bool HasTable (Table table)
+ {
+ return (TypeSystemTables & (1L << (int) table)) != 0;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/Row.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/Row.cs
similarity index 65%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/Row.cs
rename to Mono.Cecil.20/Mono.Cecil.Metadata/Row.cs
index 9975b7ba..0c05ebad 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/Row.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/Row.cs
@@ -1,36 +1,18 @@
//
-// Row.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
using System.Collections.Generic;
namespace Mono.Cecil.Metadata {
- class Row {
+ struct Row {
internal T1 Col1;
internal T2 Col2;
@@ -41,8 +23,7 @@ public Row (T1 col1, T2 col2)
}
}
- class Row
- {
+ struct Row {
internal T1 Col1;
internal T2 Col2;
internal T3 Col3;
@@ -55,8 +36,7 @@ public Row (T1 col1, T2 col2, T3 col3)
}
}
- class Row
- {
+ struct Row {
internal T1 Col1;
internal T2 Col2;
internal T3 Col3;
@@ -71,8 +51,7 @@ public Row (T1 col1, T2 col2, T3 col3, T4 col4)
}
}
- class Row
- {
+ struct Row {
internal T1 Col1;
internal T2 Col2;
internal T3 Col3;
@@ -89,8 +68,7 @@ public Row (T1 col1, T2 col2, T3 col3, T4 col4, T5 col5)
}
}
- class Row
- {
+ struct Row {
internal T1 Col1;
internal T2 Col2;
internal T3 Col3;
@@ -109,8 +87,7 @@ public Row (T1 col1, T2 col2, T3 col3, T4 col4, T5 col5, T6 col6)
}
}
- class Row
- {
+ struct Row {
internal T1 Col1;
internal T2 Col2;
internal T3 Col3;
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/StringHeap.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/StringHeap.cs
new file mode 100644
index 00000000..4bde70e2
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/StringHeap.cs
@@ -0,0 +1,60 @@
+//
+// 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;
+
+namespace Mono.Cecil.Metadata {
+
+ class StringHeap : Heap {
+
+ readonly Dictionary strings = new Dictionary ();
+
+ public StringHeap (byte [] data)
+ : base (data)
+ {
+ }
+
+ public string Read (uint index)
+ {
+ if (index == 0)
+ return string.Empty;
+
+ string @string;
+ if (strings.TryGetValue (index, out @string))
+ return @string;
+
+ if (index > data.Length - 1)
+ return string.Empty;
+
+ @string = ReadStringAt (index);
+ if (@string.Length != 0)
+ strings.Add (index, @string);
+
+ return @string;
+ }
+
+ protected virtual string ReadStringAt (uint index)
+ {
+ int length = 0;
+ int start = (int) index;
+
+ for (int i = start; ; i++) {
+ if (data [i] == 0)
+ break;
+
+ length++;
+ }
+
+ return Encoding.UTF8.GetString (data, start, length);
+ }
+ }
+}
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/TableHeap.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/TableHeap.cs
similarity index 54%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/TableHeap.cs
rename to Mono.Cecil.20/Mono.Cecil.Metadata/TableHeap.cs
index 9bc0edd3..dee655a3 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil.Metadata/TableHeap.cs
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/TableHeap.cs
@@ -1,29 +1,11 @@
//
-// TableHeap.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
using System;
@@ -77,12 +59,25 @@ enum Table : byte {
GenericParam = 0x2a,
MethodSpec = 0x2b,
GenericParamConstraint = 0x2c,
+
+ Document = 0x30,
+ MethodDebugInformation = 0x31,
+ LocalScope = 0x32,
+ LocalVariable = 0x33,
+ LocalConstant = 0x34,
+ ImportScope = 0x35,
+ StateMachineMethod = 0x36,
+ CustomDebugInformation = 0x37,
}
struct TableInformation {
public uint Offset;
public uint Length;
public uint RowSize;
+
+ public bool IsLarge {
+ get { return Length > ushort.MaxValue; }
+ }
}
sealed class TableHeap : Heap {
@@ -90,16 +85,14 @@ sealed class TableHeap : Heap {
public long Valid;
public long Sorted;
- public const int TableCount = 45;
-
- public readonly TableInformation [] Tables = new TableInformation [TableCount];
+ public readonly TableInformation [] Tables = new TableInformation [Mixin.TableCount];
public TableInformation this [Table table] {
get { return Tables [(int) table]; }
}
- public TableHeap (Section section, uint start, uint size)
- : base (section, start, size)
+ public TableHeap (byte [] data)
+ : base (data)
{
}
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/TokenType.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/TokenType.cs
new file mode 100644
index 00000000..547f6c64
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/TokenType.cs
@@ -0,0 +1,49 @@
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
+//
+// Licensed under the MIT/X11 license.
+//
+
+namespace Mono.Cecil {
+
+ public enum TokenType : uint {
+ Module = 0x00000000,
+ TypeRef = 0x01000000,
+ TypeDef = 0x02000000,
+ Field = 0x04000000,
+ Method = 0x06000000,
+ Param = 0x08000000,
+ InterfaceImpl = 0x09000000,
+ MemberRef = 0x0a000000,
+ CustomAttribute = 0x0c000000,
+ Permission = 0x0e000000,
+ Signature = 0x11000000,
+ Event = 0x14000000,
+ Property = 0x17000000,
+ ModuleRef = 0x1a000000,
+ TypeSpec = 0x1b000000,
+ Assembly = 0x20000000,
+ AssemblyRef = 0x23000000,
+ File = 0x26000000,
+ ExportedType = 0x27000000,
+ ManifestResource = 0x28000000,
+ GenericParam = 0x2a000000,
+ MethodSpec = 0x2b000000,
+ GenericParamConstraint = 0x2c000000,
+
+ Document = 0x30000000,
+ MethodDebugInformation = 0x31000000,
+ LocalScope = 0x32000000,
+ LocalVariable = 0x33000000,
+ LocalConstant = 0x34000000,
+ ImportScope = 0x35000000,
+ StateMachineMethod = 0x36000000,
+ CustomDebugInformation = 0x37000000,
+
+ String = 0x70000000,
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/UserStringHeap.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/UserStringHeap.cs
new file mode 100644
index 00000000..7b1b42ff
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/UserStringHeap.cs
@@ -0,0 +1,36 @@
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
+//
+// Licensed under the MIT/X11 license.
+//
+
+namespace Mono.Cecil.Metadata {
+
+ sealed class UserStringHeap : StringHeap {
+
+ public UserStringHeap (byte [] data)
+ : base (data)
+ {
+ }
+
+ protected override string ReadStringAt (uint index)
+ {
+ int start = (int) index;
+
+ uint length = (uint) (data.ReadCompressedUInt32 (ref start) & ~1);
+ if (length < 1)
+ return string.Empty;
+
+ var chars = new char [length / 2];
+
+ for (int i = start, j = 0; i < start + length; i += 2)
+ chars [j++] = (char) (data [i] | (data [i + 1] << 8));
+
+ return new string (chars);
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.Metadata/Utilities.cs b/Mono.Cecil.20/Mono.Cecil.Metadata/Utilities.cs
new file mode 100644
index 00000000..3a4330da
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.Metadata/Utilities.cs
@@ -0,0 +1,652 @@
+//
+// 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 Mono.Cecil.Metadata;
+
+namespace Mono.Cecil {
+
+ static partial class Mixin {
+
+ public const int TableCount = 58;
+ public const int CodedIndexCount = 14;
+
+ public static uint ReadCompressedUInt32 (this byte [] data, ref int position)
+ {
+ uint integer;
+ if ((data [position] & 0x80) == 0) {
+ integer = data [position];
+ position++;
+ } else if ((data [position] & 0x40) == 0) {
+ integer = (uint) (data [position] & ~0x80) << 8;
+ integer |= data [position + 1];
+ position += 2;
+ } else {
+ integer = (uint) (data [position] & ~0xc0) << 24;
+ integer |= (uint) data [position + 1] << 16;
+ integer |= (uint) data [position + 2] << 8;
+ integer |= (uint) data [position + 3];
+ position += 4;
+ }
+ return integer;
+ }
+
+ public static MetadataToken GetMetadataToken (this CodedIndex self, uint data)
+ {
+ uint rid;
+ TokenType token_type;
+ switch (self) {
+ case CodedIndex.TypeDefOrRef:
+ rid = data >> 2;
+ switch (data & 3) {
+ case 0:
+ token_type = TokenType.TypeDef; goto ret;
+ case 1:
+ token_type = TokenType.TypeRef; goto ret;
+ case 2:
+ token_type = TokenType.TypeSpec; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasConstant:
+ rid = data >> 2;
+ switch (data & 3) {
+ case 0:
+ token_type = TokenType.Field; goto ret;
+ case 1:
+ token_type = TokenType.Param; goto ret;
+ case 2:
+ token_type = TokenType.Property; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasCustomAttribute:
+ rid = data >> 5;
+ switch (data & 31) {
+ case 0:
+ token_type = TokenType.Method; goto ret;
+ case 1:
+ token_type = TokenType.Field; goto ret;
+ case 2:
+ token_type = TokenType.TypeRef; goto ret;
+ case 3:
+ token_type = TokenType.TypeDef; goto ret;
+ case 4:
+ token_type = TokenType.Param; goto ret;
+ case 5:
+ token_type = TokenType.InterfaceImpl; goto ret;
+ case 6:
+ token_type = TokenType.MemberRef; goto ret;
+ case 7:
+ token_type = TokenType.Module; goto ret;
+ case 8:
+ token_type = TokenType.Permission; goto ret;
+ case 9:
+ token_type = TokenType.Property; goto ret;
+ case 10:
+ token_type = TokenType.Event; goto ret;
+ case 11:
+ token_type = TokenType.Signature; goto ret;
+ case 12:
+ token_type = TokenType.ModuleRef; goto ret;
+ case 13:
+ token_type = TokenType.TypeSpec; goto ret;
+ case 14:
+ token_type = TokenType.Assembly; goto ret;
+ case 15:
+ token_type = TokenType.AssemblyRef; goto ret;
+ case 16:
+ token_type = TokenType.File; goto ret;
+ case 17:
+ token_type = TokenType.ExportedType; goto ret;
+ case 18:
+ token_type = TokenType.ManifestResource; goto ret;
+ case 19:
+ token_type = TokenType.GenericParam; goto ret;
+ case 20:
+ token_type = TokenType.GenericParamConstraint; goto ret;
+ case 21:
+ token_type = TokenType.MethodSpec; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasFieldMarshal:
+ rid = data >> 1;
+ switch (data & 1) {
+ case 0:
+ token_type = TokenType.Field; goto ret;
+ case 1:
+ token_type = TokenType.Param; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasDeclSecurity:
+ rid = data >> 2;
+ switch (data & 3) {
+ case 0:
+ token_type = TokenType.TypeDef; goto ret;
+ case 1:
+ token_type = TokenType.Method; goto ret;
+ case 2:
+ token_type = TokenType.Assembly; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.MemberRefParent:
+ rid = data >> 3;
+ switch (data & 7) {
+ case 0:
+ token_type = TokenType.TypeDef; goto ret;
+ case 1:
+ token_type = TokenType.TypeRef; goto ret;
+ case 2:
+ token_type = TokenType.ModuleRef; goto ret;
+ case 3:
+ token_type = TokenType.Method; goto ret;
+ case 4:
+ token_type = TokenType.TypeSpec; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasSemantics:
+ rid = data >> 1;
+ switch (data & 1) {
+ case 0:
+ token_type = TokenType.Event; goto ret;
+ case 1:
+ token_type = TokenType.Property; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.MethodDefOrRef:
+ rid = data >> 1;
+ switch (data & 1) {
+ case 0:
+ token_type = TokenType.Method; goto ret;
+ case 1:
+ token_type = TokenType.MemberRef; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.MemberForwarded:
+ rid = data >> 1;
+ switch (data & 1) {
+ case 0:
+ token_type = TokenType.Field; goto ret;
+ case 1:
+ token_type = TokenType.Method; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.Implementation:
+ rid = data >> 2;
+ switch (data & 3) {
+ case 0:
+ token_type = TokenType.File; goto ret;
+ case 1:
+ token_type = TokenType.AssemblyRef; goto ret;
+ case 2:
+ token_type = TokenType.ExportedType; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.CustomAttributeType:
+ rid = data >> 3;
+ switch (data & 7) {
+ case 2:
+ token_type = TokenType.Method; goto ret;
+ case 3:
+ token_type = TokenType.MemberRef; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.ResolutionScope:
+ rid = data >> 2;
+ switch (data & 3) {
+ case 0:
+ token_type = TokenType.Module; goto ret;
+ case 1:
+ token_type = TokenType.ModuleRef; goto ret;
+ case 2:
+ token_type = TokenType.AssemblyRef; goto ret;
+ case 3:
+ token_type = TokenType.TypeRef; goto ret;
+ default:
+ goto exit;
+ }
+ case CodedIndex.TypeOrMethodDef:
+ rid = data >> 1;
+ switch (data & 1) {
+ case 0:
+ token_type = TokenType.TypeDef; goto ret;
+ case 1:
+ token_type = TokenType.Method; goto ret;
+ default: goto exit;
+ }
+ case CodedIndex.HasCustomDebugInformation:
+ rid = data >> 5;
+ switch (data & 31) {
+ case 0:
+ token_type = TokenType.Method; goto ret;
+ case 1:
+ token_type = TokenType.Field; goto ret;
+ case 2:
+ token_type = TokenType.TypeRef; goto ret;
+ case 3:
+ token_type = TokenType.TypeDef; goto ret;
+ case 4:
+ token_type = TokenType.Param; goto ret;
+ case 5:
+ token_type = TokenType.InterfaceImpl; goto ret;
+ case 6:
+ token_type = TokenType.MemberRef; goto ret;
+ case 7:
+ token_type = TokenType.Module; goto ret;
+ case 8:
+ token_type = TokenType.Permission; goto ret;
+ case 9:
+ token_type = TokenType.Property; goto ret;
+ case 10:
+ token_type = TokenType.Event; goto ret;
+ case 11:
+ token_type = TokenType.Signature; goto ret;
+ case 12:
+ token_type = TokenType.ModuleRef; goto ret;
+ case 13:
+ token_type = TokenType.TypeSpec; goto ret;
+ case 14:
+ token_type = TokenType.Assembly; goto ret;
+ case 15:
+ token_type = TokenType.AssemblyRef; goto ret;
+ case 16:
+ token_type = TokenType.File; goto ret;
+ case 17:
+ token_type = TokenType.ExportedType; goto ret;
+ case 18:
+ token_type = TokenType.ManifestResource; goto ret;
+ case 19:
+ token_type = TokenType.GenericParam; goto ret;
+ case 20:
+ token_type = TokenType.GenericParamConstraint; goto ret;
+ case 21:
+ token_type = TokenType.MethodSpec; goto ret;
+ case 22:
+ token_type = TokenType.Document; goto ret;
+ case 23:
+ token_type = TokenType.LocalScope; goto ret;
+ case 24:
+ token_type = TokenType.LocalVariable; goto ret;
+ case 25:
+ token_type = TokenType.LocalConstant; goto ret;
+ case 26:
+ token_type = TokenType.ImportScope; goto ret;
+ default:
+ goto exit;
+ }
+ default:
+ goto exit;
+ }
+ ret:
+ return new MetadataToken (token_type, rid);
+ exit:
+ return MetadataToken.Zero;
+ }
+
+#if !READ_ONLY
+ public static uint CompressMetadataToken (this CodedIndex self, MetadataToken token)
+ {
+ uint ret = 0;
+ if (token.RID == 0)
+ return ret;
+ switch (self) {
+ case CodedIndex.TypeDefOrRef:
+ ret = token.RID << 2;
+ switch (token.TokenType) {
+ case TokenType.TypeDef:
+ return ret | 0;
+ case TokenType.TypeRef:
+ return ret | 1;
+ case TokenType.TypeSpec:
+ return ret | 2;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasConstant:
+ ret = token.RID << 2;
+ switch (token.TokenType) {
+ case TokenType.Field:
+ return ret | 0;
+ case TokenType.Param:
+ return ret | 1;
+ case TokenType.Property:
+ return ret | 2;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasCustomAttribute:
+ ret = token.RID << 5;
+ switch (token.TokenType) {
+ case TokenType.Method:
+ return ret | 0;
+ case TokenType.Field:
+ return ret | 1;
+ case TokenType.TypeRef:
+ return ret | 2;
+ case TokenType.TypeDef:
+ return ret | 3;
+ case TokenType.Param:
+ return ret | 4;
+ case TokenType.InterfaceImpl:
+ return ret | 5;
+ case TokenType.MemberRef:
+ return ret | 6;
+ case TokenType.Module:
+ return ret | 7;
+ case TokenType.Permission:
+ return ret | 8;
+ case TokenType.Property:
+ return ret | 9;
+ case TokenType.Event:
+ return ret | 10;
+ case TokenType.Signature:
+ return ret | 11;
+ case TokenType.ModuleRef:
+ return ret | 12;
+ case TokenType.TypeSpec:
+ return ret | 13;
+ case TokenType.Assembly:
+ return ret | 14;
+ case TokenType.AssemblyRef:
+ return ret | 15;
+ case TokenType.File:
+ return ret | 16;
+ case TokenType.ExportedType:
+ return ret | 17;
+ case TokenType.ManifestResource:
+ return ret | 18;
+ case TokenType.GenericParam:
+ return ret | 19;
+ case TokenType.GenericParamConstraint:
+ return ret | 20;
+ case TokenType.MethodSpec:
+ return ret | 21;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasFieldMarshal:
+ ret = token.RID << 1;
+ switch (token.TokenType) {
+ case TokenType.Field:
+ return ret | 0;
+ case TokenType.Param:
+ return ret | 1;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasDeclSecurity:
+ ret = token.RID << 2;
+ switch (token.TokenType) {
+ case TokenType.TypeDef:
+ return ret | 0;
+ case TokenType.Method:
+ return ret | 1;
+ case TokenType.Assembly:
+ return ret | 2;
+ default:
+ goto exit;
+ }
+ case CodedIndex.MemberRefParent:
+ ret = token.RID << 3;
+ switch (token.TokenType) {
+ case TokenType.TypeDef:
+ return ret | 0;
+ case TokenType.TypeRef:
+ return ret | 1;
+ case TokenType.ModuleRef:
+ return ret | 2;
+ case TokenType.Method:
+ return ret | 3;
+ case TokenType.TypeSpec:
+ return ret | 4;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasSemantics:
+ ret = token.RID << 1;
+ switch (token.TokenType) {
+ case TokenType.Event:
+ return ret | 0;
+ case TokenType.Property:
+ return ret | 1;
+ default:
+ goto exit;
+ }
+ case CodedIndex.MethodDefOrRef:
+ ret = token.RID << 1;
+ switch (token.TokenType) {
+ case TokenType.Method:
+ return ret | 0;
+ case TokenType.MemberRef:
+ return ret | 1;
+ default:
+ goto exit;
+ }
+ case CodedIndex.MemberForwarded:
+ ret = token.RID << 1;
+ switch (token.TokenType) {
+ case TokenType.Field:
+ return ret | 0;
+ case TokenType.Method:
+ return ret | 1;
+ default:
+ goto exit;
+ }
+ case CodedIndex.Implementation:
+ ret = token.RID << 2;
+ switch (token.TokenType) {
+ case TokenType.File:
+ return ret | 0;
+ case TokenType.AssemblyRef:
+ return ret | 1;
+ case TokenType.ExportedType:
+ return ret | 2;
+ default:
+ goto exit;
+ }
+ case CodedIndex.CustomAttributeType:
+ ret = token.RID << 3;
+ switch (token.TokenType) {
+ case TokenType.Method:
+ return ret | 2;
+ case TokenType.MemberRef:
+ return ret | 3;
+ default:
+ goto exit;
+ }
+ case CodedIndex.ResolutionScope:
+ ret = token.RID << 2;
+ switch (token.TokenType) {
+ case TokenType.Module:
+ return ret | 0;
+ case TokenType.ModuleRef:
+ return ret | 1;
+ case TokenType.AssemblyRef:
+ return ret | 2;
+ case TokenType.TypeRef:
+ return ret | 3;
+ default:
+ goto exit;
+ }
+ case CodedIndex.TypeOrMethodDef:
+ ret = token.RID << 1;
+ switch (token.TokenType) {
+ case TokenType.TypeDef:
+ return ret | 0;
+ case TokenType.Method:
+ return ret | 1;
+ default:
+ goto exit;
+ }
+ case CodedIndex.HasCustomDebugInformation:
+ ret = token.RID << 5;
+ switch (token.TokenType) {
+ case TokenType.Method:
+ return ret | 0;
+ case TokenType.Field:
+ return ret | 1;
+ case TokenType.TypeRef:
+ return ret | 2;
+ case TokenType.TypeDef:
+ return ret | 3;
+ case TokenType.Param:
+ return ret | 4;
+ case TokenType.InterfaceImpl:
+ return ret | 5;
+ case TokenType.MemberRef:
+ return ret | 6;
+ case TokenType.Module:
+ return ret | 7;
+ case TokenType.Permission:
+ return ret | 8;
+ case TokenType.Property:
+ return ret | 9;
+ case TokenType.Event:
+ return ret | 10;
+ case TokenType.Signature:
+ return ret | 11;
+ case TokenType.ModuleRef:
+ return ret | 12;
+ case TokenType.TypeSpec:
+ return ret | 13;
+ case TokenType.Assembly:
+ return ret | 14;
+ case TokenType.AssemblyRef:
+ return ret | 15;
+ case TokenType.File:
+ return ret | 16;
+ case TokenType.ExportedType:
+ return ret | 17;
+ case TokenType.ManifestResource:
+ return ret | 18;
+ case TokenType.GenericParam:
+ return ret | 19;
+ case TokenType.GenericParamConstraint:
+ return ret | 20;
+ case TokenType.MethodSpec:
+ return ret | 21;
+ case TokenType.Document:
+ return ret | 22;
+ case TokenType.LocalScope:
+ return ret | 23;
+ case TokenType.LocalVariable:
+ return ret | 24;
+ case TokenType.LocalConstant:
+ return ret | 25;
+ case TokenType.ImportScope:
+ return ret | 26;
+ default:
+ goto exit;
+ }
+ default:
+ goto exit;
+ }
+ exit:
+ throw new ArgumentException ();
+ }
+#endif
+
+ public static int GetSize (this CodedIndex self, Func counter)
+ {
+ int bits;
+ Table [] tables;
+
+ switch (self) {
+ case CodedIndex.TypeDefOrRef:
+ bits = 2;
+ tables = new [] { Table.TypeDef, Table.TypeRef, Table.TypeSpec };
+ break;
+ case CodedIndex.HasConstant:
+ bits = 2;
+ tables = new [] { Table.Field, Table.Param, Table.Property };
+ break;
+ case CodedIndex.HasCustomAttribute:
+ bits = 5;
+ tables = new [] {
+ Table.Method, Table.Field, Table.TypeRef, Table.TypeDef, Table.Param, Table.InterfaceImpl, Table.MemberRef,
+ Table.Module, Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig, Table.ModuleRef,
+ Table.TypeSpec, Table.Assembly, Table.AssemblyRef, Table.File, Table.ExportedType,
+ Table.ManifestResource, Table.GenericParam, Table.GenericParamConstraint, Table.MethodSpec,
+ };
+ break;
+ case CodedIndex.HasFieldMarshal:
+ bits = 1;
+ tables = new [] { Table.Field, Table.Param };
+ break;
+ case CodedIndex.HasDeclSecurity:
+ bits = 2;
+ tables = new [] { Table.TypeDef, Table.Method, Table.Assembly };
+ break;
+ case CodedIndex.MemberRefParent:
+ bits = 3;
+ tables = new [] { Table.TypeDef, Table.TypeRef, Table.ModuleRef, Table.Method, Table.TypeSpec };
+ break;
+ case CodedIndex.HasSemantics:
+ bits = 1;
+ tables = new [] { Table.Event, Table.Property };
+ break;
+ case CodedIndex.MethodDefOrRef:
+ bits = 1;
+ tables = new [] { Table.Method, Table.MemberRef };
+ break;
+ case CodedIndex.MemberForwarded:
+ bits = 1;
+ tables = new [] { Table.Field, Table.Method };
+ break;
+ case CodedIndex.Implementation:
+ bits = 2;
+ tables = new [] { Table.File, Table.AssemblyRef, Table.ExportedType };
+ break;
+ case CodedIndex.CustomAttributeType:
+ bits = 3;
+ tables = new [] { Table.Method, Table.MemberRef };
+ break;
+ case CodedIndex.ResolutionScope:
+ bits = 2;
+ tables = new [] { Table.Module, Table.ModuleRef, Table.AssemblyRef, Table.TypeRef };
+ break;
+ case CodedIndex.TypeOrMethodDef:
+ bits = 1;
+ tables = new [] { Table.TypeDef, Table.Method };
+ break;
+ case CodedIndex.HasCustomDebugInformation:
+ bits = 5;
+ tables = new[] {
+ Table.Method, Table.Field, Table.TypeRef, Table.TypeDef, Table.Param, Table.InterfaceImpl, Table.MemberRef,
+ Table.Module, Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig, Table.ModuleRef,
+ Table.TypeSpec, Table.Assembly, Table.AssemblyRef, Table.File, Table.ExportedType,
+ Table.ManifestResource, Table.GenericParam, Table.GenericParamConstraint, Table.MethodSpec,
+ Table.Document, Table.LocalScope, Table.LocalVariable, Table.LocalConstant, Table.ImportScope,
+ };
+ break;
+ default:
+ throw new ArgumentException ();
+ }
+
+ int max = 0;
+
+ for (int i = 0; i < tables.Length; i++) {
+ max = System.Math.Max (counter (tables [i]), max);
+ }
+
+ return max < (1 << (16 - bits)) ? 2 : 4;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/BinaryStreamReader.cs b/Mono.Cecil.20/Mono.Cecil.PE/BinaryStreamReader.cs
new file mode 100644
index 00000000..812adbc5
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/BinaryStreamReader.cs
@@ -0,0 +1,54 @@
+//
+// 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.IO;
+
+namespace Mono.Cecil.PE {
+
+ class BinaryStreamReader : BinaryReader {
+
+ public int Position {
+ get { return (int) BaseStream.Position; }
+ set { BaseStream.Position = value; }
+ }
+
+ public int Length {
+ get { return (int) BaseStream.Length; }
+ }
+
+ public BinaryStreamReader (Stream stream)
+ : base (stream)
+ {
+ }
+
+ public void Advance (int bytes)
+ {
+ BaseStream.Seek (bytes, SeekOrigin.Current);
+ }
+
+ public void MoveTo (uint position)
+ {
+ BaseStream.Seek (position, SeekOrigin.Begin);
+ }
+
+ public void Align (int align)
+ {
+ align--;
+ var position = Position;
+ Advance (((position + align) & ~align) - position);
+ }
+
+ public DataDirectory ReadDataDirectory ()
+ {
+ return new DataDirectory (ReadUInt32 (), ReadUInt32 ());
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/BinaryStreamWriter.cs b/Mono.Cecil.20/Mono.Cecil.PE/BinaryStreamWriter.cs
new file mode 100644
index 00000000..b741f684
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/BinaryStreamWriter.cs
@@ -0,0 +1,93 @@
+//
+// 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.IO;
+
+#if !READ_ONLY
+
+namespace Mono.Cecil.PE {
+
+ class BinaryStreamWriter : BinaryWriter {
+
+ public int Position {
+ get { return (int) BaseStream.Position; }
+ set { BaseStream.Position = value; }
+ }
+
+ public BinaryStreamWriter (Stream stream)
+ : base (stream)
+ {
+ }
+
+ public void WriteByte (byte value)
+ {
+ Write (value);
+ }
+
+ public void WriteUInt16 (ushort value)
+ {
+ Write (value);
+ }
+
+ public void WriteInt16 (short value)
+ {
+ Write (value);
+ }
+
+ public void WriteUInt32 (uint value)
+ {
+ Write (value);
+ }
+
+ public void WriteInt32 (int value)
+ {
+ Write (value);
+ }
+
+ public void WriteUInt64 (ulong value)
+ {
+ Write (value);
+ }
+
+ public void WriteBytes (byte [] bytes)
+ {
+ Write (bytes);
+ }
+
+ public void WriteDataDirectory (DataDirectory directory)
+ {
+ Write (directory.VirtualAddress);
+ Write (directory.Size);
+ }
+
+ public void WriteBuffer (ByteBuffer buffer)
+ {
+ Write (buffer.buffer, 0, buffer.length);
+ }
+
+ protected void Advance (int bytes)
+ {
+ BaseStream.Seek (bytes, SeekOrigin.Current);
+ }
+
+ public void Align (int align)
+ {
+ align--;
+ var position = Position;
+ var bytes = ((position + align) & ~align) - position;
+
+ for (int i = 0; i < bytes; i++)
+ WriteByte (0);
+ }
+ }
+}
+
+#endif
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/ByteBuffer.cs b/Mono.Cecil.20/Mono.Cecil.PE/ByteBuffer.cs
new file mode 100644
index 00000000..8aee04ba
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/ByteBuffer.cs
@@ -0,0 +1,341 @@
+//
+// 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;
+
+namespace Mono.Cecil.PE {
+
+ class ByteBuffer {
+
+ internal byte [] buffer;
+ internal int length;
+ internal int position;
+
+ public ByteBuffer ()
+ {
+ this.buffer = Empty.Array;
+ }
+
+ public ByteBuffer (int length)
+ {
+ this.buffer = new byte [length];
+ }
+
+ public ByteBuffer (byte [] buffer)
+ {
+ this.buffer = buffer ?? Empty.Array;
+ this.length = this.buffer.Length;
+ }
+
+ public void Advance (int length)
+ {
+ position += length;
+ }
+
+ public byte ReadByte ()
+ {
+ return buffer [position++];
+ }
+
+ public sbyte ReadSByte ()
+ {
+ return (sbyte) ReadByte ();
+ }
+
+ public byte [] ReadBytes (int length)
+ {
+ var bytes = new byte [length];
+ Buffer.BlockCopy (buffer, position, bytes, 0, length);
+ position += length;
+ return bytes;
+ }
+
+ public ushort ReadUInt16 ()
+ {
+ ushort value = (ushort) (buffer [position]
+ | (buffer [position + 1] << 8));
+ position += 2;
+ return value;
+ }
+
+ public short ReadInt16 ()
+ {
+ return (short) ReadUInt16 ();
+ }
+
+ public uint ReadUInt32 ()
+ {
+ uint value = (uint) (buffer [position]
+ | (buffer [position + 1] << 8)
+ | (buffer [position + 2] << 16)
+ | (buffer [position + 3] << 24));
+ position += 4;
+ return value;
+ }
+
+ public int ReadInt32 ()
+ {
+ return (int) ReadUInt32 ();
+ }
+
+ public ulong ReadUInt64 ()
+ {
+ uint low = ReadUInt32 ();
+ uint high = ReadUInt32 ();
+
+ return (((ulong) high) << 32) | low;
+ }
+
+ public long ReadInt64 ()
+ {
+ return (long) ReadUInt64 ();
+ }
+
+ public uint ReadCompressedUInt32 ()
+ {
+ byte first = ReadByte ();
+ if ((first & 0x80) == 0)
+ return first;
+
+ if ((first & 0x40) == 0)
+ return ((uint) (first & ~0x80) << 8)
+ | ReadByte ();
+
+ return ((uint) (first & ~0xc0) << 24)
+ | (uint) ReadByte () << 16
+ | (uint) ReadByte () << 8
+ | ReadByte ();
+ }
+
+ public int ReadCompressedInt32 ()
+ {
+ var b = buffer [position];
+ var u = (int) ReadCompressedUInt32 ();
+ var v = u >> 1;
+ if ((u & 1) == 0)
+ return v;
+
+ switch (b & 0xc0)
+ {
+ case 0:
+ case 0x40:
+ return v - 0x40;
+ case 0x80:
+ return v - 0x2000;
+ default:
+ return v - 0x10000000;
+ }
+ }
+
+ public float ReadSingle ()
+ {
+ if (!BitConverter.IsLittleEndian) {
+ var bytes = ReadBytes (4);
+ Array.Reverse (bytes);
+ return BitConverter.ToSingle (bytes, 0);
+ }
+
+ float value = BitConverter.ToSingle (buffer, position);
+ position += 4;
+ return value;
+ }
+
+ public double ReadDouble ()
+ {
+ if (!BitConverter.IsLittleEndian) {
+ var bytes = ReadBytes (8);
+ Array.Reverse (bytes);
+ return BitConverter.ToDouble (bytes, 0);
+ }
+
+ double value = BitConverter.ToDouble (buffer, position);
+ position += 8;
+ return value;
+ }
+
+#if !READ_ONLY
+
+ public void WriteByte (byte value)
+ {
+ if (position == buffer.Length)
+ Grow (1);
+
+ buffer [position++] = value;
+
+ if (position > length)
+ length = position;
+ }
+
+ public void WriteSByte (sbyte value)
+ {
+ WriteByte ((byte) value);
+ }
+
+ public void WriteUInt16 (ushort value)
+ {
+ if (position + 2 > buffer.Length)
+ Grow (2);
+
+ buffer [position++] = (byte) value;
+ buffer [position++] = (byte) (value >> 8);
+
+ if (position > length)
+ length = position;
+ }
+
+ public void WriteInt16 (short value)
+ {
+ WriteUInt16 ((ushort) value);
+ }
+
+ public void WriteUInt32 (uint value)
+ {
+ if (position + 4 > buffer.Length)
+ Grow (4);
+
+ buffer [position++] = (byte) value;
+ buffer [position++] = (byte) (value >> 8);
+ buffer [position++] = (byte) (value >> 16);
+ buffer [position++] = (byte) (value >> 24);
+
+ if (position > length)
+ length = position;
+ }
+
+ public void WriteInt32 (int value)
+ {
+ WriteUInt32 ((uint) value);
+ }
+
+ public void WriteUInt64 (ulong value)
+ {
+ if (position + 8 > buffer.Length)
+ Grow (8);
+
+ buffer [position++] = (byte) value;
+ buffer [position++] = (byte) (value >> 8);
+ buffer [position++] = (byte) (value >> 16);
+ buffer [position++] = (byte) (value >> 24);
+ buffer [position++] = (byte) (value >> 32);
+ buffer [position++] = (byte) (value >> 40);
+ buffer [position++] = (byte) (value >> 48);
+ buffer [position++] = (byte) (value >> 56);
+
+ if (position > length)
+ length = position;
+ }
+
+ public void WriteInt64 (long value)
+ {
+ WriteUInt64 ((ulong) value);
+ }
+
+ public void WriteCompressedUInt32 (uint value)
+ {
+ if (value < 0x80)
+ WriteByte ((byte) value);
+ else if (value < 0x4000) {
+ WriteByte ((byte) (0x80 | (value >> 8)));
+ WriteByte ((byte) (value & 0xff));
+ } else {
+ WriteByte ((byte) ((value >> 24) | 0xc0));
+ WriteByte ((byte) ((value >> 16) & 0xff));
+ WriteByte ((byte) ((value >> 8) & 0xff));
+ WriteByte ((byte) (value & 0xff));
+ }
+ }
+
+ public void WriteCompressedInt32 (int value)
+ {
+ if (value >= 0) {
+ WriteCompressedUInt32 ((uint) (value << 1));
+ return;
+ }
+
+ if (value > -0x40)
+ value = 0x40 + value;
+ else if (value >= -0x2000)
+ value = 0x2000 + value;
+ else if (value >= -0x20000000)
+ value = 0x20000000 + value;
+
+ WriteCompressedUInt32 ((uint) ((value << 1) | 1));
+ }
+
+ public void WriteBytes (byte [] bytes)
+ {
+ var length = bytes.Length;
+ if (position + length > buffer.Length)
+ Grow (length);
+
+ Buffer.BlockCopy (bytes, 0, buffer, position, length);
+ position += length;
+
+ if (position > this.length)
+ this.length = position;
+ }
+
+ public void WriteBytes (int length)
+ {
+ if (position + length > buffer.Length)
+ Grow (length);
+
+ position += length;
+
+ if (position > this.length)
+ this.length = position;
+ }
+
+ public void WriteBytes (ByteBuffer buffer)
+ {
+ if (position + buffer.length > this.buffer.Length)
+ Grow (buffer.length);
+
+ Buffer.BlockCopy (buffer.buffer, 0, this.buffer, position, buffer.length);
+ position += buffer.length;
+
+ if (position > this.length)
+ this.length = position;
+ }
+
+ public void WriteSingle (float value)
+ {
+ var bytes = BitConverter.GetBytes (value);
+
+ if (!BitConverter.IsLittleEndian)
+ Array.Reverse (bytes);
+
+ WriteBytes (bytes);
+ }
+
+ public void WriteDouble (double value)
+ {
+ var bytes = BitConverter.GetBytes (value);
+
+ if (!BitConverter.IsLittleEndian)
+ Array.Reverse (bytes);
+
+ WriteBytes (bytes);
+ }
+
+ void Grow (int desired)
+ {
+ var current = this.buffer;
+ var current_length = current.Length;
+
+ var buffer = new byte [System.Math.Max (current_length + desired, current_length * 2)];
+ Buffer.BlockCopy (current, 0, buffer, 0, current_length);
+ this.buffer = buffer;
+ }
+
+#endif
+
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/ByteBufferEqualityComparer.cs b/Mono.Cecil.20/Mono.Cecil.PE/ByteBufferEqualityComparer.cs
new file mode 100644
index 00000000..8b7cb238
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/ByteBufferEqualityComparer.cs
@@ -0,0 +1,48 @@
+//
+// 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;
+
+namespace Mono.Cecil.PE {
+
+ sealed class ByteBufferEqualityComparer : IEqualityComparer {
+
+ public bool Equals (ByteBuffer x, ByteBuffer y)
+ {
+ if (x.length != y.length)
+ return false;
+
+ var x_buffer = x.buffer;
+ var y_buffer = y.buffer;
+
+ for (int i = 0; i < x.length; i++)
+ if (x_buffer [i] != y_buffer [i])
+ return false;
+
+ return true;
+ }
+
+ public int GetHashCode (ByteBuffer buffer)
+ {
+ // See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
+ const int fnv_offset_bias = unchecked((int)2166136261);
+ const int fnv_prime = 16777619;
+
+ var hash_code = fnv_offset_bias;
+ var bytes = buffer.buffer;
+
+ for (int i = 0; i < buffer.length; i++)
+ hash_code = unchecked ((hash_code ^ bytes [i]) * fnv_prime);
+
+ return hash_code;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/DataDirectory.cs b/Mono.Cecil.20/Mono.Cecil.PE/DataDirectory.cs
new file mode 100644
index 00000000..4922dd2f
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/DataDirectory.cs
@@ -0,0 +1,32 @@
+//
+// 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 RVA = System.UInt32;
+
+namespace Mono.Cecil.PE {
+
+ struct DataDirectory {
+
+ public readonly RVA VirtualAddress;
+ public readonly uint Size;
+
+ public bool IsZero {
+ get { return VirtualAddress == 0 && Size == 0; }
+ }
+
+ public DataDirectory (RVA rva, uint size)
+ {
+ this.VirtualAddress = rva;
+ this.Size = size;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/Image.cs b/Mono.Cecil.20/Mono.Cecil.PE/Image.cs
new file mode 100644
index 00000000..8160f94b
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/Image.cs
@@ -0,0 +1,166 @@
+//
+// 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.IO;
+
+using Mono.Cecil.Cil;
+using Mono.Cecil.Metadata;
+using Mono.Collections.Generic;
+
+using RVA = System.UInt32;
+
+namespace Mono.Cecil.PE {
+
+ sealed class Image : IDisposable {
+
+ public Disposable Stream;
+ public string FileName;
+
+ public ModuleKind Kind;
+ public string RuntimeVersion;
+ public TargetArchitecture Architecture;
+ public ModuleCharacteristics Characteristics;
+
+ public ImageDebugHeader DebugHeader;
+
+ public Section [] Sections;
+
+ public Section MetadataSection;
+
+ public uint EntryPointToken;
+ public uint Timestamp;
+ public ModuleAttributes Attributes;
+
+ public DataDirectory Debug;
+ public DataDirectory Resources;
+ public DataDirectory StrongName;
+
+ public StringHeap StringHeap;
+ public BlobHeap BlobHeap;
+ public UserStringHeap UserStringHeap;
+ public GuidHeap GuidHeap;
+ public TableHeap TableHeap;
+ public PdbHeap PdbHeap;
+
+ readonly int [] coded_index_sizes = new int [14];
+
+ readonly Func counter;
+
+ public Image ()
+ {
+ counter = GetTableLength;
+ }
+
+ public bool HasTable (Table table)
+ {
+ return GetTableLength (table) > 0;
+ }
+
+ public int GetTableLength (Table table)
+ {
+ return (int) TableHeap [table].Length;
+ }
+
+ public int GetTableIndexSize (Table table)
+ {
+ return GetTableLength (table) < 65536 ? 2 : 4;
+ }
+
+ public 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 uint ResolveVirtualAddress (RVA rva)
+ {
+ var section = GetSectionAtVirtualAddress (rva);
+ if (section == null)
+ throw new ArgumentOutOfRangeException ();
+
+ return ResolveVirtualAddressInSection (rva, section);
+ }
+
+ public uint ResolveVirtualAddressInSection (RVA rva, Section section)
+ {
+ return rva + section.PointerToRawData - section.VirtualAddress;
+ }
+
+ public Section GetSection (string name)
+ {
+ var sections = this.Sections;
+ for (int i = 0; i < sections.Length; i++) {
+ var section = sections [i];
+ if (section.Name == name)
+ return section;
+ }
+
+ return null;
+ }
+
+ public Section GetSectionAtVirtualAddress (RVA rva)
+ {
+ var sections = this.Sections;
+ for (int i = 0; i < sections.Length; i++) {
+ var section = sections [i];
+ if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.SizeOfRawData)
+ return section;
+ }
+
+ return null;
+ }
+
+ BinaryStreamReader GetReaderAt (RVA rva)
+ {
+ var section = GetSectionAtVirtualAddress (rva);
+ if (section == null)
+ return null;
+
+ var reader = new BinaryStreamReader (Stream.value);
+ reader.MoveTo (ResolveVirtualAddressInSection (rva, section));
+ return reader;
+ }
+
+ public TRet GetReaderAt (RVA rva, TItem item, Func read) where TRet : class
+ {
+ var position = Stream.value.Position;
+ try {
+ var reader = GetReaderAt (rva);
+ if (reader == null)
+ return null;
+
+ return read (item, reader);
+ } finally {
+ Stream.value.Position = position;
+ }
+ }
+
+ public bool HasDebugTables ()
+ {
+ return HasTable (Table.Document)
+ || HasTable (Table.MethodDebugInformation)
+ || HasTable (Table.LocalScope)
+ || HasTable (Table.LocalVariable)
+ || HasTable (Table.LocalConstant)
+ || HasTable (Table.StateMachineMethod)
+ || HasTable (Table.CustomDebugInformation);
+ }
+
+ public void Dispose ()
+ {
+ Stream.Dispose ();
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/ImageReader.cs b/Mono.Cecil.20/Mono.Cecil.PE/ImageReader.cs
new file mode 100644
index 00000000..f36d2e5a
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/ImageReader.cs
@@ -0,0 +1,783 @@
+//
+// 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.IO;
+
+using Mono.Cecil.Cil;
+using Mono.Cecil.Metadata;
+using Mono.Collections.Generic;
+
+using RVA = System.UInt32;
+
+namespace Mono.Cecil.PE {
+
+ sealed class ImageReader : BinaryStreamReader {
+
+ readonly Image image;
+
+ DataDirectory cli;
+ DataDirectory metadata;
+
+ uint table_heap_offset;
+
+ public ImageReader (Disposable stream, string file_name)
+ : base (stream.value)
+ {
+ image = new Image ();
+ image.Stream = stream;
+ image.FileName = file_name;
+ }
+
+ void MoveTo (DataDirectory directory)
+ {
+ BaseStream.Position = image.ResolveVirtualAddress (directory.VirtualAddress);
+ }
+
+ void ReadImage ()
+ {
+ if (BaseStream.Length < 128)
+ throw new BadImageFormatException ();
+
+ // - DOSHeader
+
+ // PE 2
+ // Start 58
+ // Lfanew 4
+ // End 64
+
+ if (ReadUInt16 () != 0x5a4d)
+ throw new BadImageFormatException ();
+
+ Advance (58);
+
+ MoveTo (ReadUInt32 ());
+
+ if (ReadUInt32 () != 0x00004550)
+ throw new BadImageFormatException ();
+
+ // - PEFileHeader
+
+ // Machine 2
+ image.Architecture = ReadArchitecture ();
+
+ // NumberOfSections 2
+ ushort sections = ReadUInt16 ();
+
+ // TimeDateStamp 4
+ image.Timestamp = ReadUInt32 ();
+ // PointerToSymbolTable 4
+ // NumberOfSymbols 4
+ // OptionalHeaderSize 2
+ Advance (10);
+
+ // Characteristics 2
+ ushort characteristics = ReadUInt16 ();
+
+ ushort subsystem, dll_characteristics;
+ ReadOptionalHeaders (out subsystem, out dll_characteristics);
+ ReadSections (sections);
+ ReadCLIHeader ();
+ ReadMetadata ();
+ ReadDebugHeader ();
+
+ image.Kind = GetModuleKind (characteristics, subsystem);
+ image.Characteristics = (ModuleCharacteristics) dll_characteristics;
+ }
+
+ TargetArchitecture ReadArchitecture ()
+ {
+ return (TargetArchitecture) ReadUInt16 ();
+ }
+
+ static ModuleKind GetModuleKind (ushort characteristics, ushort subsystem)
+ {
+ if ((characteristics & 0x2000) != 0) // ImageCharacteristics.Dll
+ return ModuleKind.Dll;
+
+ if (subsystem == 0x2 || subsystem == 0x9) // SubSystem.WindowsGui || SubSystem.WindowsCeGui
+ return ModuleKind.Windows;
+
+ return ModuleKind.Console;
+ }
+
+ void ReadOptionalHeaders (out ushort subsystem, out ushort dll_characteristics)
+ {
+ // - PEOptionalHeader
+ // - StandardFieldsHeader
+
+ // Magic 2
+ bool pe64 = ReadUInt16 () == 0x20b;
+
+ // pe32 || pe64
+
+ // LMajor 1
+ // LMinor 1
+ // CodeSize 4
+ // InitializedDataSize 4
+ // UninitializedDataSize4
+ // EntryPointRVA 4
+ // BaseOfCode 4
+ // BaseOfData 4 || 0
+
+ // - NTSpecificFieldsHeader
+
+ // ImageBase 4 || 8
+ // SectionAlignment 4
+ // FileAlignement 4
+ // OSMajor 2
+ // OSMinor 2
+ // UserMajor 2
+ // UserMinor 2
+ // SubSysMajor 2
+ // SubSysMinor 2
+ // Reserved 4
+ // ImageSize 4
+ // HeaderSize 4
+ // FileChecksum 4
+ Advance (66);
+
+ // SubSystem 2
+ subsystem = ReadUInt16 ();
+
+ // DLLFlags 2
+ dll_characteristics = ReadUInt16 ();
+ // StackReserveSize 4 || 8
+ // StackCommitSize 4 || 8
+ // HeapReserveSize 4 || 8
+ // HeapCommitSize 4 || 8
+ // LoaderFlags 4
+ // NumberOfDataDir 4
+
+ // - DataDirectoriesHeader
+
+ // ExportTable 8
+ // ImportTable 8
+ // ResourceTable 8
+ // ExceptionTable 8
+ // CertificateTable 8
+ // BaseRelocationTable 8
+
+ Advance (pe64 ? 88 : 72);
+
+ // Debug 8
+ image.Debug = ReadDataDirectory ();
+
+ // Copyright 8
+ // GlobalPtr 8
+ // TLSTable 8
+ // LoadConfigTable 8
+ // BoundImport 8
+ // IAT 8
+ // DelayImportDescriptor8
+ Advance (56);
+
+ // CLIHeader 8
+ cli = ReadDataDirectory ();
+
+ if (cli.IsZero)
+ throw new BadImageFormatException ();
+
+ // Reserved 8
+ Advance (8);
+ }
+
+ string ReadAlignedString (int length)
+ {
+ int read = 0;
+ var buffer = new char [length];
+ while (read < length) {
+ var current = ReadByte ();
+ if (current == 0)
+ break;
+
+ buffer [read++] = (char) current;
+ }
+
+ Advance (-1 + ((read + 4) & ~3) - read);
+
+ return new string (buffer, 0, read);
+ }
+
+ string ReadZeroTerminatedString (int length)
+ {
+ int read = 0;
+ var buffer = new char [length];
+ var bytes = ReadBytes (length);
+ while (read < length) {
+ var current = bytes [read];
+ if (current == 0)
+ break;
+
+ buffer [read++] = (char) current;
+ }
+
+ return new string (buffer, 0, read);
+ }
+
+ void ReadSections (ushort count)
+ {
+ var sections = new Section [count];
+
+ for (int i = 0; i < count; i++) {
+ var section = new Section ();
+
+ // Name
+ section.Name = ReadZeroTerminatedString (8);
+
+ // VirtualSize 4
+ Advance (4);
+
+ // VirtualAddress 4
+ section.VirtualAddress = ReadUInt32 ();
+ // SizeOfRawData 4
+ section.SizeOfRawData = ReadUInt32 ();
+ // PointerToRawData 4
+ section.PointerToRawData = ReadUInt32 ();
+
+ // PointerToRelocations 4
+ // PointerToLineNumbers 4
+ // NumberOfRelocations 2
+ // NumberOfLineNumbers 2
+ // Characteristics 4
+ Advance (16);
+
+ sections [i] = section;
+ }
+
+ image.Sections = sections;
+ }
+
+ void ReadCLIHeader ()
+ {
+ MoveTo (cli);
+
+ // - CLIHeader
+
+ // Cb 4
+ // MajorRuntimeVersion 2
+ // MinorRuntimeVersion 2
+ Advance (8);
+
+ // Metadata 8
+ metadata = ReadDataDirectory ();
+ // Flags 4
+ image.Attributes = (ModuleAttributes) ReadUInt32 ();
+ // EntryPointToken 4
+ image.EntryPointToken = ReadUInt32 ();
+ // Resources 8
+ image.Resources = ReadDataDirectory ();
+ // StrongNameSignature 8
+ image.StrongName = ReadDataDirectory ();
+ // CodeManagerTable 8
+ // VTableFixups 8
+ // ExportAddressTableJumps 8
+ // ManagedNativeHeader 8
+ }
+
+ void ReadMetadata ()
+ {
+ MoveTo (metadata);
+
+ if (ReadUInt32 () != 0x424a5342)
+ throw new BadImageFormatException ();
+
+ // MajorVersion 2
+ // MinorVersion 2
+ // Reserved 4
+ Advance (8);
+
+ image.RuntimeVersion = ReadZeroTerminatedString (ReadInt32 ());
+
+ // Flags 2
+ Advance (2);
+
+ var streams = ReadUInt16 ();
+
+ var section = image.GetSectionAtVirtualAddress (metadata.VirtualAddress);
+ if (section == null)
+ throw new BadImageFormatException ();
+
+ image.MetadataSection = section;
+
+ for (int i = 0; i < streams; i++)
+ ReadMetadataStream (section);
+
+ if (image.PdbHeap != null)
+ ReadPdbHeap ();
+
+ if (image.TableHeap != null)
+ ReadTableHeap ();
+ }
+
+ void ReadDebugHeader ()
+ {
+ if (image.Debug.IsZero) {
+ image.DebugHeader = new ImageDebugHeader (Empty.Array);
+ return;
+ }
+
+ MoveTo (image.Debug);
+
+ var entries = new ImageDebugHeaderEntry [(int) image.Debug.Size / ImageDebugDirectory.Size];
+
+ for (int i = 0; i < entries.Length; i++) {
+ var directory = new ImageDebugDirectory {
+ Characteristics = ReadInt32 (),
+ TimeDateStamp = ReadInt32 (),
+ MajorVersion = ReadInt16 (),
+ MinorVersion = ReadInt16 (),
+ Type = (ImageDebugType) ReadInt32 (),
+ SizeOfData = ReadInt32 (),
+ AddressOfRawData = ReadInt32 (),
+ PointerToRawData = ReadInt32 (),
+ };
+
+ if (directory.AddressOfRawData == 0) {
+ entries [i] = new ImageDebugHeaderEntry (directory, Empty.Array);
+ continue;
+ }
+
+ var position = Position;
+ try {
+ MoveTo ((uint) directory.PointerToRawData);
+ var data = ReadBytes (directory.SizeOfData);
+ entries [i] = new ImageDebugHeaderEntry (directory, data);
+ } finally {
+ Position = position;
+ }
+ }
+
+ image.DebugHeader = new ImageDebugHeader (entries);
+ }
+
+ void ReadMetadataStream (Section section)
+ {
+ // Offset 4
+ uint offset = metadata.VirtualAddress - section.VirtualAddress + ReadUInt32 (); // relative to the section start
+
+ // Size 4
+ uint size = ReadUInt32 ();
+
+ var data = ReadHeapData (offset, size);
+
+ var name = ReadAlignedString (16);
+ switch (name) {
+ case "#~":
+ case "#-":
+ image.TableHeap = new TableHeap (data);
+ table_heap_offset = offset;
+ break;
+ case "#Strings":
+ image.StringHeap = new StringHeap (data);
+ break;
+ case "#Blob":
+ image.BlobHeap = new BlobHeap (data);
+ break;
+ case "#GUID":
+ image.GuidHeap = new GuidHeap (data);
+ break;
+ case "#US":
+ image.UserStringHeap = new UserStringHeap (data);
+ break;
+ case "#Pdb":
+ image.PdbHeap = new PdbHeap (data);
+ break;
+ }
+ }
+
+ byte [] ReadHeapData (uint offset, uint size)
+ {
+ var position = BaseStream.Position;
+ MoveTo (offset + image.MetadataSection.PointerToRawData);
+ var data = ReadBytes ((int) size);
+ BaseStream.Position = position;
+
+ return data;
+ }
+
+ void ReadTableHeap ()
+ {
+ var heap = image.TableHeap;
+
+ MoveTo (table_heap_offset + image.MetadataSection.PointerToRawData);
+
+ // Reserved 4
+ // MajorVersion 1
+ // MinorVersion 1
+ Advance (6);
+
+ // HeapSizes 1
+ var sizes = ReadByte ();
+
+ // Reserved2 1
+ Advance (1);
+
+ // Valid 8
+ heap.Valid = ReadInt64 ();
+
+ // Sorted 8
+ heap.Sorted = ReadInt64 ();
+
+ if (image.PdbHeap != null) {
+ for (int i = 0; i < Mixin.TableCount; i++) {
+ if (!image.PdbHeap.HasTable ((Table) i))
+ continue;
+
+ heap.Tables [i].Length = image.PdbHeap.TypeSystemTableRows [i];
+ }
+ }
+
+ for (int i = 0; i < Mixin.TableCount; i++) {
+ if (!heap.HasTable ((Table) i))
+ continue;
+
+ heap.Tables [i].Length = ReadUInt32 ();
+ }
+
+ SetIndexSize (image.StringHeap, sizes, 0x1);
+ SetIndexSize (image.GuidHeap, sizes, 0x2);
+ SetIndexSize (image.BlobHeap, sizes, 0x4);
+
+ ComputeTableInformations ();
+ }
+
+ static void SetIndexSize (Heap heap, uint sizes, byte flag)
+ {
+ if (heap == null)
+ return;
+
+ heap.IndexSize = (sizes & flag) > 0 ? 4 : 2;
+ }
+
+ int GetTableIndexSize (Table table)
+ {
+ return image.GetTableIndexSize (table);
+ }
+
+ int GetCodedIndexSize (CodedIndex index)
+ {
+ return image.GetCodedIndexSize (index);
+ }
+
+ void ComputeTableInformations ()
+ {
+ uint offset = (uint) BaseStream.Position - table_heap_offset - image.MetadataSection.PointerToRawData; // header
+
+ int stridx_size = image.StringHeap.IndexSize;
+ int guididx_size = image.GuidHeap != null ? image.GuidHeap.IndexSize : 2;
+ int blobidx_size = image.BlobHeap != null ? image.BlobHeap.IndexSize : 2;
+
+ var heap = image.TableHeap;
+ var tables = heap.Tables;
+
+ for (int i = 0; i < Mixin.TableCount; i++) {
+ var table = (Table) i;
+ if (!heap.HasTable (table))
+ continue;
+
+ int size;
+ switch (table) {
+ case Table.Module:
+ size = 2 // Generation
+ + stridx_size // Name
+ + (guididx_size * 3); // Mvid, EncId, EncBaseId
+ break;
+ case Table.TypeRef:
+ size = GetCodedIndexSize (CodedIndex.ResolutionScope) // ResolutionScope
+ + (stridx_size * 2); // Name, Namespace
+ break;
+ case Table.TypeDef:
+ size = 4 // Flags
+ + (stridx_size * 2) // Name, Namespace
+ + GetCodedIndexSize (CodedIndex.TypeDefOrRef) // BaseType
+ + GetTableIndexSize (Table.Field) // FieldList
+ + GetTableIndexSize (Table.Method); // MethodList
+ break;
+ case Table.FieldPtr:
+ size = GetTableIndexSize (Table.Field); // Field
+ break;
+ case Table.Field:
+ size = 2 // Flags
+ + stridx_size // Name
+ + blobidx_size; // Signature
+ break;
+ case Table.MethodPtr:
+ size = GetTableIndexSize (Table.Method); // Method
+ break;
+ case Table.Method:
+ size = 8 // Rva 4, ImplFlags 2, Flags 2
+ + stridx_size // Name
+ + blobidx_size // Signature
+ + GetTableIndexSize (Table.Param); // ParamList
+ break;
+ case Table.ParamPtr:
+ size = GetTableIndexSize (Table.Param); // Param
+ break;
+ case Table.Param:
+ size = 4 // Flags 2, Sequence 2
+ + stridx_size; // Name
+ break;
+ case Table.InterfaceImpl:
+ size = GetTableIndexSize (Table.TypeDef) // Class
+ + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Interface
+ break;
+ case Table.MemberRef:
+ size = GetCodedIndexSize (CodedIndex.MemberRefParent) // Class
+ + stridx_size // Name
+ + blobidx_size; // Signature
+ break;
+ case Table.Constant:
+ size = 2 // Type
+ + GetCodedIndexSize (CodedIndex.HasConstant) // Parent
+ + blobidx_size; // Value
+ break;
+ case Table.CustomAttribute:
+ size = GetCodedIndexSize (CodedIndex.HasCustomAttribute) // Parent
+ + GetCodedIndexSize (CodedIndex.CustomAttributeType) // Type
+ + blobidx_size; // Value
+ break;
+ case Table.FieldMarshal:
+ size = GetCodedIndexSize (CodedIndex.HasFieldMarshal) // Parent
+ + blobidx_size; // NativeType
+ break;
+ case Table.DeclSecurity:
+ size = 2 // Action
+ + GetCodedIndexSize (CodedIndex.HasDeclSecurity) // Parent
+ + blobidx_size; // PermissionSet
+ break;
+ case Table.ClassLayout:
+ size = 6 // PackingSize 2, ClassSize 4
+ + GetTableIndexSize (Table.TypeDef); // Parent
+ break;
+ case Table.FieldLayout:
+ size = 4 // Offset
+ + GetTableIndexSize (Table.Field); // Field
+ break;
+ case Table.StandAloneSig:
+ size = blobidx_size; // Signature
+ break;
+ case Table.EventMap:
+ size = GetTableIndexSize (Table.TypeDef) // Parent
+ + GetTableIndexSize (Table.Event); // EventList
+ break;
+ case Table.EventPtr:
+ size = GetTableIndexSize (Table.Event); // Event
+ break;
+ case Table.Event:
+ size = 2 // Flags
+ + stridx_size // Name
+ + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // EventType
+ break;
+ case Table.PropertyMap:
+ size = GetTableIndexSize (Table.TypeDef) // Parent
+ + GetTableIndexSize (Table.Property); // PropertyList
+ break;
+ case Table.PropertyPtr:
+ size = GetTableIndexSize (Table.Property); // Property
+ break;
+ case Table.Property:
+ size = 2 // Flags
+ + stridx_size // Name
+ + blobidx_size; // Type
+ break;
+ case Table.MethodSemantics:
+ size = 2 // Semantics
+ + GetTableIndexSize (Table.Method) // Method
+ + GetCodedIndexSize (CodedIndex.HasSemantics); // Association
+ break;
+ case Table.MethodImpl:
+ size = GetTableIndexSize (Table.TypeDef) // Class
+ + GetCodedIndexSize (CodedIndex.MethodDefOrRef) // MethodBody
+ + GetCodedIndexSize (CodedIndex.MethodDefOrRef); // MethodDeclaration
+ break;
+ case Table.ModuleRef:
+ size = stridx_size; // Name
+ break;
+ case Table.TypeSpec:
+ size = blobidx_size; // Signature
+ break;
+ case Table.ImplMap:
+ size = 2 // MappingFlags
+ + GetCodedIndexSize (CodedIndex.MemberForwarded) // MemberForwarded
+ + stridx_size // ImportName
+ + GetTableIndexSize (Table.ModuleRef); // ImportScope
+ break;
+ case Table.FieldRVA:
+ size = 4 // RVA
+ + GetTableIndexSize (Table.Field); // Field
+ break;
+ case Table.EncLog:
+ size = 8;
+ break;
+ case Table.EncMap:
+ size = 4;
+ break;
+ case Table.Assembly:
+ size = 16 // HashAlgId 4, Version 4 * 2, Flags 4
+ + blobidx_size // PublicKey
+ + (stridx_size * 2); // Name, Culture
+ break;
+ case Table.AssemblyProcessor:
+ size = 4; // Processor
+ break;
+ case Table.AssemblyOS:
+ size = 12; // Platform 4, Version 2 * 4
+ break;
+ case Table.AssemblyRef:
+ size = 12 // Version 2 * 4 + Flags 4
+ + (blobidx_size * 2) // PublicKeyOrToken, HashValue
+ + (stridx_size * 2); // Name, Culture
+ break;
+ case Table.AssemblyRefProcessor:
+ size = 4 // Processor
+ + GetTableIndexSize (Table.AssemblyRef); // AssemblyRef
+ break;
+ case Table.AssemblyRefOS:
+ size = 12 // Platform 4, Version 2 * 4
+ + GetTableIndexSize (Table.AssemblyRef); // AssemblyRef
+ break;
+ case Table.File:
+ size = 4 // Flags
+ + stridx_size // Name
+ + blobidx_size; // HashValue
+ break;
+ case Table.ExportedType:
+ size = 8 // Flags 4, TypeDefId 4
+ + (stridx_size * 2) // Name, Namespace
+ + GetCodedIndexSize (CodedIndex.Implementation); // Implementation
+ break;
+ case Table.ManifestResource:
+ size = 8 // Offset, Flags
+ + stridx_size // Name
+ + GetCodedIndexSize (CodedIndex.Implementation); // Implementation
+ break;
+ case Table.NestedClass:
+ size = GetTableIndexSize (Table.TypeDef) // NestedClass
+ + GetTableIndexSize (Table.TypeDef); // EnclosingClass
+ break;
+ case Table.GenericParam:
+ size = 4 // Number, Flags
+ + GetCodedIndexSize (CodedIndex.TypeOrMethodDef) // Owner
+ + stridx_size; // Name
+ break;
+ case Table.MethodSpec:
+ size = GetCodedIndexSize (CodedIndex.MethodDefOrRef) // Method
+ + blobidx_size; // Instantiation
+ break;
+ case Table.GenericParamConstraint:
+ size = GetTableIndexSize (Table.GenericParam) // Owner
+ + GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Constraint
+ break;
+ case Table.Document:
+ size = blobidx_size // Name
+ + guididx_size // HashAlgorithm
+ + blobidx_size // Hash
+ + guididx_size; // Language
+ break;
+ case Table.MethodDebugInformation:
+ size = GetTableIndexSize (Table.Document) // Document
+ + blobidx_size; // SequencePoints
+ break;
+ case Table.LocalScope:
+ size = GetTableIndexSize (Table.Method) // Method
+ + GetTableIndexSize (Table.ImportScope) // ImportScope
+ + GetTableIndexSize (Table.LocalVariable) // VariableList
+ + GetTableIndexSize (Table.LocalConstant) // ConstantList
+ + 4 * 2; // StartOffset, Length
+ break;
+ case Table.LocalVariable:
+ size = 2 // Attributes
+ + 2 // Index
+ + stridx_size; // Name
+ break;
+ case Table.LocalConstant:
+ size = stridx_size // Name
+ + blobidx_size; // Signature
+ break;
+ case Table.ImportScope:
+ size = GetTableIndexSize (Table.ImportScope) // Parent
+ + blobidx_size;
+ break;
+ case Table.StateMachineMethod:
+ size = GetTableIndexSize (Table.Method) // MoveNextMethod
+ + GetTableIndexSize (Table.Method); // KickOffMethod
+ break;
+ case Table.CustomDebugInformation:
+ size = GetCodedIndexSize (CodedIndex.HasCustomDebugInformation) // Parent
+ + guididx_size // Kind
+ + blobidx_size; // Value
+ break;
+ default:
+ throw new NotSupportedException ();
+ }
+
+ tables [i].RowSize = (uint) size;
+ tables [i].Offset = offset;
+
+ offset += (uint) size * tables [i].Length;
+ }
+ }
+
+ void ReadPdbHeap ()
+ {
+ var heap = image.PdbHeap;
+
+ var buffer = new ByteBuffer (heap.data);
+
+ heap.Id = buffer.ReadBytes (20);
+ heap.EntryPoint = buffer.ReadUInt32 ();
+ heap.TypeSystemTables = buffer.ReadInt64 ();
+ heap.TypeSystemTableRows = new uint [Mixin.TableCount];
+
+ for (int i = 0; i < Mixin.TableCount; i++) {
+ var table = (Table) i;
+ if (!heap.HasTable (table))
+ continue;
+
+ heap.TypeSystemTableRows [i] = buffer.ReadUInt32 ();
+ }
+ }
+
+ public static Image ReadImage (Disposable stream, string file_name)
+ {
+ try {
+ var reader = new ImageReader (stream, file_name);
+ reader.ReadImage ();
+ return reader.image;
+ } catch (EndOfStreamException e) {
+ throw new BadImageFormatException (stream.value.GetFileName (), e);
+ }
+ }
+
+ public static Image ReadPortablePdb (Disposable stream, string file_name)
+ {
+ try {
+ var reader = new ImageReader (stream, file_name);
+ var length = (uint) stream.value.Length;
+
+ reader.image.Sections = new[] {
+ new Section {
+ PointerToRawData = 0,
+ SizeOfRawData = length,
+ VirtualAddress = 0,
+ VirtualSize = length,
+ }
+ };
+
+ reader.metadata = new DataDirectory (0, length);
+ reader.ReadMetadata ();
+ return reader.image;
+ } catch (EndOfStreamException e) {
+ throw new BadImageFormatException (stream.value.GetFileName (), e);
+ }
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/ImageWriter.cs b/Mono.Cecil.20/Mono.Cecil.PE/ImageWriter.cs
new file mode 100644
index 00000000..3fc689d2
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/ImageWriter.cs
@@ -0,0 +1,857 @@
+//
+// 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.IO;
+
+#if !READ_ONLY
+
+using Mono.Cecil.Cil;
+using Mono.Cecil.Metadata;
+
+using RVA = System.UInt32;
+
+namespace Mono.Cecil.PE {
+
+ sealed class ImageWriter : BinaryStreamWriter {
+
+ readonly ModuleDefinition module;
+ readonly MetadataBuilder metadata;
+ readonly TextMap text_map;
+ readonly internal Disposable stream;
+
+ readonly string runtime_version;
+
+ ImageDebugHeader debug_header;
+
+ ByteBuffer win32_resources;
+
+ const uint pe_header_size = 0x98u;
+ const uint section_header_size = 0x28u;
+ const uint file_alignment = 0x200;
+ const uint section_alignment = 0x2000;
+ const ulong image_base = 0x00400000;
+
+ internal const RVA text_rva = 0x2000;
+
+ readonly bool pe64;
+ readonly bool has_reloc;
+
+ internal Section text;
+ internal Section rsrc;
+ internal Section reloc;
+
+ ushort sections;
+
+ ImageWriter (ModuleDefinition module, string runtime_version, MetadataBuilder metadata, Disposable stream, bool metadataOnly = false)
+ : base (stream.value)
+ {
+ this.module = module;
+ this.runtime_version = runtime_version;
+ this.text_map = metadata.text_map;
+ this.stream = stream;
+ this.metadata = metadata;
+ if (metadataOnly)
+ return;
+
+ this.pe64 = module.Architecture == TargetArchitecture.AMD64 || module.Architecture == TargetArchitecture.IA64 || module.Architecture == TargetArchitecture.ARM64;
+ this.has_reloc = module.Architecture == TargetArchitecture.I386;
+ this.GetDebugHeader ();
+ this.GetWin32Resources ();
+ this.BuildTextMap ();
+ this.sections = (ushort) (has_reloc ? 2 : 1); // text + reloc?
+ }
+
+ void GetDebugHeader ()
+ {
+ var symbol_writer = metadata.symbol_writer;
+ if (symbol_writer != null)
+ debug_header = symbol_writer.GetDebugHeader ();
+
+ if (module.HasDebugHeader) {
+ var header = module.GetDebugHeader ();
+ var deterministic = header.GetDeterministicEntry ();
+ if (deterministic == null)
+ return;
+
+ debug_header = debug_header.AddDeterministicEntry ();
+ }
+ }
+
+ void GetWin32Resources ()
+ {
+ var rsrc = GetImageResourceSection ();
+ if (rsrc == null)
+ return;
+
+ win32_resources = module.Image.GetReaderAt (rsrc.VirtualAddress, rsrc.SizeOfRawData, (s, reader) => new ByteBuffer (reader.ReadBytes ((int) s)));
+ }
+
+ Section GetImageResourceSection ()
+ {
+ if (!module.HasImage)
+ return null;
+
+ const string rsrc_section = ".rsrc";
+
+ return module.Image.GetSection (rsrc_section);
+ }
+
+ public static ImageWriter CreateWriter (ModuleDefinition module, MetadataBuilder metadata, Disposable stream)
+ {
+ var writer = new ImageWriter (module, module.runtime_version, metadata, stream);
+ writer.BuildSections ();
+ return writer;
+ }
+
+ public static ImageWriter CreateDebugWriter (ModuleDefinition module, MetadataBuilder metadata, Disposable stream)
+ {
+ var writer = new ImageWriter (module, "PDB v1.0", metadata, stream, metadataOnly: true);
+ var length = metadata.text_map.GetLength ();
+ writer.text = new Section { SizeOfRawData = length, VirtualSize = length };
+ return writer;
+ }
+
+ void BuildSections ()
+ {
+ var has_win32_resources = win32_resources != null;
+ if (has_win32_resources)
+ sections++;
+
+ text = CreateSection (".text", text_map.GetLength (), null);
+ var previous = text;
+
+ if (has_win32_resources) {
+ rsrc = CreateSection (".rsrc", (uint) win32_resources.length, previous);
+
+ PatchWin32Resources (win32_resources);
+ previous = rsrc;
+ }
+
+ if (has_reloc)
+ reloc = CreateSection (".reloc", 12u, previous);
+ }
+
+ Section CreateSection (string name, uint size, Section previous)
+ {
+ return new Section {
+ Name = name,
+ VirtualAddress = previous != null
+ ? previous.VirtualAddress + Align (previous.VirtualSize, section_alignment)
+ : text_rva,
+ VirtualSize = size,
+ PointerToRawData = previous != null
+ ? previous.PointerToRawData + previous.SizeOfRawData
+ : Align (GetHeaderSize (), file_alignment),
+ SizeOfRawData = Align (size, file_alignment)
+ };
+ }
+
+ static uint Align (uint value, uint align)
+ {
+ align--;
+ return (value + align) & ~align;
+ }
+
+ void WriteDOSHeader ()
+ {
+ Write (new byte [] {
+ // dos header start
+ 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ // lfanew
+ 0x80, 0x00, 0x00, 0x00,
+ // dos header end
+ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09,
+ 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21,
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72,
+ 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63,
+ 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62,
+ 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69,
+ 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d,
+ 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+ });
+ }
+
+ ushort SizeOfOptionalHeader ()
+ {
+ return (ushort) (!pe64 ? 0xe0 : 0xf0);
+ }
+
+ void WritePEFileHeader ()
+ {
+ WriteUInt32 (0x00004550); // Magic
+ WriteUInt16 ((ushort) module.Architecture); // Machine
+ WriteUInt16 (sections); // NumberOfSections
+ WriteUInt32 (metadata.timestamp);
+ WriteUInt32 (0); // PointerToSymbolTable
+ WriteUInt32 (0); // NumberOfSymbols
+ WriteUInt16 (SizeOfOptionalHeader ()); // SizeOfOptionalHeader
+
+ // ExecutableImage | (pe64 ? 32BitsMachine : LargeAddressAware)
+ var characteristics = (ushort) (0x0002 | (!pe64 ? 0x0100 : 0x0020));
+ if (module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule)
+ characteristics |= 0x2000;
+ WriteUInt16 (characteristics); // Characteristics
+ }
+
+ Section LastSection ()
+ {
+ if (reloc != null)
+ return reloc;
+
+ if (rsrc != null)
+ return rsrc;
+
+ return text;
+ }
+
+ void WriteOptionalHeaders ()
+ {
+ WriteUInt16 ((ushort) (!pe64 ? 0x10b : 0x20b)); // Magic
+ WriteByte (8); // LMajor
+ WriteByte (0); // LMinor
+ WriteUInt32 (text.SizeOfRawData); // CodeSize
+ WriteUInt32 ((reloc != null ? reloc.SizeOfRawData : 0)
+ + (rsrc != null ? rsrc.SizeOfRawData : 0)); // InitializedDataSize
+ WriteUInt32 (0); // UninitializedDataSize
+
+ var startub_stub = text_map.GetRange (TextSegment.StartupStub);
+ WriteUInt32 (startub_stub.Length > 0 ? startub_stub.Start : 0); // EntryPointRVA
+ WriteUInt32 (text_rva); // BaseOfCode
+
+ if (!pe64) {
+ WriteUInt32 (0); // BaseOfData
+ WriteUInt32 ((uint) image_base); // ImageBase
+ } else {
+ WriteUInt64 (image_base); // ImageBase
+ }
+
+ WriteUInt32 (section_alignment); // SectionAlignment
+ WriteUInt32 (file_alignment); // FileAlignment
+
+ WriteUInt16 (4); // OSMajor
+ WriteUInt16 (0); // OSMinor
+ WriteUInt16 (0); // UserMajor
+ WriteUInt16 (0); // UserMinor
+ WriteUInt16 (4); // SubSysMajor
+ WriteUInt16 (0); // SubSysMinor
+ WriteUInt32 (0); // Reserved
+
+ var last_section = LastSection();
+ WriteUInt32 (last_section.VirtualAddress + Align (last_section.VirtualSize, section_alignment)); // ImageSize
+ WriteUInt32 (text.PointerToRawData); // HeaderSize
+
+ WriteUInt32 (0); // Checksum
+ WriteUInt16 (GetSubSystem ()); // SubSystem
+ WriteUInt16 ((ushort) module.Characteristics); // DLLFlags
+
+ const ulong stack_reserve = 0x100000;
+ const ulong stack_commit = 0x1000;
+ const ulong heap_reserve = 0x100000;
+ const ulong heap_commit = 0x1000;
+
+ if (!pe64) {
+ WriteUInt32 ((uint) stack_reserve);
+ WriteUInt32 ((uint) stack_commit);
+ WriteUInt32 ((uint) heap_reserve);
+ WriteUInt32 ((uint) heap_commit);
+ } else {
+ WriteUInt64 (stack_reserve);
+ WriteUInt64 (stack_commit);
+ WriteUInt64 (heap_reserve);
+ WriteUInt64 (heap_commit);
+ }
+
+ WriteUInt32 (0); // LoaderFlags
+ WriteUInt32 (16); // NumberOfDataDir
+
+ WriteZeroDataDirectory (); // ExportTable
+ WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportDirectory)); // ImportTable
+ if (rsrc != null) { // ResourceTable
+ WriteUInt32 (rsrc.VirtualAddress);
+ WriteUInt32 (rsrc.VirtualSize);
+ } else
+ WriteZeroDataDirectory ();
+
+ WriteZeroDataDirectory (); // ExceptionTable
+ WriteZeroDataDirectory (); // CertificateTable
+ WriteUInt32 (reloc != null ? reloc.VirtualAddress : 0); // BaseRelocationTable
+ WriteUInt32 (reloc != null ? reloc.VirtualSize : 0);
+
+ if (text_map.GetLength (TextSegment.DebugDirectory) > 0) {
+ WriteUInt32 (text_map.GetRVA (TextSegment.DebugDirectory));
+ WriteUInt32 ((uint) (debug_header.Entries.Length * ImageDebugDirectory.Size));
+ } else
+ WriteZeroDataDirectory ();
+
+ WriteZeroDataDirectory (); // Copyright
+ WriteZeroDataDirectory (); // GlobalPtr
+ WriteZeroDataDirectory (); // TLSTable
+ WriteZeroDataDirectory (); // LoadConfigTable
+ WriteZeroDataDirectory (); // BoundImport
+ WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportAddressTable)); // IAT
+ WriteZeroDataDirectory (); // DelayImportDesc
+ WriteDataDirectory (text_map.GetDataDirectory (TextSegment.CLIHeader)); // CLIHeader
+ WriteZeroDataDirectory (); // Reserved
+ }
+
+ void WriteZeroDataDirectory ()
+ {
+ WriteUInt32 (0);
+ WriteUInt32 (0);
+ }
+
+ ushort GetSubSystem ()
+ {
+ switch (module.Kind) {
+ case ModuleKind.Console:
+ case ModuleKind.Dll:
+ case ModuleKind.NetModule:
+ return 0x3;
+ case ModuleKind.Windows:
+ return 0x2;
+ default:
+ throw new ArgumentOutOfRangeException ();
+ }
+ }
+
+ void WriteSectionHeaders ()
+ {
+ WriteSection (text, 0x60000020);
+
+ if (rsrc != null)
+ WriteSection (rsrc, 0x40000040);
+
+ if (reloc != null)
+ WriteSection (reloc, 0x42000040);
+ }
+
+ void WriteSection (Section section, uint characteristics)
+ {
+ var name = new byte [8];
+ var sect_name = section.Name;
+ for (int i = 0; i < sect_name.Length; i++)
+ name [i] = (byte) sect_name [i];
+
+ WriteBytes (name);
+ WriteUInt32 (section.VirtualSize);
+ WriteUInt32 (section.VirtualAddress);
+ WriteUInt32 (section.SizeOfRawData);
+ WriteUInt32 (section.PointerToRawData);
+ WriteUInt32 (0); // PointerToRelocations
+ WriteUInt32 (0); // PointerToLineNumbers
+ WriteUInt16 (0); // NumberOfRelocations
+ WriteUInt16 (0); // NumberOfLineNumbers
+ WriteUInt32 (characteristics);
+ }
+
+ void MoveTo (uint pointer)
+ {
+ BaseStream.Seek (pointer, SeekOrigin.Begin);
+ }
+
+ void MoveToRVA (Section section, RVA rva)
+ {
+ BaseStream.Seek (section.PointerToRawData + rva - section.VirtualAddress, SeekOrigin.Begin);
+ }
+
+ void MoveToRVA (TextSegment segment)
+ {
+ MoveToRVA (text, text_map.GetRVA (segment));
+ }
+
+ void WriteRVA (RVA rva)
+ {
+ if (!pe64)
+ WriteUInt32 (rva);
+ else
+ WriteUInt64 (rva);
+ }
+
+ void PrepareSection (Section section)
+ {
+ MoveTo (section.PointerToRawData);
+
+ const int buffer_size = 4096;
+
+ if (section.SizeOfRawData <= buffer_size) {
+ Write (new byte [section.SizeOfRawData]);
+ MoveTo (section.PointerToRawData);
+ return;
+ }
+
+ var written = 0;
+ var buffer = new byte [buffer_size];
+ while (written != section.SizeOfRawData) {
+ var write_size = System.Math.Min((int) section.SizeOfRawData - written, buffer_size);
+ Write (buffer, 0, write_size);
+ written += write_size;
+ }
+
+ MoveTo (section.PointerToRawData);
+ }
+
+ void WriteText ()
+ {
+ PrepareSection (text);
+
+ // ImportAddressTable
+
+ if (has_reloc) {
+ WriteRVA (text_map.GetRVA (TextSegment.ImportHintNameTable));
+ WriteRVA (0);
+ }
+
+ // CLIHeader
+
+ WriteUInt32 (0x48);
+ WriteUInt16 (2);
+ WriteUInt16 ((ushort) ((module.Runtime <= TargetRuntime.Net_1_1) ? 0 : 5));
+
+ WriteUInt32 (text_map.GetRVA (TextSegment.MetadataHeader));
+ WriteUInt32 (GetMetadataLength ());
+ WriteUInt32 ((uint) module.Attributes);
+ WriteUInt32 (metadata.entry_point.ToUInt32 ());
+ WriteDataDirectory (text_map.GetDataDirectory (TextSegment.Resources));
+ WriteDataDirectory (text_map.GetDataDirectory (TextSegment.StrongNameSignature));
+ WriteZeroDataDirectory (); // CodeManagerTable
+ WriteZeroDataDirectory (); // VTableFixups
+ WriteZeroDataDirectory (); // ExportAddressTableJumps
+ WriteZeroDataDirectory (); // ManagedNativeHeader
+
+ // Code
+
+ MoveToRVA (TextSegment.Code);
+ WriteBuffer (metadata.code);
+
+ // Resources
+
+ MoveToRVA (TextSegment.Resources);
+ WriteBuffer (metadata.resources);
+
+ // Data
+
+ if (metadata.data.length > 0) {
+ MoveToRVA (TextSegment.Data);
+ WriteBuffer (metadata.data);
+ }
+
+ // StrongNameSignature
+ // stays blank
+
+ // MetadataHeader
+
+ MoveToRVA (TextSegment.MetadataHeader);
+ WriteMetadataHeader ();
+
+ WriteMetadata ();
+
+ // DebugDirectory
+ if (text_map.GetLength (TextSegment.DebugDirectory) > 0) {
+ MoveToRVA (TextSegment.DebugDirectory);
+ WriteDebugDirectory ();
+ }
+
+ if (!has_reloc)
+ return;
+
+ // ImportDirectory
+ MoveToRVA (TextSegment.ImportDirectory);
+ WriteImportDirectory ();
+
+ // StartupStub
+ MoveToRVA (TextSegment.StartupStub);
+ WriteStartupStub ();
+ }
+
+ uint GetMetadataLength ()
+ {
+ return text_map.GetRVA (TextSegment.DebugDirectory) - text_map.GetRVA (TextSegment.MetadataHeader);
+ }
+
+ public void WriteMetadataHeader ()
+ {
+ WriteUInt32 (0x424a5342); // Signature
+ WriteUInt16 (1); // MajorVersion
+ WriteUInt16 (1); // MinorVersion
+ WriteUInt32 (0); // Reserved
+
+ var version = GetZeroTerminatedString (runtime_version);
+ WriteUInt32 ((uint) version.Length);
+ WriteBytes (version);
+ WriteUInt16 (0); // Flags
+ WriteUInt16 (GetStreamCount ());
+
+ uint offset = text_map.GetRVA (TextSegment.TableHeap) - text_map.GetRVA (TextSegment.MetadataHeader);
+
+ WriteStreamHeader (ref offset, TextSegment.TableHeap, "#~");
+ WriteStreamHeader (ref offset, TextSegment.StringHeap, "#Strings");
+ WriteStreamHeader (ref offset, TextSegment.UserStringHeap, "#US");
+ WriteStreamHeader (ref offset, TextSegment.GuidHeap, "#GUID");
+ WriteStreamHeader (ref offset, TextSegment.BlobHeap, "#Blob");
+ WriteStreamHeader (ref offset, TextSegment.PdbHeap, "#Pdb");
+ }
+
+ ushort GetStreamCount ()
+ {
+ return (ushort) (
+ 1 // #~
+ + 1 // #Strings
+ + (metadata.user_string_heap.IsEmpty ? 0 : 1) // #US
+ + (metadata.guid_heap.IsEmpty ? 0 : 1) // GUID
+ + (metadata.blob_heap.IsEmpty ? 0 : 1)
+ + (metadata.pdb_heap == null ? 0 : 1)); // #Blob
+ }
+
+ void WriteStreamHeader (ref uint offset, TextSegment heap, string name)
+ {
+ var length = (uint) text_map.GetLength (heap);
+ if (length == 0)
+ return;
+
+ WriteUInt32 (offset);
+ WriteUInt32 (length);
+ WriteBytes (GetZeroTerminatedString (name));
+ offset += length;
+ }
+
+ static int GetZeroTerminatedStringLength (string @string)
+ {
+ return (@string.Length + 1 + 3) & ~3;
+ }
+
+ static byte [] GetZeroTerminatedString (string @string)
+ {
+ return GetString (@string, GetZeroTerminatedStringLength (@string));
+ }
+
+ static byte [] GetSimpleString (string @string)
+ {
+ return GetString (@string, @string.Length);
+ }
+
+ static byte [] GetString (string @string, int length)
+ {
+ var bytes = new byte [length];
+ for (int i = 0; i < @string.Length; i++)
+ bytes [i] = (byte) @string [i];
+
+ return bytes;
+ }
+
+ public void WriteMetadata ()
+ {
+ WriteHeap (TextSegment.TableHeap, metadata.table_heap);
+ WriteHeap (TextSegment.StringHeap, metadata.string_heap);
+ WriteHeap (TextSegment.UserStringHeap, metadata.user_string_heap);
+ WriteHeap (TextSegment.GuidHeap, metadata.guid_heap);
+ WriteHeap (TextSegment.BlobHeap, metadata.blob_heap);
+ WriteHeap (TextSegment.PdbHeap, metadata.pdb_heap);
+ }
+
+ void WriteHeap (TextSegment heap, HeapBuffer buffer)
+ {
+ if (buffer == null || buffer.IsEmpty)
+ return;
+
+ MoveToRVA (heap);
+ WriteBuffer (buffer);
+ }
+
+ void WriteDebugDirectory ()
+ {
+ var data_start = (int) BaseStream.Position + (debug_header.Entries.Length * ImageDebugDirectory.Size);
+
+ for (var i = 0; i < debug_header.Entries.Length; i++) {
+ var entry = debug_header.Entries [i];
+ var directory = entry.Directory;
+ WriteInt32 (directory.Characteristics);
+ WriteInt32 (directory.TimeDateStamp);
+ WriteInt16 (directory.MajorVersion);
+ WriteInt16 (directory.MinorVersion);
+ WriteInt32 ((int) directory.Type);
+ WriteInt32 (directory.SizeOfData);
+ WriteInt32 (directory.AddressOfRawData);
+ WriteInt32 (data_start);
+
+ data_start += entry.Data.Length;
+ }
+
+ for (var i = 0; i < debug_header.Entries.Length; i++) {
+ var entry = debug_header.Entries [i];
+ WriteBytes (entry.Data);
+ }
+ }
+
+ void WriteImportDirectory ()
+ {
+ WriteUInt32 (text_map.GetRVA (TextSegment.ImportDirectory) + 40); // ImportLookupTable
+ WriteUInt32 (0); // DateTimeStamp
+ WriteUInt32 (0); // ForwarderChain
+ WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable) + 14);
+ WriteUInt32 (text_map.GetRVA (TextSegment.ImportAddressTable));
+ Advance (20);
+
+ // ImportLookupTable
+ WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable));
+
+ // ImportHintNameTable
+ MoveToRVA (TextSegment.ImportHintNameTable);
+
+ WriteUInt16 (0); // Hint
+ WriteBytes (GetRuntimeMain ());
+ WriteByte (0);
+ WriteBytes (GetSimpleString ("mscoree.dll"));
+ WriteUInt16 (0);
+ }
+
+ byte [] GetRuntimeMain ()
+ {
+ return module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule
+ ? GetSimpleString ("_CorDllMain")
+ : GetSimpleString ("_CorExeMain");
+ }
+
+ void WriteStartupStub ()
+ {
+ switch (module.Architecture) {
+ case TargetArchitecture.I386:
+ WriteUInt16 (0x25ff);
+ WriteUInt32 ((uint) image_base + text_map.GetRVA (TextSegment.ImportAddressTable));
+ return;
+ default:
+ throw new NotSupportedException ();
+ }
+ }
+
+ void WriteRsrc ()
+ {
+ PrepareSection (rsrc);
+ WriteBuffer (win32_resources);
+ }
+
+ void WriteReloc ()
+ {
+ PrepareSection (reloc);
+
+ var reloc_rva = text_map.GetRVA (TextSegment.StartupStub);
+ reloc_rva += module.Architecture == TargetArchitecture.IA64 ? 0x20u : 2;
+ var page_rva = reloc_rva & ~0xfffu;
+
+ WriteUInt32 (page_rva); // PageRVA
+ WriteUInt32 (0x000c); // Block Size
+
+ switch (module.Architecture) {
+ case TargetArchitecture.I386:
+ WriteUInt32 (0x3000 + reloc_rva - page_rva);
+ break;
+ default:
+ throw new NotSupportedException();
+ }
+ }
+
+ public void WriteImage ()
+ {
+ WriteDOSHeader ();
+ WritePEFileHeader ();
+ WriteOptionalHeaders ();
+ WriteSectionHeaders ();
+ WriteText ();
+ if (rsrc != null)
+ WriteRsrc ();
+ if (reloc != null)
+ WriteReloc ();
+ Flush ();
+ }
+
+ void BuildTextMap ()
+ {
+ var map = text_map;
+
+ map.AddMap (TextSegment.Code, metadata.code.length, !pe64 ? 4 : 16);
+ map.AddMap (TextSegment.Resources, metadata.resources.length, 8);
+ map.AddMap (TextSegment.Data, metadata.data.length, 4);
+ if (metadata.data.length > 0)
+ metadata.table_heap.FixupData (map.GetRVA (TextSegment.Data));
+ map.AddMap (TextSegment.StrongNameSignature, GetStrongNameLength (), 4);
+
+ BuildMetadataTextMap ();
+
+ int debug_dir_len = 0;
+ if (debug_header != null && debug_header.HasEntries) {
+ var directories_len = debug_header.Entries.Length * ImageDebugDirectory.Size;
+ var data_address = (int) map.GetNextRVA (TextSegment.BlobHeap) + directories_len;
+ var data_len = 0;
+
+ for (var i = 0; i < debug_header.Entries.Length; i++) {
+ var entry = debug_header.Entries [i];
+ var directory = entry.Directory;
+
+ directory.AddressOfRawData = entry.Data.Length == 0 ? 0 : data_address;
+ entry.Directory = directory;
+
+ data_len += entry.Data.Length;
+ data_address += data_len;
+ }
+
+ debug_dir_len = directories_len + data_len;
+ }
+
+ map.AddMap (TextSegment.DebugDirectory, debug_dir_len, 4);
+
+ if (!has_reloc) {
+ var start = map.GetNextRVA (TextSegment.DebugDirectory);
+ map.AddMap (TextSegment.ImportDirectory, new Range (start, 0));
+ map.AddMap (TextSegment.ImportHintNameTable, new Range (start, 0));
+ map.AddMap (TextSegment.StartupStub, new Range (start, 0));
+ return;
+ }
+
+ RVA import_dir_rva = map.GetNextRVA (TextSegment.DebugDirectory);
+ RVA import_hnt_rva = import_dir_rva + 48u;
+ import_hnt_rva = (import_hnt_rva + 15u) & ~15u;
+ uint import_dir_len = (import_hnt_rva - import_dir_rva) + 27u;
+
+ RVA startup_stub_rva = import_dir_rva + import_dir_len;
+ startup_stub_rva = module.Architecture == TargetArchitecture.IA64
+ ? (startup_stub_rva + 15u) & ~15u
+ : 2 + ((startup_stub_rva + 3u) & ~3u);
+
+ map.AddMap (TextSegment.ImportDirectory, new Range (import_dir_rva, import_dir_len));
+ map.AddMap (TextSegment.ImportHintNameTable, new Range (import_hnt_rva, 0));
+ map.AddMap (TextSegment.StartupStub, new Range (startup_stub_rva, GetStartupStubLength ()));
+ }
+
+ public void BuildMetadataTextMap ()
+ {
+ var map = text_map;
+
+ map.AddMap (TextSegment.MetadataHeader, GetMetadataHeaderLength (module.RuntimeVersion));
+ map.AddMap (TextSegment.TableHeap, metadata.table_heap.length, 4);
+ map.AddMap (TextSegment.StringHeap, metadata.string_heap.length, 4);
+ map.AddMap (TextSegment.UserStringHeap, metadata.user_string_heap.IsEmpty ? 0 : metadata.user_string_heap.length, 4);
+ map.AddMap (TextSegment.GuidHeap, metadata.guid_heap.length, 4);
+ map.AddMap (TextSegment.BlobHeap, metadata.blob_heap.IsEmpty ? 0 : metadata.blob_heap.length, 4);
+ map.AddMap (TextSegment.PdbHeap, metadata.pdb_heap == null ? 0 : metadata.pdb_heap.length, 4);
+ }
+
+ uint GetStartupStubLength ()
+ {
+ switch (module.Architecture) {
+ case TargetArchitecture.I386:
+ return 6;
+ default:
+ throw new NotSupportedException ();
+ }
+ }
+
+ int GetMetadataHeaderLength (string runtimeVersion)
+ {
+ return
+ // MetadataHeader
+ 20 + GetZeroTerminatedStringLength (runtimeVersion)
+ // #~ header
+ + 12
+ // #Strings header
+ + 20
+ // #US header
+ + (metadata.user_string_heap.IsEmpty ? 0 : 12)
+ // #GUID header
+ + 16
+ // #Blob header
+ + (metadata.blob_heap.IsEmpty ? 0 : 16)
+ //
+ + (metadata.pdb_heap == null ? 0 : 16);
+ }
+
+ int GetStrongNameLength ()
+ {
+ if (module.Assembly == null)
+ return 0;
+
+ var public_key = module.Assembly.Name.PublicKey;
+ if (public_key.IsNullOrEmpty ())
+ return 0;
+
+ // in fx 2.0 the key may be from 384 to 16384 bits
+ // so we must calculate the signature size based on
+ // the size of the public key (minus the 32 byte header)
+ int size = public_key.Length;
+ if (size > 32)
+ return size - 32;
+
+ // note: size == 16 for the ECMA "key" which is replaced
+ // by the runtime with a 1024 bits key (128 bytes)
+
+ return 128; // default strongname signature size
+ }
+
+ public DataDirectory GetStrongNameSignatureDirectory ()
+ {
+ return text_map.GetDataDirectory (TextSegment.StrongNameSignature);
+ }
+
+ public uint GetHeaderSize ()
+ {
+ return pe_header_size + SizeOfOptionalHeader () + (sections * section_header_size);
+ }
+
+ void PatchWin32Resources (ByteBuffer resources)
+ {
+ PatchResourceDirectoryTable (resources);
+ }
+
+ void PatchResourceDirectoryTable (ByteBuffer resources)
+ {
+ resources.Advance (12);
+
+ var entries = resources.ReadUInt16 () + resources.ReadUInt16 ();
+
+ for (int i = 0; i < entries; i++)
+ PatchResourceDirectoryEntry (resources);
+ }
+
+ void PatchResourceDirectoryEntry (ByteBuffer resources)
+ {
+ resources.Advance (4);
+ var child = resources.ReadUInt32 ();
+
+ var position = resources.position;
+ resources.position = (int) child & 0x7fffffff;
+
+ if ((child & 0x80000000) != 0)
+ PatchResourceDirectoryTable (resources);
+ else
+ PatchResourceDataEntry (resources);
+
+ resources.position = position;
+ }
+
+ void PatchResourceDataEntry (ByteBuffer resources)
+ {
+ var old_rsrc = GetImageResourceSection ();
+ var rva = resources.ReadUInt32 ();
+ resources.position -= 4;
+ resources.WriteUInt32 (rva - old_rsrc.VirtualAddress + rsrc.VirtualAddress);
+ }
+ }
+}
+
+#endif
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/Section.cs b/Mono.Cecil.20/Mono.Cecil.PE/Section.cs
new file mode 100644
index 00000000..49d8e900
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/Section.cs
@@ -0,0 +1,24 @@
+//
+// 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 RVA = System.UInt32;
+
+namespace Mono.Cecil.PE {
+
+ sealed class Section {
+ public string Name;
+ public RVA VirtualAddress;
+ public uint VirtualSize;
+ public uint SizeOfRawData;
+ public uint PointerToRawData;
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil.PE/TextMap.cs b/Mono.Cecil.20/Mono.Cecil.PE/TextMap.cs
new file mode 100644
index 00000000..614691b6
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil.PE/TextMap.cs
@@ -0,0 +1,112 @@
+//
+// 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;
+
+#if !READ_ONLY
+
+using RVA = System.UInt32;
+
+namespace Mono.Cecil.PE {
+
+ enum TextSegment {
+ ImportAddressTable,
+ CLIHeader,
+ Code,
+ Resources,
+ Data,
+ StrongNameSignature,
+
+ // Metadata
+ MetadataHeader,
+ TableHeap,
+ StringHeap,
+ UserStringHeap,
+ GuidHeap,
+ BlobHeap,
+ PdbHeap,
+ // End Metadata
+
+ DebugDirectory,
+ ImportDirectory,
+ ImportHintNameTable,
+ StartupStub,
+ }
+
+ sealed class TextMap {
+
+ readonly Range [] map = new Range [17 /*Enum.GetValues (typeof (TextSegment)).Length*/];
+
+ public void AddMap (TextSegment segment, int length)
+ {
+ map [(int) segment] = new Range (GetStart (segment), (uint) length);
+ }
+
+ public void AddMap (TextSegment segment, int length, int align)
+ {
+ align--;
+
+ AddMap (segment, (length + align) & ~align);
+ }
+
+ public void AddMap (TextSegment segment, Range range)
+ {
+ map [(int) segment] = range;
+ }
+
+ public Range GetRange (TextSegment segment)
+ {
+ return map [(int) segment];
+ }
+
+ public DataDirectory GetDataDirectory (TextSegment segment)
+ {
+ var range = map [(int) segment];
+
+ return new DataDirectory (range.Length == 0 ? 0 : range.Start, range.Length);
+ }
+
+ public RVA GetRVA (TextSegment segment)
+ {
+ return map [(int) segment].Start;
+ }
+
+ public RVA GetNextRVA (TextSegment segment)
+ {
+ var i = (int) segment;
+ return map [i].Start + map [i].Length;
+ }
+
+ public int GetLength (TextSegment segment)
+ {
+ return (int) map [(int) segment].Length;
+ }
+
+ RVA GetStart (TextSegment segment)
+ {
+ var index = (int) segment;
+ return index == 0 ? ImageWriter.text_rva : ComputeStart (index);
+ }
+
+ RVA ComputeStart (int index)
+ {
+ index--;
+ return map [index].Start + map [index].Length;
+ }
+
+ public uint GetLength ()
+ {
+ var range = map [(int) TextSegment.StartupStub];
+ return range.Start - ImageWriter.text_rva + range.Length;
+ }
+ }
+}
+
+#endif
diff --git a/Mono.Cecil.20/MonoCecil/Mono.Cecil/ArrayType.cs b/Mono.Cecil.20/Mono.Cecil/ArrayType.cs
similarity index 69%
rename from Mono.Cecil.20/MonoCecil/Mono.Cecil/ArrayType.cs
rename to Mono.Cecil.20/Mono.Cecil/ArrayType.cs
index 55c59d87..010049cc 100644
--- a/Mono.Cecil.20/MonoCecil/Mono.Cecil/ArrayType.cs
+++ b/Mono.Cecil.20/Mono.Cecil/ArrayType.cs
@@ -1,29 +1,11 @@
//
-// ArrayType.cs
-//
// Author:
// Jb Evain (jbevain@gmail.com)
//
-// Copyright (c) 2008 - 2011 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Licensed under the MIT/X11 license.
//
using System;
diff --git a/Mono.Cecil.20/Mono.Cecil/AssemblyDefinition.cs b/Mono.Cecil.20/Mono.Cecil/AssemblyDefinition.cs
new file mode 100644
index 00000000..f02b93f2
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil/AssemblyDefinition.cs
@@ -0,0 +1,194 @@
+//
+// 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.IO;
+
+using Mono.Collections.Generic;
+
+namespace Mono.Cecil {
+
+ public sealed class AssemblyDefinition : ICustomAttributeProvider, ISecurityDeclarationProvider, IDisposable {
+
+ AssemblyNameDefinition name;
+
+ internal ModuleDefinition main_module;
+ Collection modules;
+ Collection custom_attributes;
+ Collection security_declarations;
+
+ public AssemblyNameDefinition Name {
+ get { return name; }
+ set { name = value; }
+ }
+
+ public string FullName {
+ get { return name != null ? name.FullName : string.Empty; }
+ }
+
+ public MetadataToken MetadataToken {
+ get { return new MetadataToken (TokenType.Assembly, 1); }
+ set { }
+ }
+
+ public Collection Modules {
+ get {
+ if (modules != null)
+ return modules;
+
+ if (main_module.HasImage)
+ return main_module.Read (ref modules, this, (_, reader) => reader.ReadModules ());
+
+ return modules = new Collection (1) { main_module };
+ }
+ }
+
+ public ModuleDefinition MainModule {
+ get { return main_module; }
+ }
+
+ public MethodDefinition EntryPoint {
+ get { return main_module.EntryPoint; }
+ set { main_module.EntryPoint = value; }
+ }
+
+ public bool HasCustomAttributes {
+ get {
+ if (custom_attributes != null)
+ return custom_attributes.Count > 0;
+
+ return this.GetHasCustomAttributes (main_module);
+ }
+ }
+
+ public Collection CustomAttributes {
+ get { return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, main_module)); }
+ }
+
+ public bool HasSecurityDeclarations {
+ get {
+ if (security_declarations != null)
+ return security_declarations.Count > 0;
+
+ return this.GetHasSecurityDeclarations (main_module);
+ }
+ }
+
+ public Collection SecurityDeclarations {
+ get { return security_declarations ?? (this.GetSecurityDeclarations (ref security_declarations, main_module)); }
+ }
+
+ internal AssemblyDefinition ()
+ {
+ }
+
+ public void Dispose ()
+ {
+ if (this.modules == null) {
+ main_module.Dispose ();
+ return;
+ }
+
+ var modules = this.Modules;
+ for (int i = 0; i < modules.Count; i++)
+ modules [i].Dispose ();
+ }
+
+#if !READ_ONLY
+ public static AssemblyDefinition CreateAssembly (AssemblyNameDefinition assemblyName, string moduleName, ModuleKind kind)
+ {
+ return CreateAssembly (assemblyName, moduleName, new ModuleParameters { Kind = kind });
+ }
+
+ public static AssemblyDefinition CreateAssembly (AssemblyNameDefinition assemblyName, string moduleName, ModuleParameters parameters)
+ {
+ if (assemblyName == null)
+ throw new ArgumentNullException ("assemblyName");
+ if (moduleName == null)
+ throw new ArgumentNullException ("moduleName");
+ Mixin.CheckParameters (parameters);
+ if (parameters.Kind == ModuleKind.NetModule)
+ throw new ArgumentException ("kind");
+
+ var assembly = ModuleDefinition.CreateModule (moduleName, parameters).Assembly;
+ assembly.Name = assemblyName;
+
+ return assembly;
+ }
+#endif
+
+ public static AssemblyDefinition ReadAssembly (string fileName)
+ {
+ return ReadAssembly (ModuleDefinition.ReadModule (fileName));
+ }
+
+ public static AssemblyDefinition ReadAssembly (string fileName, ReaderParameters parameters)
+ {
+ return ReadAssembly (ModuleDefinition.ReadModule (fileName, parameters));
+ }
+
+ public static AssemblyDefinition ReadAssembly (Stream stream)
+ {
+ return ReadAssembly (ModuleDefinition.ReadModule (stream));
+ }
+
+ public static AssemblyDefinition ReadAssembly (Stream stream, ReaderParameters parameters)
+ {
+ return ReadAssembly (ModuleDefinition.ReadModule (stream, parameters));
+ }
+
+ static AssemblyDefinition ReadAssembly (ModuleDefinition module)
+ {
+ var assembly = module.Assembly;
+ if (assembly == null)
+ throw new ArgumentException ();
+
+ return assembly;
+ }
+
+#if !READ_ONLY
+
+ public void Write (string fileName)
+ {
+ Write (fileName, new WriterParameters ());
+ }
+
+ public void Write (string fileName, WriterParameters parameters)
+ {
+ main_module.Write (fileName, parameters);
+ }
+
+ public void Write ()
+ {
+ main_module.Write ();
+ }
+
+ public void Write (WriterParameters parameters)
+ {
+ main_module.Write (parameters);
+ }
+
+ public void Write (Stream stream)
+ {
+ Write (stream, new WriterParameters ());
+ }
+
+ public void Write (Stream stream, WriterParameters parameters)
+ {
+ main_module.Write (stream, parameters);
+ }
+#endif
+
+ public override string ToString ()
+ {
+ return this.FullName;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil/AssemblyFlags.cs b/Mono.Cecil.20/Mono.Cecil/AssemblyFlags.cs
new file mode 100644
index 00000000..6ca5bc27
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil/AssemblyFlags.cs
@@ -0,0 +1,24 @@
+//
+// 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;
+
+namespace Mono.Cecil {
+
+ [Flags]
+ public enum AssemblyAttributes : uint {
+ PublicKey = 0x0001,
+ SideBySideCompatible = 0x0000,
+ Retargetable = 0x0100,
+ WindowsRuntime = 0x0200,
+ DisableJITCompileOptimizer = 0x4000,
+ EnableJITCompileTracking = 0x8000,
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil/AssemblyHashAlgorithm.cs b/Mono.Cecil.20/Mono.Cecil/AssemblyHashAlgorithm.cs
new file mode 100644
index 00000000..66ef4cbb
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil/AssemblyHashAlgorithm.cs
@@ -0,0 +1,18 @@
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// Copyright (c) 2008 - 2015 Jb Evain
+// Copyright (c) 2008 - 2011 Novell, Inc.
+//
+// Licensed under the MIT/X11 license.
+//
+
+namespace Mono.Cecil {
+
+ public enum AssemblyHashAlgorithm : uint {
+ None = 0x0000,
+ Reserved = 0x8003, // MD5
+ SHA1 = 0x8004
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil/AssemblyLinkedResource.cs b/Mono.Cecil.20/Mono.Cecil/AssemblyLinkedResource.cs
new file mode 100644
index 00000000..f4896bd2
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil/AssemblyLinkedResource.cs
@@ -0,0 +1,39 @@
+//
+// 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;
+
+namespace Mono.Cecil {
+
+ public sealed class AssemblyLinkedResource : Resource {
+
+ AssemblyNameReference reference;
+
+ public AssemblyNameReference Assembly {
+ get { return reference; }
+ set { reference = value; }
+ }
+
+ public override ResourceType ResourceType {
+ get { return ResourceType.AssemblyLinked; }
+ }
+
+ public AssemblyLinkedResource (string name, ManifestResourceAttributes flags)
+ : base (name, flags)
+ {
+ }
+
+ public AssemblyLinkedResource (string name, ManifestResourceAttributes flags, AssemblyNameReference reference)
+ : base (name, flags)
+ {
+ this.reference = reference;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil/AssemblyNameDefinition.cs b/Mono.Cecil.20/Mono.Cecil/AssemblyNameDefinition.cs
new file mode 100644
index 00000000..2511d793
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil/AssemblyNameDefinition.cs
@@ -0,0 +1,32 @@
+//
+// 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;
+
+namespace Mono.Cecil {
+
+ public sealed class AssemblyNameDefinition : AssemblyNameReference {
+
+ public override byte [] Hash {
+ get { return Empty.Array; }
+ }
+
+ internal AssemblyNameDefinition ()
+ {
+ this.token = new MetadataToken (TokenType.Assembly, 1);
+ }
+
+ public AssemblyNameDefinition (string name, Version version)
+ : base (name, version)
+ {
+ this.token = new MetadataToken (TokenType.Assembly, 1);
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil/AssemblyNameReference.cs b/Mono.Cecil.20/Mono.Cecil/AssemblyNameReference.cs
new file mode 100644
index 00000000..1d12cc16
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil/AssemblyNameReference.cs
@@ -0,0 +1,266 @@
+//
+// 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.Globalization;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Mono.Cecil {
+
+ public class AssemblyNameReference : IMetadataScope {
+
+ string name;
+ string culture;
+ Version version;
+ uint attributes;
+ byte [] public_key;
+ byte [] public_key_token;
+ AssemblyHashAlgorithm hash_algorithm;
+ byte [] hash;
+
+ internal MetadataToken token;
+
+ string full_name;
+
+ public string Name {
+ get { return name; }
+ set {
+ name = value;
+ full_name = null;
+ }
+ }
+
+ public string Culture {
+ get { return culture; }
+ set {
+ culture = value;
+ full_name = null;
+ }
+ }
+
+ public Version Version {
+ get { return version; }
+ set {
+ version = Mixin.CheckVersion (value);
+ full_name = null;
+ }
+ }
+
+ public AssemblyAttributes Attributes {
+ get { return (AssemblyAttributes) attributes; }
+ set { attributes = (uint) value; }
+ }
+
+ public bool HasPublicKey {
+ get { return attributes.GetAttributes ((uint) AssemblyAttributes.PublicKey); }
+ set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.PublicKey, value); }
+ }
+
+ public bool IsSideBySideCompatible {
+ get { return attributes.GetAttributes ((uint) AssemblyAttributes.SideBySideCompatible); }
+ set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.SideBySideCompatible, value); }
+ }
+
+ public bool IsRetargetable {
+ get { return attributes.GetAttributes ((uint) AssemblyAttributes.Retargetable); }
+ set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.Retargetable, value); }
+ }
+
+ public bool IsWindowsRuntime {
+ get { return attributes.GetAttributes ((uint) AssemblyAttributes.WindowsRuntime); }
+ set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.WindowsRuntime, value); }
+ }
+
+ public byte [] PublicKey {
+ get { return public_key ?? Empty.Array; }
+ set {
+ public_key = value;
+ HasPublicKey = !public_key.IsNullOrEmpty ();
+ public_key_token = Empty.Array;
+ full_name = null;
+ }
+ }
+
+ public byte [] PublicKeyToken {
+ get {
+ if (public_key_token.IsNullOrEmpty () && !public_key.IsNullOrEmpty ()) {
+ var hash = HashPublicKey ();
+ // we need the last 8 bytes in reverse order
+ var local_public_key_token = new byte [8];
+ Array.Copy (hash, (hash.Length - 8), local_public_key_token, 0, 8);
+ Array.Reverse (local_public_key_token, 0, 8);
+ public_key_token = local_public_key_token; // publish only once finished (required for thread-safety)
+ }
+ return public_key_token ?? Empty.Array;
+ }
+ set {
+ public_key_token = value;
+ full_name = null;
+ }
+ }
+
+ byte [] HashPublicKey ()
+ {
+ HashAlgorithm algorithm;
+
+ switch (hash_algorithm) {
+ case AssemblyHashAlgorithm.Reserved:
+ algorithm = MD5.Create ();
+ break;
+ default:
+ // None default to SHA1
+ algorithm = SHA1.Create ();
+ break;
+ }
+
+ using (algorithm)
+ return algorithm.ComputeHash (public_key);
+ }
+
+ public virtual MetadataScopeType MetadataScopeType {
+ get { return MetadataScopeType.AssemblyNameReference; }
+ }
+
+ public string FullName {
+ get {
+ if (full_name != null)
+ return full_name;
+
+ const string sep = ", ";
+
+ var builder = new StringBuilder ();
+ builder.Append (name);
+ builder.Append (sep);
+ builder.Append ("Version=");
+ builder.Append (version.ToString (fieldCount: 4));
+ builder.Append (sep);
+ builder.Append ("Culture=");
+ builder.Append (string.IsNullOrEmpty (culture) ? "neutral" : culture);
+ builder.Append (sep);
+ builder.Append ("PublicKeyToken=");
+
+ var pk_token = PublicKeyToken;
+ if (!pk_token.IsNullOrEmpty () && pk_token.Length > 0) {
+ for (int i = 0 ; i < pk_token.Length ; i++) {
+ builder.Append (pk_token [i].ToString ("x2"));
+ }
+ } else
+ builder.Append ("null");
+
+ if (IsRetargetable) {
+ builder.Append (sep);
+ builder.Append ("Retargetable=Yes");
+ }
+
+ return full_name = builder.ToString ();
+ }
+ }
+
+ public static AssemblyNameReference Parse (string fullName)
+ {
+ if (fullName == null)
+ throw new ArgumentNullException ("fullName");
+ if (fullName.Length == 0)
+ throw new ArgumentException ("Name can not be empty");
+
+ var name = new AssemblyNameReference ();
+ var tokens = fullName.Split (',');
+ for (int i = 0; i < tokens.Length; i++) {
+ var token = tokens [i].Trim ();
+
+ if (i == 0) {
+ name.Name = token;
+ continue;
+ }
+
+ var parts = token.Split ('=');
+ if (parts.Length != 2)
+ throw new ArgumentException ("Malformed name");
+
+ switch (parts [0].ToLowerInvariant ()) {
+ case "version":
+ name.Version = new Version (parts [1]);
+ break;
+ case "culture":
+ name.Culture = parts [1] == "neutral" ? "" : parts [1];
+ break;
+ case "publickeytoken":
+ var pk_token = parts [1];
+ if (pk_token == "null")
+ break;
+
+ name.PublicKeyToken = new byte [pk_token.Length / 2];
+ for (int j = 0; j < name.PublicKeyToken.Length; j++)
+ name.PublicKeyToken [j] = Byte.Parse (pk_token.Substring (j * 2, 2), NumberStyles.HexNumber);
+
+ break;
+ }
+ }
+
+ return name;
+ }
+
+ public AssemblyHashAlgorithm HashAlgorithm {
+ get { return hash_algorithm; }
+ set { hash_algorithm = value; }
+ }
+
+ public virtual byte [] Hash {
+ get { return hash; }
+ set { hash = value; }
+ }
+
+ public MetadataToken MetadataToken {
+ get { return token; }
+ set { token = value; }
+ }
+
+ internal AssemblyNameReference ()
+ {
+ this.version = Mixin.ZeroVersion;
+ this.token = new MetadataToken (TokenType.AssemblyRef);
+ }
+
+ public AssemblyNameReference (string name, Version version)
+ {
+ Mixin.CheckName (name);
+
+ this.name = name;
+ this.version = Mixin.CheckVersion (version);
+ this.hash_algorithm = AssemblyHashAlgorithm.None;
+ this.token = new MetadataToken (TokenType.AssemblyRef);
+ }
+
+ public override string ToString ()
+ {
+ return this.FullName;
+ }
+ }
+
+ partial class Mixin {
+
+ public static Version ZeroVersion = new Version (0, 0, 0 ,0);
+
+ public static Version CheckVersion (Version version)
+ {
+ if (version == null)
+ return ZeroVersion;
+
+ if (version.Build == -1)
+ return new Version (version.Major, version.Minor, 0, 0);
+
+ if (version.Revision == -1)
+ return new Version (version.Major, version.Minor, version.Build, 0);
+
+ return version;
+ }
+ }
+}
diff --git a/Mono.Cecil.20/Mono.Cecil/AssemblyReader.cs b/Mono.Cecil.20/Mono.Cecil/AssemblyReader.cs
new file mode 100644
index 00000000..752a49e6
--- /dev/null
+++ b/Mono.Cecil.20/Mono.Cecil/AssemblyReader.cs
@@ -0,0 +1,3892 @@
+//
+// 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.IO;
+using System.IO.Compression;
+using System.Text;
+
+using Mono.Collections.Generic;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Metadata;
+using Mono.Cecil.PE;
+
+using RVA = System.UInt32;
+
+namespace Mono.Cecil {
+
+ abstract class ModuleReader {
+
+ readonly protected ModuleDefinition module;
+
+ protected ModuleReader (Image image, ReadingMode mode)
+ {
+ this.module = new ModuleDefinition (image);
+ this.module.ReadingMode = mode;
+ }
+
+ protected abstract void ReadModule ();
+ public abstract void ReadSymbols (ModuleDefinition module);
+
+ protected void ReadModuleManifest (MetadataReader reader)
+ {
+ reader.Populate (module);
+
+ ReadAssembly (reader);
+ }
+
+ void ReadAssembly (MetadataReader reader)
+ {
+ var name = reader.ReadAssemblyNameDefinition ();
+ if (name == null) {
+ module.kind = ModuleKind.NetModule;
+ return;
+ }
+
+ var assembly = new AssemblyDefinition ();
+ assembly.Name = name;
+
+ module.assembly = assembly;
+ assembly.main_module = module;
+ }
+
+ public static ModuleDefinition CreateModule (Image image, ReaderParameters parameters)
+ {
+ var reader = CreateModuleReader (image, parameters.ReadingMode);
+ var module = reader.module;
+
+ if (parameters.assembly_resolver != null)
+ module.assembly_resolver = Disposable.NotOwned (parameters.assembly_resolver);
+
+ if (parameters.metadata_resolver != null)
+ module.metadata_resolver = parameters.metadata_resolver;
+
+#if !READ_ONLY
+ if (parameters.metadata_importer_provider != null)
+ module.metadata_importer = parameters.metadata_importer_provider.GetMetadataImporter (module);
+ if (parameters.reflection_importer_provider != null)
+ module.reflection_importer = parameters.reflection_importer_provider.GetReflectionImporter (module);
+#endif
+
+ GetMetadataKind (module, parameters);
+
+ reader.ReadModule ();
+
+ ReadSymbols (module, parameters);
+
+ reader.ReadSymbols (module);
+
+ if (parameters.ReadingMode == ReadingMode.Immediate)
+ module.MetadataSystem.Clear ();
+
+ return module;
+ }
+
+ static void ReadSymbols (ModuleDefinition module, ReaderParameters parameters)
+ {
+ var symbol_reader_provider = parameters.SymbolReaderProvider;
+
+ if (symbol_reader_provider == null && parameters.ReadSymbols)
+ symbol_reader_provider = new DefaultSymbolReaderProvider ();
+
+ if (symbol_reader_provider != null) {
+ module.SymbolReaderProvider = symbol_reader_provider;
+
+ var reader = parameters.SymbolStream != null
+ ? symbol_reader_provider.GetSymbolReader (module, parameters.SymbolStream)
+ : symbol_reader_provider.GetSymbolReader (module, module.FileName);
+
+ if (reader != null)
+ module.ReadSymbols (reader);
+ }
+
+ if (module.Image.HasDebugTables ())
+ module.ReadSymbols (new PortablePdbReader (module.Image, module));
+ }
+
+ static void GetMetadataKind (ModuleDefinition module, ReaderParameters parameters)
+ {
+ if (!parameters.ApplyWindowsRuntimeProjections) {
+ module.MetadataKind = MetadataKind.Ecma335;
+ return;
+ }
+
+ var runtime_version = module.RuntimeVersion;
+
+ if (!runtime_version.Contains ("WindowsRuntime"))
+ module.MetadataKind = MetadataKind.Ecma335;
+ else if (runtime_version.Contains ("CLR"))
+ module.MetadataKind = MetadataKind.ManagedWindowsMetadata;
+ else
+ module.MetadataKind = MetadataKind.WindowsMetadata;
+ }
+
+ static ModuleReader CreateModuleReader (Image image, ReadingMode mode)
+ {
+ switch (mode) {
+ case ReadingMode.Immediate:
+ return new ImmediateModuleReader (image);
+ case ReadingMode.Deferred:
+ return new DeferredModuleReader (image);
+ default:
+ throw new ArgumentException ();
+ }
+ }
+ }
+
+ sealed class ImmediateModuleReader : ModuleReader {
+
+ bool resolve_attributes;
+
+ public ImmediateModuleReader (Image image)
+ : base (image, ReadingMode.Immediate)
+ {
+ }
+
+ protected override void ReadModule ()
+ {
+ this.module.Read (this.module, (module, reader) => {
+ ReadModuleManifest (reader);
+ ReadModule (module, resolve_attributes: true);
+ return module;
+ });
+ }
+
+ public void ReadModule (ModuleDefinition module, bool resolve_attributes)
+ {
+ this.resolve_attributes = resolve_attributes;
+
+ if (module.HasAssemblyReferences)
+ Mixin.Read (module.AssemblyReferences);
+ if (module.HasResources)
+ Mixin.Read (module.Resources);
+ if (module.HasModuleReferences)
+ Mixin.Read (module.ModuleReferences);
+ if (module.HasTypes)
+ ReadTypes (module.Types);
+ if (module.HasExportedTypes)
+ Mixin.Read (module.ExportedTypes);
+
+ ReadCustomAttributes (module);
+
+ var assembly = module.Assembly;
+ if (assembly == null)
+ return;
+
+ ReadCustomAttributes (assembly);
+ ReadSecurityDeclarations (assembly);
+ }
+
+ void ReadTypes (Collection types)
+ {
+ for (int i = 0; i < types.Count; i++)
+ ReadType (types [i]);
+ }
+
+ void ReadType (TypeDefinition type)
+ {
+ ReadGenericParameters (type);
+
+ if (type.HasInterfaces)
+ ReadInterfaces (type);
+
+ if (type.HasNestedTypes)
+ ReadTypes (type.NestedTypes);
+
+ if (type.HasLayoutInfo)
+ Mixin.Read (type.ClassSize);
+
+ if (type.HasFields)
+ ReadFields (type);
+
+ if (type.HasMethods)
+ ReadMethods (type);
+
+ if (type.HasProperties)
+ ReadProperties (type);
+
+ if (type.HasEvents)
+ ReadEvents (type);
+
+ ReadSecurityDeclarations (type);
+ ReadCustomAttributes (type);
+ }
+
+ void ReadInterfaces (TypeDefinition type)
+ {
+ var interfaces = type.Interfaces;
+
+ for (int i = 0; i < interfaces.Count; i++)
+ ReadCustomAttributes (interfaces [i]);
+ }
+
+ void ReadGenericParameters (IGenericParameterProvider provider)
+ {
+ if (!provider.HasGenericParameters)
+ return;
+
+ var parameters = provider.GenericParameters;
+
+ for (int i = 0; i < parameters.Count; i++) {
+ var parameter = parameters [i];
+
+ if (parameter.HasConstraints)
+ Mixin.Read (parameter.Constraints);
+
+ ReadCustomAttributes (parameter);
+ }
+ }
+
+ void ReadSecurityDeclarations (ISecurityDeclarationProvider provider)
+ {
+ if (!provider.HasSecurityDeclarations)
+ return;
+
+ var security_declarations = provider.SecurityDeclarations;
+
+ if (!resolve_attributes)
+ return;
+
+ for (int i = 0; i < security_declarations.Count; i++) {
+ var security_declaration = security_declarations [i];
+
+ Mixin.Read (security_declaration.SecurityAttributes);
+ }
+ }
+
+ void ReadCustomAttributes (ICustomAttributeProvider provider)
+ {
+ if (!provider.HasCustomAttributes)
+ return;
+
+ var custom_attributes = provider.CustomAttributes;
+
+ if (!resolve_attributes)
+ return;
+
+ for (int i = 0; i < custom_attributes.Count; i++) {
+ var custom_attribute = custom_attributes [i];
+
+ Mixin.Read (custom_attribute.ConstructorArguments);
+ }
+ }
+
+ void ReadFields (TypeDefinition type)
+ {
+ var fields = type.Fields;
+
+ for (int i = 0; i < fields.Count; i++) {
+ var field = fields [i];
+
+ if (field.HasConstant)
+ Mixin.Read (field.Constant);
+
+ if (field.HasLayoutInfo)
+ Mixin.Read (field.Offset);
+
+ if (field.RVA > 0)
+ Mixin.Read (field.InitialValue);
+
+ if (field.HasMarshalInfo)
+ Mixin.Read (field.MarshalInfo);
+
+ ReadCustomAttributes (field);
+ }
+ }
+
+ void ReadMethods (TypeDefinition type)
+ {
+ var methods = type.Methods;
+
+ for (int i = 0; i < methods.Count; i++) {
+ var method = methods [i];
+
+ ReadGenericParameters (method);
+
+ if (method.HasParameters)
+ ReadParameters (method);
+
+ if (method.HasOverrides)
+ Mixin.Read (method.Overrides);
+
+ if (method.IsPInvokeImpl)
+ Mixin.Read (method.PInvokeInfo);
+
+ ReadSecurityDeclarations (method);
+ ReadCustomAttributes (method);
+
+ var return_type = method.MethodReturnType;
+ if (return_type.HasConstant)
+ Mixin.Read (return_type.Constant);
+
+ if (return_type.HasMarshalInfo)
+ Mixin.Read (return_type.MarshalInfo);
+
+ ReadCustomAttributes (return_type);
+ }
+ }
+
+ void ReadParameters (MethodDefinition method)
+ {
+ var parameters = method.Parameters;
+
+ for (int i = 0; i < parameters.Count; i++) {
+ var parameter = parameters [i];
+
+ if (parameter.HasConstant)
+ Mixin.Read (parameter.Constant);
+
+ if (parameter.HasMarshalInfo)
+ Mixin.Read (parameter.MarshalInfo);
+
+ ReadCustomAttributes (parameter);
+ }
+ }
+
+ void ReadProperties (TypeDefinition type)
+ {
+ var properties = type.Properties;
+
+ for (int i = 0; i < properties.Count; i++) {
+ var property = properties [i];
+
+ Mixin.Read (property.GetMethod);
+
+ if (property.HasConstant)
+ Mixin.Read (property.Constant);
+
+ ReadCustomAttributes (property);
+ }
+ }
+
+ void ReadEvents (TypeDefinition type)
+ {
+ var events = type.Events;
+
+ for (int i = 0; i < events.Count; i++) {
+ var @event = events [i];
+
+ Mixin.Read (@event.AddMethod);
+
+ ReadCustomAttributes (@event);
+ }
+ }
+
+ public override void ReadSymbols (ModuleDefinition module)
+ {
+ if (module.symbol_reader == null)
+ return;
+
+ ReadTypesSymbols (module.Types, module.symbol_reader);
+ }
+
+ void ReadTypesSymbols (Collection types, ISymbolReader symbol_reader)
+ {
+ for (int i = 0; i < types.Count; i++) {
+ var type = types [i];
+
+ if (type.HasNestedTypes)
+ ReadTypesSymbols (type.NestedTypes, symbol_reader);
+
+ if (type.HasMethods)
+ ReadMethodsSymbols (type, symbol_reader);
+ }
+ }
+
+ void ReadMethodsSymbols (TypeDefinition type, ISymbolReader symbol_reader)
+ {
+ var methods = type.Methods;
+ for (int i = 0; i < methods.Count; i++) {
+ var method = methods [i];
+
+ if (method.HasBody && method.token.RID != 0 && method.debug_info == null)
+ method.debug_info = symbol_reader.Read (method);
+ }
+ }
+ }
+
+ sealed class DeferredModuleReader : ModuleReader {
+
+ public DeferredModuleReader (Image image)
+ : base (image, ReadingMode.Deferred)
+ {
+ }
+
+ protected override void ReadModule ()
+ {
+ this.module.Read (this.module, (module, reader) => {
+ ReadModuleManifest (reader);
+ return module;
+ });
+ }
+
+ public override void ReadSymbols (ModuleDefinition module)
+ {
+ }
+ }
+
+ sealed class MetadataReader : ByteBuffer {
+
+ readonly internal Image image;
+ readonly internal ModuleDefinition module;
+ readonly internal MetadataSystem metadata;
+
+ internal CodeReader code;
+ internal IGenericContext context;
+
+ readonly MetadataReader metadata_reader;
+
+ public MetadataReader (ModuleDefinition module)
+ : base (module.Image.TableHeap.data)
+ {
+ this.image = module.Image;
+ this.module = module;
+ this.metadata = module.MetadataSystem;
+ this.code = new CodeReader (this);
+ }
+
+ public MetadataReader (Image image, ModuleDefinition module, MetadataReader metadata_reader)
+ : base (image.TableHeap.data)
+ {
+ this.image = image;
+ this.module = module;
+ this.metadata = module.MetadataSystem;
+ this.metadata_reader = metadata_reader;
+ }
+
+ int GetCodedIndexSize (CodedIndex index)
+ {
+ return image.GetCodedIndexSize (index);
+ }
+
+ uint ReadByIndexSize (int size)
+ {
+ if (size == 4)
+ return ReadUInt32 ();
+ else
+ return ReadUInt16 ();
+ }
+
+ byte [] ReadBlob ()
+ {
+ var blob_heap = image.BlobHeap;
+ if (blob_heap == null) {
+ position += 2;
+ return Empty.Array;
+ }
+
+ return blob_heap.Read (ReadBlobIndex ());
+ }
+
+ byte [] ReadBlob (uint signature)
+ {
+ var blob_heap = image.BlobHeap;
+ if (blob_heap == null)
+ return Empty.Array;
+
+ return blob_heap.Read (signature);
+ }
+
+ uint ReadBlobIndex ()
+ {
+ var blob_heap = image.BlobHeap;
+ return ReadByIndexSize (blob_heap != null ? blob_heap.IndexSize : 2);
+ }
+
+ void GetBlobView (uint signature, out byte [] blob, out int index, out int count)
+ {
+ var blob_heap = image.BlobHeap;
+ if (blob_heap == null) {
+ blob = null;
+ index = count = 0;
+ return;
+ }
+
+ blob_heap.GetView (signature, out blob, out index, out count);
+ }
+
+ string ReadString ()
+ {
+ return image.StringHeap.Read (ReadByIndexSize (image.StringHeap.IndexSize));
+ }
+
+ uint ReadStringIndex ()
+ {
+ return ReadByIndexSize (image.StringHeap.IndexSize);
+ }
+
+ Guid ReadGuid ()
+ {
+ return image.GuidHeap.Read (ReadByIndexSize (image.GuidHeap.IndexSize));
+ }
+
+ uint ReadTableIndex (Table table)
+ {
+ return ReadByIndexSize (image.GetTableIndexSize (table));
+ }
+
+ MetadataToken ReadMetadataToken (CodedIndex index)
+ {
+ return index.GetMetadataToken (ReadByIndexSize (GetCodedIndexSize (index)));
+ }
+
+ int MoveTo (Table table)
+ {
+ var info = image.TableHeap [table];
+ if (info.Length != 0)
+ this.position = (int) info.Offset;
+
+ return (int) info.Length;
+ }
+
+ bool MoveTo (Table table, uint row)
+ {
+ var info = image.TableHeap [table];
+ var length = info.Length;
+ if (length == 0 || row > length)
+ return false;
+
+ this.position = (int) (info.Offset + (info.RowSize * (row - 1)));
+ return true;
+ }
+
+ public AssemblyNameDefinition ReadAssemblyNameDefinition ()
+ {
+ if (MoveTo (Table.Assembly) == 0)
+ return null;
+
+ var name = new AssemblyNameDefinition ();
+
+ name.HashAlgorithm = (AssemblyHashAlgorithm) ReadUInt32 ();
+
+ PopulateVersionAndFlags (name);
+
+ name.PublicKey = ReadBlob ();
+
+ PopulateNameAndCulture (name);
+
+ return name;
+ }
+
+ public ModuleDefinition Populate (ModuleDefinition module)
+ {
+ if (MoveTo (Table.Module) == 0)
+ return module;
+
+ Advance (2); // Generation
+
+ module.Name = ReadString ();
+ module.Mvid = ReadGuid ();
+
+ return module;
+ }
+
+ void InitializeAssemblyReferences ()
+ {
+ if (metadata.AssemblyReferences != null)
+ return;
+
+ int length = MoveTo (Table.AssemblyRef);
+ var references = metadata.AssemblyReferences = new AssemblyNameReference [length];
+
+ for (uint i = 0; i < length; i++) {
+ var reference = new AssemblyNameReference ();
+ reference.token = new MetadataToken (TokenType.AssemblyRef, i + 1);
+
+ PopulateVersionAndFlags (reference);
+
+ var key_or_token = ReadBlob ();
+
+ if (reference.HasPublicKey)
+ reference.PublicKey = key_or_token;
+ else
+ reference.PublicKeyToken = key_or_token;
+
+ PopulateNameAndCulture (reference);
+
+ reference.Hash = ReadBlob ();
+
+ references [i] = reference;
+ }
+ }
+
+ public Collection ReadAssemblyReferences ()
+ {
+ InitializeAssemblyReferences ();
+
+ var references = new Collection (metadata.AssemblyReferences);
+ if (module.IsWindowsMetadata ())
+ module.Projections.AddVirtualReferences (references);
+
+ return references;
+ }
+
+ public MethodDefinition ReadEntryPoint ()
+ {
+ if (module.Image.EntryPointToken == 0)
+ return null;
+
+ var token = new MetadataToken (module.Image.EntryPointToken);
+ return GetMethodDefinition (token.RID);
+ }
+
+ public Collection ReadModules ()
+ {
+ var modules = new Collection (1);
+ modules.Add (this.module);
+
+ int length = MoveTo (Table.File);
+ for (uint i = 1; i <= length; i++) {
+ var attributes = (FileAttributes) ReadUInt32 ();
+ var name = ReadString ();
+ ReadBlobIndex ();
+
+ if (attributes != FileAttributes.ContainsMetaData)
+ continue;
+
+ var parameters = new ReaderParameters {
+ ReadingMode = module.ReadingMode,
+ SymbolReaderProvider = module.SymbolReaderProvider,
+ AssemblyResolver = module.AssemblyResolver
+ };
+
+ modules.Add (ModuleDefinition.ReadModule (
+ GetModuleFileName (name), parameters));
+ }
+
+ return modules;
+ }
+
+ string GetModuleFileName (string name)
+ {
+ if (module.FileName == null)
+ throw new NotSupportedException ();
+
+ var path = Path.GetDirectoryName (module.FileName);
+ return Path.Combine (path, name);
+ }
+
+ void InitializeModuleReferences ()
+ {
+ if (metadata.ModuleReferences != null)
+ return;
+
+ int length = MoveTo (Table.ModuleRef);
+ var references = metadata.ModuleReferences = new ModuleReference [length];
+
+ for (uint i = 0; i < length; i++) {
+ var reference = new ModuleReference (ReadString ());
+ reference.token = new MetadataToken (TokenType.ModuleRef, i + 1);
+
+ references [i] = reference;
+ }
+ }
+
+ public Collection ReadModuleReferences ()
+ {
+ InitializeModuleReferences ();
+
+ return new Collection (metadata.ModuleReferences);
+ }
+
+ public bool HasFileResource ()
+ {
+ int length = MoveTo (Table.File);
+ if (length == 0)
+ return false;
+
+ for (uint i = 1; i <= length; i++)
+ if (ReadFileRecord (i).Col1 == FileAttributes.ContainsNoMetaData)
+ return true;
+
+ return false;
+ }
+
+ public Collection ReadResources ()
+ {
+ int length = MoveTo (Table.ManifestResource);
+ var resources = new Collection (length);
+
+ for (int i = 1; i <= length; i++) {
+ var offset = ReadUInt32 ();
+ var flags = (ManifestResourceAttributes) ReadUInt32 ();
+ var name = ReadString ();
+ var implementation = ReadMetadataToken (CodedIndex.Implementation);
+
+ Resource resource;
+
+ if (implementation.RID == 0) {
+ resource = new EmbeddedResource (name, flags, offset, this);
+ } else if (implementation.TokenType == TokenType.AssemblyRef) {
+ resource = new AssemblyLinkedResource (name, flags) {
+ Assembly = (AssemblyNameReference) GetTypeReferenceScope (implementation),
+ };
+ } else if (implementation.TokenType == TokenType.File) {
+ var file_record = ReadFileRecord (implementation.RID);
+
+ resource = new LinkedResource (name, flags) {
+ File = file_record.Col2,
+ hash = ReadBlob (file_record.Col3)
+ };
+ } else
+ continue;
+
+ resources.Add (resource);
+ }
+
+ return resources;
+ }
+
+ Row ReadFileRecord (uint rid)
+ {
+ var position = this.position;
+
+ if (!MoveTo (Table.File, rid))
+ throw new ArgumentException ();
+
+ var record = new Row (
+ (FileAttributes) ReadUInt32 (),
+ ReadString (),
+ ReadBlobIndex ());
+
+ this.position = position;
+
+ return record;
+ }
+
+ public byte [] GetManagedResource (uint offset)
+ {
+ return image.GetReaderAt (image.Resources.VirtualAddress, offset, (o, reader) => {
+ reader.Advance ((int) o);
+ return reader.ReadBytes (reader.ReadInt32 ());
+ }) ?? Empty.Array;
+ }
+
+ void PopulateVersionAndFlags (AssemblyNameReference name)
+ {
+ name.Version = new Version (
+ ReadUInt16 (),
+ ReadUInt16 (),
+ ReadUInt16 (),
+ ReadUInt16 ());
+
+ name.Attributes = (AssemblyAttributes) ReadUInt32 ();
+ }
+
+ void PopulateNameAndCulture (AssemblyNameReference name)
+ {
+ name.Name = ReadString ();
+ name.Culture = ReadString ();
+ }
+
+ public TypeDefinitionCollection ReadTypes ()
+ {
+ InitializeTypeDefinitions ();
+ var mtypes = metadata.Types;
+ var type_count = mtypes.Length - metadata.NestedTypes.Count;
+ var types = new TypeDefinitionCollection (module, type_count);
+
+ for (int i = 0; i < mtypes.Length; i++) {
+ var type = mtypes [i];
+ if (IsNested (type.Attributes))
+ continue;
+
+ types.Add (type);
+ }
+
+ if (image.HasTable (Table.MethodPtr) || image.HasTable (Table.FieldPtr))
+ CompleteTypes ();
+
+ return types;
+ }
+
+ void CompleteTypes ()
+ {
+ var types = metadata.Types;
+
+ for (int i = 0; i < types.Length; i++) {
+ var type = types [i];
+
+ Mixin.Read (type.Fields);
+ Mixin.Read (type.Methods);
+ }
+ }
+
+ void InitializeTypeDefinitions ()
+ {
+ if (metadata.Types != null)
+ return;
+
+ InitializeNestedTypes ();
+ InitializeFields ();
+ InitializeMethods ();
+
+ int length = MoveTo (Table.TypeDef);
+ var types = metadata.Types = new TypeDefinition [length];
+
+ for (uint i = 0; i < length; i++) {
+ if (types [i] != null)
+ continue;
+
+ types [i] = ReadType (i + 1);
+ }
+ }
+
+ static bool IsNested (TypeAttributes attributes)
+ {
+ switch (attributes & TypeAttributes.VisibilityMask) {
+ case TypeAttributes.NestedAssembly:
+ case TypeAttributes.NestedFamANDAssem:
+ case TypeAttributes.NestedFamily:
+ case TypeAttributes.NestedFamORAssem:
+ case TypeAttributes.NestedPrivate:
+ case TypeAttributes.NestedPublic:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public bool HasNestedTypes (TypeDefinition type)
+ {
+ Collection mapping;
+ InitializeNestedTypes ();
+
+ if (!metadata.TryGetNestedTypeMapping (type, out mapping))
+ return false;
+
+ return mapping.Count > 0;
+ }
+
+ public Collection ReadNestedTypes (TypeDefinition type)
+ {
+ InitializeNestedTypes ();
+ Collection mapping;
+ if (!metadata.TryGetNestedTypeMapping (type, out mapping))
+ return new MemberDefinitionCollection (type);
+
+ var nested_types = new MemberDefinitionCollection (type, mapping.Count);
+
+ for (int i = 0; i < mapping.Count; i++) {
+ var nested_type = GetTypeDefinition (mapping [i]);
+
+ if (nested_type != null)
+ nested_types.Add (nested_type);
+ }
+
+ metadata.RemoveNestedTypeMapping (type);
+
+ return nested_types;
+ }
+
+ void InitializeNestedTypes ()
+ {
+ if (metadata.NestedTypes != null)
+ return;
+
+ var length = MoveTo (Table.NestedClass);
+
+ metadata.NestedTypes = new Dictionary> (length);
+ metadata.ReverseNestedTypes = new Dictionary (length);
+
+ if (length == 0)
+ return;
+
+ for (int i = 1; i <= length; i++) {
+ var nested = ReadTableIndex (Table.TypeDef);
+ var declaring = ReadTableIndex (Table.TypeDef);
+
+ AddNestedMapping (declaring, nested);
+ }
+ }
+
+ void AddNestedMapping (uint declaring, uint nested)
+ {
+ metadata.SetNestedTypeMapping (declaring, AddMapping (metadata.NestedTypes, declaring, nested));
+ metadata.SetReverseNestedTypeMapping (nested, declaring);
+ }
+
+ static Collection AddMapping (Dictionary> cache, TKey key, TValue value)
+ {
+ Collection mapped;
+ if (!cache.TryGetValue (key, out mapped)) {
+ mapped = new Collection ();
+ }
+ mapped.Add (value);
+ return mapped;
+ }
+
+ TypeDefinition ReadType (uint rid)
+ {
+ if (!MoveTo (Table.TypeDef, rid))
+ return null;
+
+ var attributes = (TypeAttributes) ReadUInt32 ();
+ var name = ReadString ();
+ var @namespace = ReadString ();
+ var type = new TypeDefinition (@namespace, name, attributes);
+ type.token = new MetadataToken (TokenType.TypeDef, rid);
+ type.scope = module;
+ type.module = module;
+
+ metadata.AddTypeDefinition (type);
+
+ this.context = type;
+
+ type.BaseType = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef));
+
+ type.fields_range = ReadListRange (rid, Table.TypeDef, Table.Field);
+ type.methods_range = ReadListRange (rid, Table.TypeDef, Table.Method);
+
+ if (IsNested (attributes))
+ type.DeclaringType = GetNestedTypeDeclaringType (type);
+
+ if (module.IsWindowsMetadata ())
+ WindowsRuntimeProjections.Project (type);
+
+ return type;
+ }
+
+ TypeDefinition GetNestedTypeDeclaringType (TypeDefinition type)
+ {
+ uint declaring_rid;
+ if (!metadata.TryGetReverseNestedTypeMapping (type, out declaring_rid))
+ return null;
+
+ metadata.RemoveReverseNestedTypeMapping (type);
+ return GetTypeDefinition (declaring_rid);
+ }
+
+ Range ReadListRange (uint current_index, Table current, Table target)
+ {
+ var list = new Range ();
+
+ var start = ReadTableIndex (target);
+ if (start == 0)
+ return list;
+
+ uint next_index;
+ var current_table = image.TableHeap [current];
+
+ if (current_index == current_table.Length)
+ next_index = image.TableHeap [target].Length + 1;
+ else {
+ var position = this.position;
+ this.position += (int) (current_table.RowSize - image.GetTableIndexSize (target));
+ next_index = ReadTableIndex (target);
+ this.position = position;
+ }
+
+ list.Start = start;
+ list.Length = next_index - start;
+
+ return list;
+ }
+
+ public Row ReadTypeLayout (TypeDefinition type)
+ {
+ InitializeTypeLayouts ();
+ Row class_layout;
+ var rid = type.token.RID;
+ if (!metadata.ClassLayouts.TryGetValue (rid, out class_layout))
+ return new Row (Mixin.NoDataMarker, Mixin.NoDataMarker);
+
+ type.PackingSize = (short) class_layout.Col1;
+ type.ClassSize = (int) class_layout.Col2;
+
+ metadata.ClassLayouts.Remove (rid);
+
+ return new Row ((short) class_layout.Col1, (int) class_layout.Col2);
+ }
+
+ void InitializeTypeLayouts ()
+ {
+ if (metadata.ClassLayouts != null)
+ return;
+
+ int length = MoveTo (Table.ClassLayout);
+
+ var class_layouts = metadata.ClassLayouts = new Dictionary> (length);
+
+ for (uint i = 0; i < length; i++) {
+ var packing_size = ReadUInt16 ();
+ var class_size = ReadUInt32 ();
+
+ var parent = ReadTableIndex (Table.TypeDef);
+
+ class_layouts.Add (parent, new Row (packing_size, class_size));
+ }
+ }
+
+ public TypeReference GetTypeDefOrRef (MetadataToken token)
+ {
+ return (TypeReference) LookupToken (token);
+ }
+
+ public TypeDefinition GetTypeDefinition (uint rid)
+ {
+ InitializeTypeDefinitions ();
+
+ var type = metadata.GetTypeDefinition (rid);
+ if (type != null)
+ return type;
+
+ return ReadTypeDefinition (rid);
+ }
+
+ TypeDefinition ReadTypeDefinition (uint rid)
+ {
+ if (!MoveTo (Table.TypeDef, rid))
+ return null;
+
+ return ReadType (rid);
+ }
+
+ void InitializeTypeReferences ()
+ {
+ if (metadata.TypeReferences != null)
+ return;
+
+ metadata.TypeReferences = new TypeReference [image.GetTableLength (Table.TypeRef)];
+ }
+
+ public TypeReference GetTypeReference (string scope, string full_name)
+ {
+ InitializeTypeReferences ();
+
+ var length = metadata.TypeReferences.Length;
+
+ for (uint i = 1; i <= length; i++) {
+ var type = GetTypeReference (i);
+
+ if (type.FullName != full_name)
+ continue;
+
+ if (string.IsNullOrEmpty (scope))
+ return type;
+
+ if (type.Scope.Name == scope)
+ return type;
+ }
+
+ return null;
+ }
+
+ TypeReference GetTypeReference (uint rid)
+ {
+ InitializeTypeReferences ();
+
+ var type = metadata.GetTypeReference (rid);
+ if (type != null)
+ return type;
+
+ return ReadTypeReference (rid);
+ }
+
+ TypeReference ReadTypeReference (uint rid)
+ {
+ if (!MoveTo (Table.TypeRef, rid))
+ return null;
+
+ TypeReference declaring_type = null;
+ IMetadataScope scope;
+
+ var scope_token = ReadMetadataToken (CodedIndex.ResolutionScope);
+
+ var name = ReadString ();
+ var @namespace = ReadString ();
+
+ var type = new TypeReference (
+ @namespace,
+ name,
+ module,
+ null);
+
+ type.token = new MetadataToken (TokenType.TypeRef, rid);
+
+ metadata.AddTypeReference (type);
+
+ if (scope_token.TokenType == TokenType.TypeRef) {
+ declaring_type = GetTypeDefOrRef (scope_token);
+
+ scope = declaring_type != null
+ ? declaring_type.Scope
+ : module;
+ } else
+ scope = GetTypeReferenceScope (scope_token);
+
+ type.scope = scope;
+ type.DeclaringType = declaring_type;
+
+ MetadataSystem.TryProcessPrimitiveTypeReference (type);
+
+ if (type.Module.IsWindowsMetadata ())
+ WindowsRuntimeProjections.Project (type);
+
+ return type;
+ }
+
+ IMetadataScope GetTypeReferenceScope (MetadataToken scope)
+ {
+ if (scope.TokenType == TokenType.Module)
+ return module;
+
+ IMetadataScope[] scopes;
+
+ switch (scope.TokenType) {
+ case TokenType.AssemblyRef:
+ InitializeAssemblyReferences ();
+ scopes = metadata.AssemblyReferences;
+ break;
+ case TokenType.ModuleRef:
+ InitializeModuleReferences ();
+ scopes = metadata.ModuleReferences;
+ break;
+ default:
+ throw new NotSupportedException ();
+ }
+
+ var index = scope.RID - 1;
+ if (index < 0 || index >= scopes.Length)
+ return null;
+
+ return scopes [index];
+ }
+
+ public IEnumerable GetTypeReferences ()
+ {
+ InitializeTypeReferences ();
+
+ var length = image.GetTableLength (Table.TypeRef);
+
+ var type_references = new TypeReference [length];
+
+ for (uint i = 1; i <= length; i++)
+ type_references [i - 1] = GetTypeReference (i);
+
+ return type_references;
+ }
+
+ TypeReference GetTypeSpecification (uint rid)
+ {
+ if (!MoveTo (Table.TypeSpec, rid))
+ return null;
+
+ var reader = ReadSignature (ReadBlobIndex ());
+ var type = reader.ReadTypeSignature ();
+ if (type.token.RID == 0)
+ type.token = new MetadataToken (TokenType.TypeSpec, rid);
+
+ return type;
+ }
+
+ SignatureReader ReadSignature (uint signature)
+ {
+ return new SignatureReader (signature, this);
+ }
+
+ public bool HasInterfaces (TypeDefinition type)
+ {
+ InitializeInterfaces ();
+ Collection> mapping;
+
+ return metadata.TryGetInterfaceMapping (type, out mapping);
+ }
+
+ public InterfaceImplementationCollection ReadInterfaces (TypeDefinition type)
+ {
+ InitializeInterfaces ();
+ Collection> mapping;
+
+ if (!metadata.TryGetInterfaceMapping (type, out mapping))
+ return new InterfaceImplementationCollection (type);
+
+ var interfaces = new InterfaceImplementationCollection (type, mapping.Count);
+
+ this.context = type;
+
+ for (int i = 0; i < mapping.Count; i++) {
+ interfaces.Add (
+ new InterfaceImplementation (
+ GetTypeDefOrRef (mapping [i].Col2),
+ new MetadataToken(TokenType.InterfaceImpl, mapping [i].Col1)));
+ }
+
+ metadata.RemoveInterfaceMapping (type);
+
+ return interfaces;
+ }
+
+ void InitializeInterfaces ()
+ {
+ if (metadata.Interfaces != null)
+ return;
+
+ int length = MoveTo (Table.InterfaceImpl);
+
+ metadata.Interfaces = new Dictionary>> (length);
+
+ for (uint i = 1; i <= length; i++) {
+ var type = ReadTableIndex (Table.TypeDef);
+ var @interface = ReadMetadataToken (CodedIndex.TypeDefOrRef);
+
+ AddInterfaceMapping (type, new Row (i, @interface));
+ }
+ }
+
+ void AddInterfaceMapping (uint type, Row @interface)
+ {
+ metadata.SetInterfaceMapping (type, AddMapping (metadata.Interfaces, type, @interface));
+ }
+
+ public Collection ReadFields (TypeDefinition type)
+ {
+ var fields_range = type.fields_range;
+ if (fields_range.Length == 0)
+ return new MemberDefinitionCollection (type);
+
+ var fields = new MemberDefinitionCollection (type, (int) fields_range.Length);
+ this.context = type;
+
+ if (!MoveTo (Table.FieldPtr, fields_range.Start)) {
+ if (!MoveTo (Table.Field, fields_range.Start))
+ return fields;
+
+ for (uint i = 0; i < fields_range.Length; i++)
+ ReadField (fields_range.Start + i, fields);
+ } else
+ ReadPointers (Table.FieldPtr, Table.Field, fields_range, fields, ReadField);
+
+ return fields;
+ }
+
+ void ReadField (uint field_rid, Collection fields)
+ {
+ var attributes = (FieldAttributes) ReadUInt16 ();
+ var name = ReadString ();
+ var signature = ReadBlobIndex ();
+
+ var field = new FieldDefinition (name, attributes, ReadFieldType (signature));
+ field.token = new MetadataToken (TokenType.Field, field_rid);
+ metadata.AddFieldDefinition (field);
+
+ if (IsDeleted (field))
+ return;
+
+ fields.Add (field);
+
+ if (module.IsWindowsMetadata ())
+ WindowsRuntimeProjections.Project (field);
+ }
+
+ void InitializeFields ()
+ {
+ if (metadata.Fields != null)
+ return;
+
+ metadata.Fields = new FieldDefinition [image.GetTableLength (Table.Field)];
+ }
+
+ TypeReference ReadFieldType (uint signature)
+ {
+ var reader = ReadSignature (signature);
+
+ const byte field_sig = 0x6;
+
+ if (reader.ReadByte () != field_sig)
+ throw new NotSupportedException ();
+
+ return reader.ReadTypeSignature ();
+ }
+
+ public int ReadFieldRVA (FieldDefinition field)
+ {
+ InitializeFieldRVAs ();
+ var rid = field.token.RID;
+
+ RVA rva;
+ if (!metadata.FieldRVAs.TryGetValue (rid, out rva))
+ return 0;
+
+ var size = GetFieldTypeSize (field.FieldType);
+
+ if (size == 0 || rva == 0)
+ return 0;
+
+ metadata.FieldRVAs.Remove (rid);
+
+ field.InitialValue = GetFieldInitializeValue (size, rva);
+
+ return (int) rva;
+ }
+
+ byte [] GetFieldInitializeValue (int size, RVA rva)
+ {
+ return image.GetReaderAt (rva, size, (s, reader) => reader.ReadBytes (s)) ?? Empty.Array;
+ }
+
+ static int GetFieldTypeSize (TypeReference type)
+ {
+ int size = 0;
+
+ switch (type.etype) {
+ case ElementType.Boolean:
+ case ElementType.U1:
+ case ElementType.I1:
+ size = 1;
+ break;
+ case ElementType.U2:
+ case ElementType.I2:
+ case ElementType.Char:
+ size = 2;
+ break;
+ case ElementType.U4:
+ case ElementType.I4:
+ case ElementType.R4:
+ size = 4;
+ break;
+ case ElementType.U8:
+ case ElementType.I8:
+ case ElementType.R8:
+ size = 8;
+ break;
+ case ElementType.Ptr:
+ case ElementType.FnPtr:
+ size = IntPtr.Size;
+ break;
+ case ElementType.CModOpt:
+ case ElementType.CModReqD:
+ return GetFieldTypeSize (((IModifierType) type).ElementType);
+ default:
+ var field_type = type.Resolve ();
+ if (field_type != null && field_type.HasLayoutInfo)
+ size = field_type.ClassSize;
+
+ break;
+ }
+
+ return size;
+ }
+
+ void InitializeFieldRVAs ()
+ {
+ if (metadata.FieldRVAs != null)
+ return;
+
+ int length = MoveTo (Table.FieldRVA);
+
+ var field_rvas = metadata.FieldRVAs = new Dictionary (length);
+
+ for (int i = 0; i < length; i++) {
+ var rva = ReadUInt32 ();
+ var field = ReadTableIndex (Table.Field);
+
+ field_rvas.Add (field, rva);
+ }
+ }
+
+ public int ReadFieldLayout (FieldDefinition field)
+ {
+ InitializeFieldLayouts ();
+ var rid = field.token.RID;
+ uint offset;
+ if (!metadata.FieldLayouts.TryGetValue (rid, out offset))
+ return Mixin.NoDataMarker;
+
+ metadata.FieldLayouts.Remove (rid);
+
+ return (int) offset;
+ }
+
+ void InitializeFieldLayouts ()
+ {
+ if (metadata.FieldLayouts != null)
+ return;
+
+ int length = MoveTo (Table.FieldLayout);
+
+ var field_layouts = metadata.FieldLayouts = new Dictionary (length);
+
+ for (int i = 0; i < length; i++) {
+ var offset = ReadUInt32 ();
+ var field = ReadTableIndex (Table.Field);
+
+ field_layouts.Add (field, offset);
+ }
+ }
+
+ public bool HasEvents (TypeDefinition type)
+ {
+ InitializeEvents ();
+
+ Range range;
+ if (!metadata.TryGetEventsRange (type, out range))
+ return false;
+
+ return range.Length > 0;
+ }
+
+ public Collection ReadEvents (TypeDefinition type)
+ {
+ InitializeEvents ();
+ Range range;
+
+ if (!metadata.TryGetEventsRange (type, out range))
+ return new MemberDefinitionCollection (type);
+
+ var events = new MemberDefinitionCollection (type, (int) range.Length);
+
+ metadata.RemoveEventsRange (type);
+
+ if (range.Length == 0)
+ return events;
+
+ this.context = type;
+
+ if (!MoveTo (Table.EventPtr, range.Start)) {
+ if (!MoveTo (Table.Event, range.Start))
+ return events;
+
+ for (uint i = 0; i < range.Length; i++)
+ ReadEvent (range.Start + i, events);
+ } else
+ ReadPointers (Table.EventPtr, Table.Event, range, events, ReadEvent);
+
+ return events;
+ }
+
+ void ReadEvent (uint event_rid, Collection events)
+ {
+ var attributes = (EventAttributes) ReadUInt16 ();
+ var name = ReadString ();
+ var event_type = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef));
+
+ var @event = new EventDefinition (name, attributes, event_type);
+ @event.token = new MetadataToken (TokenType.Event, event_rid);
+
+ if (IsDeleted (@event))
+ return;
+
+ events.Add (@event);
+ }
+
+ void InitializeEvents ()
+ {
+ if (metadata.Events != null)
+ return;
+
+ int length = MoveTo (Table.EventMap);
+
+ metadata.Events = new Dictionary (length);
+
+ for (uint i = 1; i <= length; i++) {
+ var type_rid = ReadTableIndex (Table.TypeDef);
+ Range events_range = ReadListRange (i, Table.EventMap, Table.Event);
+ metadata.AddEventsRange (type_rid, events_range);
+ }
+ }
+
+ public bool HasProperties (TypeDefinition type)
+ {
+ InitializeProperties ();
+
+ Range range;
+ if (!metadata.TryGetPropertiesRange (type, out range))
+ return false;
+
+ return range.Length > 0;
+ }
+
+ public Collection ReadProperties (TypeDefinition type)
+ {
+ InitializeProperties ();
+
+ Range range;
+
+ if (!metadata.TryGetPropertiesRange (type, out range))
+ return new MemberDefinitionCollection (type);
+
+ metadata.RemovePropertiesRange (type);
+
+ var properties = new MemberDefinitionCollection (type, (int) range.Length);
+
+ if (range.Length == 0)
+ return properties;
+
+ this.context = type;
+
+ if (!MoveTo (Table.PropertyPtr, range.Start)) {
+ if (!MoveTo (Table.Property, range.Start))
+ return properties;
+ for (uint i = 0; i < range.Length; i++)
+ ReadProperty (range.Start + i, properties);
+ } else
+ ReadPointers (Table.PropertyPtr, Table.Property, range, properties, ReadProperty);
+
+ return properties;
+ }
+
+ void ReadProperty (uint property_rid, Collection properties)
+ {
+ var attributes = (PropertyAttributes) ReadUInt16 ();
+ var name = ReadString ();
+ var signature = ReadBlobIndex ();
+
+ var reader = ReadSignature (signature);
+ const byte property_signature = 0x8;
+
+ var calling_convention = reader.ReadByte ();
+
+ if ((calling_convention & property_signature) == 0)
+ throw new NotSupportedException ();
+
+ var has_this = (calling_convention & 0x20) != 0;
+
+ reader.ReadCompressedUInt32 (); // count
+
+ var property = new PropertyDefinition (name, attributes, reader.ReadTypeSignature ());
+ property.HasThis = has_this;
+ property.token = new MetadataToken (TokenType.Property, property_rid);
+
+ if (IsDeleted (property))
+ return;
+
+ properties.Add (property);
+ }
+
+ void InitializeProperties ()
+ {
+ if (metadata.Properties != null)
+ return;
+
+ int length = MoveTo (Table.PropertyMap);
+
+ metadata.Properties = new Dictionary (length);
+
+ for (uint i = 1; i <= length; i++) {
+ var type_rid = ReadTableIndex (Table.TypeDef);
+ var properties_range = ReadListRange (i, Table.PropertyMap, Table.Property);
+ metadata.AddPropertiesRange (type_rid, properties_range);
+ }
+ }
+
+ MethodSemanticsAttributes ReadMethodSemantics (MethodDefinition method)
+ {
+ InitializeMethodSemantics ();
+ Row row;
+ if (!metadata.Semantics.TryGetValue (method.token.RID, out row))
+ return MethodSemanticsAttributes.None;
+
+ var type = method.DeclaringType;
+
+ switch (row.Col1) {
+ case MethodSemanticsAttributes.AddOn:
+ GetEvent (type, row.Col2).add_method = method;
+ break;
+ case MethodSemanticsAttributes.Fire:
+ GetEvent (type, row.Col2).invoke_method = method;
+ break;
+ case MethodSemanticsAttributes.RemoveOn:
+ GetEvent (type, row.Col2).remove_method = method;
+ break;
+ case MethodSemanticsAttributes.Getter:
+ GetProperty (type, row.Col2).get_method = method;
+ break;
+ case MethodSemanticsAttributes.Setter:
+ GetProperty (type, row.Col2).set_method = method;
+ break;
+ case MethodSemanticsAttributes.Other:
+ switch (row.Col2.TokenType) {
+ case TokenType.Event: {
+ var @event = GetEvent (type, row.Col2);
+ if (@event.other_methods == null)
+ @event.other_methods = new Collection ();
+
+ @event.other_methods.Add (method);
+ break;
+ }
+ case TokenType.Property: {
+ var property = GetProperty (type, row.Col2);
+ if (property.other_methods == null)
+ property.other_methods = new Collection ();
+
+ property.other_methods.Add (method);
+
+ break;
+ }
+ default:
+ throw new NotSupportedException ();
+ }
+ break;
+ default:
+ throw new NotSupportedException ();
+ }
+
+ metadata.Semantics.Remove (method.token.RID);
+
+ return row.Col1;
+ }
+
+ static EventDefinition GetEvent (TypeDefinition type, MetadataToken token)
+ {
+ if (token.TokenType != TokenType.Event)
+ throw new ArgumentException ();
+
+ return GetMember (type.Events, token);
+ }
+
+ static PropertyDefinition GetProperty (TypeDefinition type, MetadataToken token)
+ {
+ if (token.TokenType != TokenType.Property)
+ throw new ArgumentException ();
+
+ return GetMember (type.Properties, token);
+ }
+
+ static TMember GetMember (Collection members, MetadataToken token) where TMember : IMemberDefinition
+ {
+ for (int i = 0; i < members.Count; i++) {
+ var member = members [i];
+ if (member.MetadataToken == token)
+ return member;
+ }
+
+ throw new ArgumentException ();
+ }
+
+ void InitializeMethodSemantics ()
+ {
+ if (metadata.Semantics != null)
+ return;
+
+ int length = MoveTo (Table.MethodSemantics);
+
+ var semantics = metadata.Semantics = new Dictionary> (0);
+
+ for (uint i = 0; i < length; i++) {
+ var attributes = (MethodSemanticsAttributes) ReadUInt16 ();
+ var method_rid = ReadTableIndex (Table.Method);
+ var association = ReadMetadataToken (CodedIndex.HasSemantics);
+
+ semantics [method_rid] = new Row (attributes, association);
+ }
+ }
+
+ public PropertyDefinition ReadMethods (PropertyDefinition property)
+ {
+ ReadAllSemantics (property.DeclaringType);
+ return property;
+ }
+
+ public EventDefinition ReadMethods (EventDefinition @event)
+ {
+ ReadAllSemantics (@event.DeclaringType);
+ return @event;
+ }
+
+ public MethodSemanticsAttributes ReadAllSemantics (MethodDefinition method)
+ {
+ ReadAllSemantics (method.DeclaringType);
+
+ return method.SemanticsAttributes;
+ }
+
+ void ReadAllSemantics (TypeDefinition type)
+ {
+ var methods = type.Methods;
+ for (int i = 0; i < methods.Count; i++) {
+ var method = methods [i];
+ if (method.sem_attrs_ready)
+ continue;
+
+ method.sem_attrs = ReadMethodSemantics (method);
+ method.sem_attrs_ready = true;
+ }
+ }
+
+ public Collection ReadMethods (TypeDefinition type)
+ {
+ var methods_range = type.methods_range;
+ if (methods_range.Length == 0)
+ return new MemberDefinitionCollection (type);
+
+ var methods = new MemberDefinitionCollection (type, (int) methods_range.Length);
+ if (!MoveTo (Table.MethodPtr, methods_range.Start)) {
+ if (!MoveTo (Table.Method, methods_range.Start))
+ return methods;
+
+ for (uint i = 0; i < methods_range.Length; i++)
+ ReadMethod (methods_range.Start + i, methods);
+ } else
+ ReadPointers (Table.MethodPtr, Table.Method, methods_range, methods, ReadMethod);
+
+ return methods;
+ }
+
+ void ReadPointers (Table ptr, Table table, Range range, Collection members, Action> reader)
+ where TMember : IMemberDefinition
+ {
+ for (uint i = 0; i < range.Length; i++) {
+ MoveTo (ptr, range.Start + i);
+
+ var rid = ReadTableIndex (table);
+ MoveTo (table, rid);
+
+ reader (rid, members);
+ }
+ }
+
+ static bool IsDeleted (IMemberDefinition member)
+ {
+ return member.IsSpecialName && member.Name == "_Deleted";
+ }
+
+ void InitializeMethods ()
+ {
+ if (metadata.Methods != null)
+ return;
+
+ metadata.Methods = new MethodDefinition [image.GetTableLength (Table.Method)];
+ }
+
+ void ReadMethod (uint method_rid, Collection methods)
+ {
+ var method = new MethodDefinition ();
+ method.rva = ReadUInt32 ();
+ method.ImplAttributes = (MethodImplAttributes) ReadUInt16 ();
+ method.Attributes = (MethodAttributes) ReadUInt16 ();
+ method.Name = ReadString ();
+ method.token = new MetadataToken (TokenType.Method, method_rid);
+
+ if (IsDeleted (method))
+ return;
+
+ methods.Add (method); // attach method
+
+ var signature = ReadBlobIndex ();
+ var param_range = ReadListRange (method_rid, Table.Method, Table.Param);
+
+ this.context = method;
+
+ ReadMethodSignature (signature, method);
+ metadata.AddMethodDefinition (method);
+
+ if (param_range.Length != 0) {
+ var position = base.position;
+ ReadParameters (method, param_range);
+ base.position = position;
+ }
+
+ if (module.IsWindowsMetadata ())
+ WindowsRuntimeProjections.Project (method);
+ }
+
+ void ReadParameters (MethodDefinition method, Range param_range)
+ {
+ if (!MoveTo (Table.ParamPtr, param_range.Start)) {
+ if (!MoveTo (Table.Param, param_range.Start))
+ return;
+
+ for (uint i = 0; i < param_range.Length; i++)
+ ReadParameter (param_range.Start + i, method);
+ } else
+ ReadParameterPointers (method, param_range);
+ }
+
+ void ReadParameterPointers (MethodDefinition method, Range range)
+ {
+ for (uint i = 0; i < range.Length; i++) {
+ MoveTo (Table.ParamPtr, range.Start + i);
+
+ var rid = ReadTableIndex (Table.Param);
+
+ MoveTo (Table.Param, rid);
+
+ ReadParameter (rid, method);
+ }
+ }
+
+ void ReadParameter (uint param_rid, MethodDefinition method)
+ {
+ var attributes = (ParameterAttributes) ReadUInt16 ();
+ var sequence = ReadUInt16 ();
+ var name = ReadString ();
+
+ var parameter = sequence == 0
+ ? method.MethodReturnType.Parameter
+ : method.Parameters [sequence - 1];
+
+ parameter.token = new MetadataToken (TokenType.Param, param_rid);
+ parameter.Name = name;
+ parameter.Attributes = attributes;
+ }
+
+ void ReadMethodSignature (uint signature, IMethodSignature method)
+ {
+ var reader = ReadSignature (signature);
+ reader.ReadMethodSignature (method);
+ }
+
+ public PInvokeInfo ReadPInvokeInfo (MethodDefinition method)
+ {
+ InitializePInvokes ();
+ Row row;
+
+ var rid = method.token.RID;
+
+ if (!metadata.PInvokes.TryGetValue (rid, out row))
+ return null;
+
+ metadata.PInvokes.Remove (rid);
+
+ return new PInvokeInfo (
+ row.Col1,
+ image.StringHeap.Read (row.Col2),
+ module.ModuleReferences [(int) row.Col3 - 1]);
+ }
+
+ void InitializePInvokes ()
+ {
+ if (metadata.PInvokes != null)
+ return;
+
+ int length = MoveTo (Table.ImplMap);
+
+ var pinvokes = metadata.PInvokes = new Dictionary> (length);
+
+ for (int i = 1; i <= length; i++) {
+ var attributes = (PInvokeAttributes) ReadUInt16 ();
+ var method = ReadMetadataToken (CodedIndex.MemberForwarded);
+ var name = ReadStringIndex ();
+ var scope = ReadTableIndex (Table.File);
+
+ if (method.TokenType != TokenType.Method)
+ continue;
+
+ pinvokes.Add (method.RID, new Row (attributes, name, scope));
+ }
+ }
+
+ public bool HasGenericParameters (IGenericParameterProvider provider)
+ {
+ InitializeGenericParameters ();
+
+ Range [] ranges;
+ if (!metadata.TryGetGenericParameterRanges (provider, out ranges))
+ return false;
+
+ return RangesSize (ranges) > 0;
+ }
+
+ public Collection ReadGenericParameters (IGenericParameterProvider provider)
+ {
+ InitializeGenericParameters ();
+
+ Range [] ranges;
+ if (!metadata.TryGetGenericParameterRanges (provider, out ranges))
+ return new GenericParameterCollection (provider);
+
+ metadata.RemoveGenericParameterRange (provider);
+
+ var generic_parameters = new GenericParameterCollection (provider, RangesSize (ranges));
+
+ for (int i = 0; i < ranges.Length; i++)
+ ReadGenericParametersRange (ranges [i], provider, generic_parameters);
+
+ return generic_parameters;
+ }
+
+ void ReadGenericParametersRange (Range range, IGenericParameterProvider provider, GenericParameterCollection generic_parameters)
+ {
+ if (!MoveTo (Table.GenericParam, range.Start))
+ return;
+
+ for (uint i = 0; i < range.Length; i++) {
+ ReadUInt16 (); // index
+ var flags = (GenericParameterAttributes) ReadUInt16 ();
+ ReadMetadataToken (CodedIndex.TypeOrMethodDef);
+ var name = ReadString ();
+
+ var parameter = new GenericParameter (name, provider);
+ parameter.token = new MetadataToken (TokenType.GenericParam, range.Start + i);
+ parameter.Attributes = flags;
+
+ generic_parameters.Add (parameter);
+ }
+ }
+
+ void InitializeGenericParameters ()
+ {
+ if (metadata.GenericParameters != null)
+ return;
+
+ metadata.GenericParameters = InitializeRanges (
+ Table.GenericParam, () => {
+ Advance (4);
+ var next = ReadMetadataToken (CodedIndex.TypeOrMethodDef);
+ ReadStringIndex ();
+ return next;
+ });
+ }
+
+ Dictionary InitializeRanges (Table table, Func get_next)
+ {
+ int length = MoveTo (table);
+ var ranges = new Dictionary (length);
+
+ if (length == 0)
+ return ranges;
+
+ MetadataToken owner = MetadataToken.Zero;
+ Range range = new Range (1, 0);
+
+ for (uint i = 1; i <= length; i++) {
+ var next = get_next ();
+
+ if (i == 1) {
+ owner = next;
+ range.Length++;
+ } else if (next != owner) {
+ AddRange (ranges, owner, range);
+ range = new Range (i, 1);
+ owner = next;
+ } else
+ range.Length++;
+ }
+
+ AddRange (ranges, owner, range);
+
+ return ranges;
+ }
+
+ static void AddRange (Dictionary ranges, MetadataToken owner, Range range)
+ {
+ if (owner.RID == 0)
+ return;
+
+ Range [] slots;
+ if (!ranges.TryGetValue (owner, out slots)) {
+ ranges.Add (owner, new [] { range });
+ return;
+ }
+
+ ranges [owner] = slots.Add(range);
+ }
+
+ public bool HasGenericConstraints (GenericParameter generic_parameter)
+ {
+ InitializeGenericConstraints ();
+
+ Collection mapping;
+ if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping))
+ return false;
+
+ return mapping.Count > 0;
+ }
+
+ public Collection ReadGenericConstraints (GenericParameter generic_parameter)
+ {
+ InitializeGenericConstraints ();
+
+ Collection mapping;
+ if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping))
+ return new Collection ();
+
+ var constraints = new Collection (mapping.Count);
+
+ this.context = (IGenericContext) generic_parameter.Owner;
+
+ for (int i = 0; i < mapping.Count; i++)
+ constraints.Add (GetTypeDefOrRef (mapping [i]));
+
+ metadata.RemoveGenericConstraintMapping (generic_parameter);
+
+ return constraints;
+ }
+
+ void InitializeGenericConstraints ()
+ {
+ if (metadata.GenericConstraints != null)
+ return;
+
+ var length = MoveTo (Table.GenericParamConstraint);
+
+ metadata.GenericConstraints = new Dictionary> (length);
+
+ for (int i = 1; i <= length; i++)
+ AddGenericConstraintMapping (
+ ReadTableIndex (Table.GenericParam),
+ ReadMetadataToken (CodedIndex.TypeDefOrRef));
+ }
+
+ void AddGenericConstraintMapping (uint generic_parameter, MetadataToken constraint)
+ {
+ metadata.SetGenericConstraintMapping (
+ generic_parameter,
+ AddMapping (metadata.GenericConstraints, generic_parameter, constraint));
+ }
+
+ public bool HasOverrides (MethodDefinition method)
+ {
+ InitializeOverrides ();
+ Collection mapping;
+
+ if (!metadata.TryGetOverrideMapping (method, out mapping))
+ return false;
+
+ return mapping.Count > 0;
+ }
+
+ public Collection ReadOverrides (MethodDefinition method)
+ {
+ InitializeOverrides ();
+
+ Collection mapping;
+ if (!metadata.TryGetOverrideMapping (method, out mapping))
+ return new Collection ();
+
+ var overrides = new Collection (mapping.Count);
+
+ this.context = method;
+
+ for (int i = 0; i < mapping.Count; i++)
+ overrides.Add ((MethodReference) LookupToken (mapping [i]));
+
+ metadata.RemoveOverrideMapping (method);
+
+ return overrides;
+ }
+
+ void InitializeOverrides ()
+ {
+ if (metadata.Overrides != null)
+ return;
+
+ var length = MoveTo (Table.MethodImpl);
+
+ metadata.Overrides = new Dictionary> (length);
+
+ for (int i = 1; i <= length; i++) {
+ ReadTableIndex (Table.TypeDef);
+
+ var method = ReadMetadataToken (CodedIndex.MethodDefOrRef);
+ if (method.TokenType != TokenType.Method)
+ throw new NotSupportedException ();
+
+ var @override = ReadMetadataToken (CodedIndex.MethodDefOrRef);
+
+ AddOverrideMapping (method.RID, @override);
+ }
+ }
+
+ void AddOverrideMapping (uint method_rid, MetadataToken @override)
+ {
+ metadata.SetOverrideMapping (
+ method_rid,
+ AddMapping (metadata.Overrides, method_rid, @override));
+ }
+
+ public MethodBody ReadMethodBody (MethodDefinition method)
+ {
+ return code.ReadMethodBody (method);
+ }
+
+ public CallSite ReadCallSite (MetadataToken token)
+ {
+ if (!MoveTo (Table.StandAloneSig, token.RID))
+ return null;
+
+ var signature = ReadBlobIndex ();
+
+ var call_site = new CallSite ();
+
+ ReadMethodSignature (signature, call_site);
+
+ call_site.MetadataToken = token;
+
+ return call_site;
+ }
+
+ public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token)
+ {
+ if (!MoveTo (Table.StandAloneSig, local_var_token.RID))
+ return null;
+
+ var reader = ReadSignature (ReadBlobIndex ());
+ const byte local_sig = 0x7;
+
+ if (reader.ReadByte () != local_sig)
+ throw new NotSupportedException ();
+
+ var count = reader.ReadCompressedUInt32 ();
+ if (count == 0)
+ return null;
+
+ var variables = new VariableDefinitionCollection ((int) count);
+
+ for (int i = 0; i < count; i++)
+ variables.Add (new VariableDefinition (reader.ReadTypeSignature ()));
+
+ return variables;
+ }
+
+ public IMetadataTokenProvider LookupToken (MetadataToken token)
+ {
+ var rid = token.RID;
+
+ if (rid == 0)
+ return null;
+
+ if (metadata_reader != null)
+ return metadata_reader.LookupToken (token);
+
+ IMetadataTokenProvider element;
+ var position = this.position;
+ var context = this.context;
+
+ switch (token.TokenType) {
+ case TokenType.TypeDef:
+ element = GetTypeDefinition (rid);
+ break;
+ case TokenType.TypeRef:
+ element = GetTypeReference (rid);
+ break;
+ case TokenType.TypeSpec:
+ element = GetTypeSpecification (rid);
+ break;
+ case TokenType.Field:
+ element = GetFieldDefinition (rid);
+ break;
+ case TokenType.Method:
+ element = GetMethodDefinition (rid);
+ break;
+ case TokenType.MemberRef:
+ element = GetMemberReference (rid);
+ break;
+ case TokenType.MethodSpec:
+ element = GetMethodSpecification (rid);
+ break;
+ default:
+ return null;
+ }
+
+ this.position = position;
+ this.context = context;
+
+ return element;
+ }
+
+ public FieldDefinition GetFieldDefinition (uint rid)
+ {
+ InitializeTypeDefinitions ();
+
+ var field = metadata.GetFieldDefinition (rid);
+ if (field != null)
+ return field;
+
+ return LookupField (rid);
+ }
+
+ FieldDefinition LookupField (uint rid)
+ {
+ var type = metadata.GetFieldDeclaringType (rid);
+ if (type == null)
+ return null;
+
+ Mixin.Read (type.Fields);
+
+ return metadata.GetFieldDefinition (rid);
+ }
+
+ public MethodDefinition GetMethodDefinition (uint rid)
+ {
+ InitializeTypeDefinitions ();
+
+ var method = metadata.GetMethodDefinition (rid);
+ if (method != null)
+ return method;
+
+ return LookupMethod (rid);
+ }
+
+ MethodDefinition LookupMethod (uint rid)
+ {
+ var type = metadata.GetMethodDeclaringType (rid);
+ if (type == null)
+ return null;
+
+ Mixin.Read (type.Methods);
+
+ return metadata.GetMethodDefinition (rid);
+ }
+
+ MethodSpecification GetMethodSpecification (uint rid)
+ {
+ if (!MoveTo (Table.MethodSpec, rid))
+ return null;
+
+ var element_method = (MethodReference) LookupToken (
+ ReadMetadataToken (CodedIndex.MethodDefOrRef));
+ var signature = ReadBlobIndex ();
+
+ var method_spec = ReadMethodSpecSignature (signature, element_method);
+ method_spec.token = new MetadataToken (TokenType.MethodSpec, rid);
+ return method_spec;
+ }
+
+ MethodSpecification ReadMethodSpecSignature (uint signature, MethodReference method)
+ {
+ var reader = ReadSignature (signature);
+ const byte methodspec_sig = 0x0a;
+
+ var call_conv = reader.ReadByte ();
+
+ if (call_conv != methodspec_sig)
+ throw new NotSupportedException ();
+
+ var instance = new GenericInstanceMethod (method);
+
+ reader.ReadGenericInstanceSignature (method, instance);
+
+ return instance;
+ }
+
+ MemberReference GetMemberReference (uint rid)
+ {
+ InitializeMemberReferences ();
+
+ var member = metadata.GetMemberReference (rid);
+ if (member != null)
+ return member;
+
+ member = ReadMemberReference (rid);
+ if (member != null && !member.ContainsGenericParameter)
+ metadata.AddMemberReference (member);
+ return member;
+ }
+
+ MemberReference ReadMemberReference (uint rid)
+ {
+ if (!MoveTo (Table.MemberRef, rid))
+ return null;
+
+ var token = ReadMetadataToken (CodedIndex.MemberRefParent);
+ var name = ReadString ();
+ var signature = ReadBlobIndex ();
+
+ MemberReference member;
+
+ switch (token.TokenType) {
+ case TokenType.TypeDef:
+ case TokenType.TypeRef:
+ case TokenType.TypeSpec:
+ member = ReadTypeMemberReference (token, name, signature);
+ break;
+ case TokenType.Method:
+ member = ReadMethodMemberReference (token, name, signature);
+ break;
+ default:
+ throw new NotSupportedException ();
+ }
+
+ member.token = new MetadataToken (TokenType.MemberRef, rid);
+
+ if (module.IsWindowsMetadata ())
+ WindowsRuntimeProjections.Project (member);
+
+ return member;
+ }
+
+ MemberReference ReadTypeMemberReference (MetadataToken type, string name, uint signature)
+ {
+ var declaring_type = GetTypeDefOrRef (type);
+
+ if (!declaring_type.IsArray)
+ this.context = declaring_type;
+
+ var member = ReadMemberReferenceSignature (signature, declaring_type);
+ member.Name = name;
+
+ return member;
+ }
+
+ MemberReference ReadMemberReferenceSignature (uint signature, TypeReference declaring_type)
+ {
+ var reader = ReadSignature (signature);
+ const byte field_sig = 0x6;
+
+ if (reader.buffer [reader.position] == field_sig) {
+ reader.position++;
+ var field = new FieldReference ();
+ field.DeclaringType = declaring_type;
+ field.FieldType = reader.ReadTypeSignature ();
+ return field;
+ } else {
+ var method = new MethodReference ();
+ method.DeclaringType = declaring_type;
+ reader.ReadMethodSignature (method);
+ return method;
+ }
+ }
+
+ MemberReference ReadMethodMemberReference (MetadataToken token, string name, uint signature)
+ {
+ var method = GetMethodDefinition (token.RID);
+
+ this.context = method;
+
+ var member = ReadMemberReferenceSignature (signature, method.DeclaringType);
+ member.Name = name;
+
+ return member;
+ }
+
+ void InitializeMemberReferences ()
+ {
+ if (metadata.MemberReferences != null)
+ return;
+
+ metadata.MemberReferences = new MemberReference [image.GetTableLength (Table.MemberRef)];
+ }
+
+ public IEnumerable GetMemberReferences ()
+ {
+ InitializeMemberReferences ();
+
+ var length = image.GetTableLength (Table.MemberRef);
+
+ var type_system = module.TypeSystem;
+
+ var context = new MethodReference (string.Empty, type_system.Void);
+ context.DeclaringType = new TypeReference (string.Empty, string.Empty, module, type_system.CoreLibrary);
+
+ var member_references = new MemberReference [length];
+
+ for (uint i = 1; i <= length; i++) {
+ this.context = context;
+ member_references [i - 1] = GetMemberReference (i);
+ }
+
+ return member_references;
+ }
+
+ void InitializeConstants ()
+ {
+ if (metadata.Constants != null)
+ return;
+
+ var length = MoveTo (Table.Constant);
+
+ var constants = metadata.Constants = new Dictionary> (length);
+
+ for (uint i = 1; i <= length; i++) {
+ var type = (ElementType) ReadUInt16 ();
+ var owner = ReadMetadataToken (CodedIndex.HasConstant);
+ var signature = ReadBlobIndex ();
+
+ constants.Add (owner, new Row (type, signature));
+ }
+ }
+
+ public TypeReference ReadConstantSignature (MetadataToken token)
+ {
+ if (token.TokenType != TokenType.Signature)
+ throw new NotSupportedException ();
+
+ if (!MoveTo (Table.StandAloneSig, token.RID))
+ return null;
+
+ return ReadFieldType (ReadBlobIndex ());
+ }
+
+ public object ReadConstant (IConstantProvider owner)
+ {
+ InitializeConstants ();
+
+ Row row;
+ if (!metadata.Constants.TryGetValue (owner.MetadataToken, out row))
+ return Mixin.NoValue;
+
+ metadata.Constants.Remove (owner.MetadataToken);
+
+ return ReadConstantValue (row.Col1, row.Col2);
+ }
+
+ object ReadConstantValue (ElementType etype, uint signature)
+ {
+ switch (etype) {
+ case ElementType.Class:
+ case ElementType.Object:
+ return null;
+ case ElementType.String:
+ return ReadConstantString (signature);
+ default:
+ return ReadConstantPrimitive (etype, signature);
+ }
+ }
+
+ string ReadConstantString (uint signature)
+ {
+ byte [] blob;
+ int index, count;
+
+ GetBlobView (signature, out blob, out index, out count);
+ if (count == 0)
+ return string.Empty;
+
+ if ((count & 1) == 1)
+ count--;
+
+ return Encoding.Unicode.GetString (blob, index, count);
+ }
+
+ object ReadConstantPrimitive (ElementType type, uint signature)
+ {
+ var reader = ReadSignature (signature);
+ return reader.ReadConstantSignature (type);
+ }
+
+ internal void InitializeCustomAttributes ()
+ {
+ if (metadata.CustomAttributes != null)
+ return;
+
+ metadata.CustomAttributes = InitializeRanges (
+ Table.CustomAttribute, () => {
+ var next = ReadMetadataToken (CodedIndex.HasCustomAttribute);
+ ReadMetadataToken (CodedIndex.CustomAttributeType);
+ ReadBlobIndex ();
+ return next;
+ });
+ }
+
+ public bool HasCustomAttributes (ICustomAttributeProvider owner)
+ {
+ InitializeCustomAttributes ();
+
+ Range [] ranges;
+ if (!metadata.TryGetCustomAttributeRanges (owner, out ranges))
+ return false;
+
+ return RangesSize (ranges) > 0;
+ }
+
+ public Collection ReadCustomAttributes (ICustomAttributeProvider owner)
+ {
+ InitializeCustomAttributes ();
+
+ Range [] ranges;
+ if (!metadata.TryGetCustomAttributeRanges (owner, out ranges))
+ return new Collection ();
+
+ var custom_attributes = new Collection (RangesSize (ranges));
+
+ for (int i = 0; i < ranges.Length; i++)
+ ReadCustomAttributeRange (ranges [i], custom_attributes);
+
+ metadata.RemoveCustomAttributeRange (owner);
+
+ if (module.IsWindowsMetadata ())
+ foreach (var custom_attribute in custom_attributes)
+ WindowsRuntimeProjections.Project (owner, custom_attribute);
+
+ return custom_attributes;
+ }
+
+ void ReadCustomAttributeRange (Range range, Collection custom_attributes)
+ {
+ if (!MoveTo (Table.CustomAttribute, range.Start))
+ return;
+
+ for (var i = 0; i < range.Length; i++) {
+ ReadMetadataToken (CodedIndex.HasCustomAttribute);
+
+ var constructor = (MethodReference) LookupToken (
+ ReadMetadataToken (CodedIndex.CustomAttributeType));
+
+ var signature = ReadBlobIndex ();
+
+ custom_attributes.Add (new CustomAttribute (signature, constructor));
+ }
+ }
+
+ static int RangesSize (Range [] ranges)
+ {
+ uint size = 0;
+ for (int i = 0; i < ranges.Length; i++)
+ size += ranges [i].Length;
+
+ return (int) size;
+ }
+
+ public IEnumerable GetCustomAttributes ()
+ {
+ InitializeTypeDefinitions ();
+
+ var length = image.TableHeap [Table.CustomAttribute].Length;
+ var custom_attributes = new Collection ((int) length);
+ ReadCustomAttributeRange (new Range (1, length), custom_attributes);
+
+ return custom_attributes;
+ }
+
+ public byte [] ReadCustomAttributeBlob (uint signature)
+ {
+ return ReadBlob (signature);
+ }
+
+ public void ReadCustomAttributeSignature (CustomAttribute attribute)
+ {
+ var reader = ReadSignature (attribute.signature);
+
+ if (!reader.CanReadMore ())
+ return;
+
+ if (reader.ReadUInt16 () != 0x0001)
+ throw new InvalidOperationException ();
+
+ var constructor = attribute.Constructor;
+ if (constructor.HasParameters)
+ reader.ReadCustomAttributeConstructorArguments (attribute, constructor.Parameters);
+
+ if (!reader.CanReadMore ())
+ return;
+
+ var named = reader.ReadUInt16 ();
+
+ if (named == 0)
+ return;
+
+ reader.ReadCustomAttributeNamedArguments (named, ref attribute.fields, ref attribute.properties);
+ }
+
+ void InitializeMarshalInfos ()
+ {
+ if (metadata.FieldMarshals != null)
+ return;
+
+ var length = MoveTo (Table.FieldMarshal);
+
+ var marshals = metadata.FieldMarshals = new Dictionary (length);
+
+ for (int i = 0; i < length; i++) {
+ var token = ReadMetadataToken (CodedIndex.HasFieldMarshal);
+ var signature = ReadBlobIndex ();
+ if (token.RID == 0)
+ continue;
+
+ marshals.Add (token, signature);
+ }
+ }
+
+ public bool HasMarshalInfo (IMarshalInfoProvider owner)
+ {
+ InitializeMarshalInfos ();
+
+ return metadata.FieldMarshals.ContainsKey (owner.MetadataToken);
+ }
+
+ public MarshalInfo ReadMarshalInfo (IMarshalInfoProvider owner)
+ {
+ InitializeMarshalInfos ();
+
+ uint signature;
+ if (!metadata.FieldMarshals.TryGetValue (owner.MetadataToken, out signature))
+ return null;
+
+ var reader = ReadSignature (signature);
+
+ metadata.FieldMarshals.Remove (owner.MetadataToken);
+
+ return reader.ReadMarshalInfo ();
+ }
+
+ void InitializeSecurityDeclarations ()
+ {
+ if (metadata.SecurityDeclarations != null)
+ return;
+
+ metadata.SecurityDeclarations = InitializeRanges (
+ Table.DeclSecurity, () => {
+ ReadUInt16 ();
+ var next = ReadMetadataToken (CodedIndex.HasDeclSecurity);
+ ReadBlobIndex ();
+ return next;
+ });
+ }
+
+ public bool HasSecurityDeclarations (ISecurityDeclarationProvider owner)
+ {
+ InitializeSecurityDeclarations ();
+
+ Range [] ranges;
+ if (!metadata.TryGetSecurityDeclarationRanges (owner, out ranges))
+ return false;
+
+ return RangesSize (ranges) > 0;
+ }
+
+ public Collection ReadSecurityDeclarations (ISecurityDeclarationProvider owner)
+ {
+ InitializeSecurityDeclarations ();
+
+ Range [] ranges;
+ if (!metadata.TryGetSecurityDeclarationRanges (owner, out ranges))
+ return new Collection ();
+
+ var security_declarations = new Collection (RangesSize (ranges));
+
+ for (int i = 0; i < ranges.Length; i++)
+ ReadSecurityDeclarationRange (ranges [i], security_declarations);
+
+ metadata.RemoveSecurityDeclarationRange (owner);
+
+ return security_declarations;
+ }
+
+ void ReadSecurityDeclarationRange (Range range, Collection security_declarations)
+ {
+ if (!MoveTo (Table.DeclSecurity, range.Start))
+ return;
+
+ for (int i = 0; i < range.Length; i++) {
+ var action = (SecurityAction) ReadUInt16 ();
+ ReadMetadataToken (CodedIndex.HasDeclSecurity);
+ var signature = ReadBlobIndex ();
+
+ security_declarations.Add (new SecurityDeclaration (action, signature, module));
+ }
+ }
+
+ public byte [] ReadSecurityDeclarationBlob (uint signature)
+ {
+ return ReadBlob (signature);
+ }
+
+ public void ReadSecurityDeclarationSignature (SecurityDeclaration declaration)
+ {
+ var signature = declaration.signature;
+ var reader = ReadSignature (signature);
+
+ if (reader.buffer [reader.position] != '.') {
+ ReadXmlSecurityDeclaration (signature, declaration);
+ return;
+ }
+
+ reader.position++;
+ var count = reader.ReadCompressedUInt32 ();
+ var attributes = new Collection ((int) count);
+
+ for (int i = 0; i < count; i++)
+ attributes.Add (reader.ReadSecurityAttribute ());
+
+ declaration.security_attributes = attributes;
+ }
+
+ void ReadXmlSecurityDeclaration (uint signature, SecurityDeclaration declaration)
+ {
+ var attributes = new Collection (1);
+
+ var attribute = new SecurityAttribute (
+ module.TypeSystem.LookupType ("System.Security.Permissions", "PermissionSetAttribute"));
+
+ attribute.properties = new Collection (1);
+ attribute.properties.Add (
+ new CustomAttributeNamedArgument (
+ "XML",
+ new CustomAttributeArgument (
+ module.TypeSystem.String,
+ ReadUnicodeStringBlob (signature))));
+
+ attributes.Add (attribute);
+
+ declaration.security_attributes = attributes;
+ }
+
+ public Collection ReadExportedTypes ()
+ {
+ var length = MoveTo (Table.ExportedType);
+ if (length == 0)
+ return new Collection ();
+
+ var exported_types = new Collection (length);
+
+ for (int i = 1; i <= length; i++) {
+ var attributes = (TypeAttributes) ReadUInt32 ();
+ var identifier = ReadUInt32 ();
+ var name = ReadString ();
+ var @namespace = ReadString ();
+ var implementation = ReadMetadataToken (CodedIndex.Implementation);
+
+ ExportedType declaring_type = null;
+ IMetadataScope scope = null;
+
+ switch (implementation.TokenType) {
+ case TokenType.AssemblyRef:
+ case TokenType.File:
+ scope = GetExportedTypeScope (implementation);
+ break;
+ case TokenType.ExportedType:
+ // FIXME: if the table is not properly sorted
+ declaring_type = exported_types [(int) implementation.RID - 1];
+ break;
+ }
+
+ var exported_type = new ExportedType (@namespace, name, module, scope) {
+ Attributes = attributes,
+ Identifier = (int) identifier,
+ DeclaringType = declaring_type,
+ };
+ exported_type.token = new MetadataToken (TokenType.ExportedType, i);
+
+ exported_types.Add (exported_type);
+ }
+
+ return exported_types;
+ }
+
+ IMetadataScope GetExportedTypeScope (MetadataToken token)
+ {
+ var position = this.position;
+ IMetadataScope scope;
+
+ switch (token.TokenType) {
+ case TokenType.AssemblyRef:
+ InitializeAssemblyReferences ();
+ scope = metadata.GetAssemblyNameReference (token.RID);
+ break;
+ case TokenType.File:
+ InitializeModuleReferences ();
+ scope = GetModuleReferenceFromFile (token);
+ break;
+ default:
+ throw new NotSupportedException ();
+ }
+
+ this.position = position;
+ return scope;
+ }
+
+ ModuleReference GetModuleReferenceFromFile (MetadataToken token)
+ {
+ if (!MoveTo (Table.File, token.RID))
+ return null;
+
+ ReadUInt32 ();
+ var file_name = ReadString ();
+ var modules = module.ModuleReferences;
+
+ ModuleReference reference;
+ for (int i = 0; i < modules.Count; i++) {
+ reference = modules [i];
+ if (reference.Name == file_name)
+ return reference;
+ }
+
+ reference = new ModuleReference (file_name);
+ modules.Add (reference);
+ return reference;
+ }
+
+ void InitializeDocuments ()
+ {
+ if (metadata.Documents != null)
+ return;
+
+ int length = MoveTo (Table.Document);
+
+ var documents = metadata.Documents = new Document [length];
+
+ for (uint i = 1; i <= length; i++) {
+ var name_index = ReadBlobIndex ();
+ var hash_algorithm = ReadGuid ();
+ var hash = ReadBlob ();
+ var language = ReadGuid ();
+
+ var signature = ReadSignature (name_index);
+ var name = signature.ReadDocumentName ();
+
+ documents [i - 1] = new Document (name) {
+ HashAlgorithm = hash_algorithm.ToHashAlgorithm (),
+ Hash = hash,
+ Language = language.ToLanguage (),
+ token = new MetadataToken (TokenType.Document, i),
+ };
+ }
+ }
+
+ public Collection ReadSequencePoints (MethodDefinition method)
+ {
+ InitializeDocuments ();
+
+ if (!MoveTo (Table.MethodDebugInformation, method.MetadataToken.RID))
+ return new Collection (0);
+
+ var document_index = ReadTableIndex (Table.Document);
+ var signature = ReadBlobIndex ();
+ if (signature == 0)
+ return new Collection (0);
+
+ var document = GetDocument (document_index);
+ var reader = ReadSignature (signature);
+
+ return reader.ReadSequencePoints (document);
+ }
+
+ public Document GetDocument (uint rid)
+ {
+ var document = metadata.GetDocument (rid);
+ if (document == null)
+ return null;
+
+ document.custom_infos = GetCustomDebugInformation (document);
+ return document;
+ }
+
+ void InitializeLocalScopes ()
+ {
+ if (metadata.LocalScopes != null)
+ return;
+
+ InitializeMethods ();
+
+ int length = MoveTo (Table.LocalScope);
+
+ metadata.LocalScopes = new Dictionary