forked from cgvr/DeltaVR
		
	
		
			
				
	
	
		
			229 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
//
 | 
						|
// 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 MonoFN.Cecil.Cil;
 | 
						|
using MonoFN.Collections.Generic;
 | 
						|
using System;
 | 
						|
 | 
						|
namespace MonoFN.Cecil.Rocks {
 | 
						|
 | 
						|
#if UNITY_EDITOR
 | 
						|
	public
 | 
						|
#endif
 | 
						|
	interface IILVisitor {
 | 
						|
		void OnInlineNone (OpCode opcode);
 | 
						|
		void OnInlineSByte (OpCode opcode, sbyte value);
 | 
						|
		void OnInlineByte (OpCode opcode, byte value);
 | 
						|
		void OnInlineInt32 (OpCode opcode, int value);
 | 
						|
		void OnInlineInt64 (OpCode opcode, long value);
 | 
						|
		void OnInlineSingle (OpCode opcode, float value);
 | 
						|
		void OnInlineDouble (OpCode opcode, double value);
 | 
						|
		void OnInlineString (OpCode opcode, string value);
 | 
						|
		void OnInlineBranch (OpCode opcode, int offset);
 | 
						|
		void OnInlineSwitch (OpCode opcode, int [] offsets);
 | 
						|
		void OnInlineVariable (OpCode opcode, VariableDefinition variable);
 | 
						|
		void OnInlineArgument (OpCode opcode, ParameterDefinition parameter);
 | 
						|
		void OnInlineSignature (OpCode opcode, CallSite callSite);
 | 
						|
		void OnInlineType (OpCode opcode, TypeReference type);
 | 
						|
		void OnInlineField (OpCode opcode, FieldReference field);
 | 
						|
		void OnInlineMethod (OpCode opcode, MethodReference method);
 | 
						|
	}
 | 
						|
 | 
						|
#if UNITY_EDITOR
 | 
						|
	public
 | 
						|
#endif
 | 
						|
	static class ILParser {
 | 
						|
 | 
						|
		class ParseContext {
 | 
						|
			public CodeReader Code { get; set; }
 | 
						|
			public int Position { get; set; }
 | 
						|
			public MetadataReader Metadata { get; set; }
 | 
						|
			public Collection<VariableDefinition> Variables { get; set; }
 | 
						|
			public IILVisitor Visitor { get; set; }
 | 
						|
		}
 | 
						|
 | 
						|
		public static void Parse (MethodDefinition method, IILVisitor visitor)
 | 
						|
		{
 | 
						|
			if (method == null)
 | 
						|
				throw new ArgumentNullException ("method");
 | 
						|
			if (visitor == null)
 | 
						|
				throw new ArgumentNullException ("visitor");
 | 
						|
			if (!method.HasBody || !method.HasImage)
 | 
						|
				throw new ArgumentException ();
 | 
						|
 | 
						|
			method.Module.Read (method, (m, _) => {
 | 
						|
				ParseMethod (m, visitor);
 | 
						|
				return true;
 | 
						|
			});
 | 
						|
		}
 | 
						|
 | 
						|
		static void ParseMethod (MethodDefinition method, IILVisitor visitor)
 | 
						|
		{
 | 
						|
			var context = CreateContext (method, visitor);
 | 
						|
			var code = context.Code;
 | 
						|
 | 
						|
			var flags = code.ReadByte ();
 | 
						|
 | 
						|
			switch (flags & 0x3) {
 | 
						|
			case 0x2: // tiny
 | 
						|
				int code_size = flags >> 2;
 | 
						|
				ParseCode (code_size, context);
 | 
						|
				break;
 | 
						|
			case 0x3: // fat
 | 
						|
				code.Advance (-1);
 | 
						|
				ParseFatMethod (context);
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				throw new NotSupportedException ();
 | 
						|
			}
 | 
						|
 | 
						|
			code.MoveBackTo (context.Position);
 | 
						|
		}
 | 
						|
 | 
						|
		static ParseContext CreateContext (MethodDefinition method, IILVisitor visitor)
 | 
						|
		{
 | 
						|
			var code = method.Module.Read (method, (_, reader) => reader.code);
 | 
						|
			var position = code.MoveTo (method);
 | 
						|
 | 
						|
			return new ParseContext {
 | 
						|
				Code = code,
 | 
						|
				Position = position,
 | 
						|
				Metadata = code.reader,
 | 
						|
				Visitor = visitor,
 | 
						|
			};
 | 
						|
		}
 | 
						|
 | 
						|
		static void ParseFatMethod (ParseContext context)
 | 
						|
		{
 | 
						|
			var code = context.Code;
 | 
						|
 | 
						|
			code.Advance (4);
 | 
						|
			var code_size = code.ReadInt32 ();
 | 
						|
			var local_var_token = code.ReadToken ();
 | 
						|
 | 
						|
			if (local_var_token != MetadataToken.Zero)
 | 
						|
				context.Variables = code.ReadVariables (local_var_token);
 | 
						|
 | 
						|
			ParseCode (code_size, context);
 | 
						|
		}
 | 
						|
 | 
						|
		static void ParseCode (int code_size, ParseContext context)
 | 
						|
		{
 | 
						|
			var code = context.Code;
 | 
						|
			var metadata = context.Metadata;
 | 
						|
			var visitor = context.Visitor;
 | 
						|
 | 
						|
			var start = code.Position;
 | 
						|
			var end = start + code_size;
 | 
						|
 | 
						|
			while (code.Position < end) {
 | 
						|
				var il_opcode = code.ReadByte ();
 | 
						|
				var opcode = il_opcode != 0xfe
 | 
						|
					? OpCodes.OneByteOpCode [il_opcode]
 | 
						|
					: OpCodes.TwoBytesOpCode [code.ReadByte ()];
 | 
						|
 | 
						|
				switch (opcode.OperandType) {
 | 
						|
				case OperandType.InlineNone:
 | 
						|
					visitor.OnInlineNone (opcode);
 | 
						|
					break;
 | 
						|
				case OperandType.InlineSwitch:
 | 
						|
					var length = code.ReadInt32 ();
 | 
						|
					var branches = new int [length];
 | 
						|
					for (int i = 0; i < length; i++)
 | 
						|
						branches [i] = code.ReadInt32 ();
 | 
						|
					visitor.OnInlineSwitch (opcode, branches);
 | 
						|
					break;
 | 
						|
				case OperandType.ShortInlineBrTarget:
 | 
						|
					visitor.OnInlineBranch (opcode, code.ReadSByte ());
 | 
						|
					break;
 | 
						|
				case OperandType.InlineBrTarget:
 | 
						|
					visitor.OnInlineBranch (opcode, code.ReadInt32 ());
 | 
						|
					break;
 | 
						|
				case OperandType.ShortInlineI:
 | 
						|
					if (opcode == OpCodes.Ldc_I4_S)
 | 
						|
						visitor.OnInlineSByte (opcode, code.ReadSByte ());
 | 
						|
					else
 | 
						|
						visitor.OnInlineByte (opcode, code.ReadByte ());
 | 
						|
					break;
 | 
						|
				case OperandType.InlineI:
 | 
						|
					visitor.OnInlineInt32 (opcode, code.ReadInt32 ());
 | 
						|
					break;
 | 
						|
				case OperandType.InlineI8:
 | 
						|
					visitor.OnInlineInt64 (opcode, code.ReadInt64 ());
 | 
						|
					break;
 | 
						|
				case OperandType.ShortInlineR:
 | 
						|
					visitor.OnInlineSingle (opcode, code.ReadSingle ());
 | 
						|
					break;
 | 
						|
				case OperandType.InlineR:
 | 
						|
					visitor.OnInlineDouble (opcode, code.ReadDouble ());
 | 
						|
					break;
 | 
						|
				case OperandType.InlineSig:
 | 
						|
					visitor.OnInlineSignature (opcode, code.GetCallSite (code.ReadToken ()));
 | 
						|
					break;
 | 
						|
				case OperandType.InlineString:
 | 
						|
					visitor.OnInlineString (opcode, code.GetString (code.ReadToken ()));
 | 
						|
					break;
 | 
						|
				case OperandType.ShortInlineArg:
 | 
						|
					visitor.OnInlineArgument (opcode, code.GetParameter (code.ReadByte ()));
 | 
						|
					break;
 | 
						|
				case OperandType.InlineArg:
 | 
						|
					visitor.OnInlineArgument (opcode, code.GetParameter (code.ReadInt16 ()));
 | 
						|
					break;
 | 
						|
				case OperandType.ShortInlineVar:
 | 
						|
					visitor.OnInlineVariable (opcode, GetVariable (context, code.ReadByte ()));
 | 
						|
					break;
 | 
						|
				case OperandType.InlineVar:
 | 
						|
					visitor.OnInlineVariable (opcode, GetVariable (context, code.ReadInt16 ()));
 | 
						|
					break;
 | 
						|
				case OperandType.InlineTok:
 | 
						|
				case OperandType.InlineField:
 | 
						|
				case OperandType.InlineMethod:
 | 
						|
				case OperandType.InlineType:
 | 
						|
					var member = metadata.LookupToken (code.ReadToken ());
 | 
						|
					switch (member.MetadataToken.TokenType) {
 | 
						|
					case TokenType.TypeDef:
 | 
						|
					case TokenType.TypeRef:
 | 
						|
					case TokenType.TypeSpec:
 | 
						|
						visitor.OnInlineType (opcode, (TypeReference)member);
 | 
						|
						break;
 | 
						|
					case TokenType.Method:
 | 
						|
					case TokenType.MethodSpec:
 | 
						|
						visitor.OnInlineMethod (opcode, (MethodReference)member);
 | 
						|
						break;
 | 
						|
					case TokenType.Field:
 | 
						|
						visitor.OnInlineField (opcode, (FieldReference)member);
 | 
						|
						break;
 | 
						|
					case TokenType.MemberRef:
 | 
						|
						var field_ref = member as FieldReference;
 | 
						|
						if (field_ref != null) {
 | 
						|
							visitor.OnInlineField (opcode, field_ref);
 | 
						|
							break;
 | 
						|
						}
 | 
						|
 | 
						|
						var method_ref = member as MethodReference;
 | 
						|
						if (method_ref != null) {
 | 
						|
							visitor.OnInlineMethod (opcode, method_ref);
 | 
						|
							break;
 | 
						|
						}
 | 
						|
 | 
						|
						throw new InvalidOperationException ();
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		static VariableDefinition GetVariable (ParseContext context, int index)
 | 
						|
		{
 | 
						|
			return context.Variables [index];
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |