internal void ProcessInternal(Patcher p, Target target)
        {
            p.Method       = p.FindMethod(target.FullName).ResolveMethodDef();
            p.Instructions = p.Method.Body.Instructions;

            if (target.ILCodes != null && target.ILCodes.Count > 0)
            {
                ScriptEngineHelpers.ParseILCodes(p, target);
            }

            ScriptEngineHelpers.PatchTarget(p, target);

            ScriptEngineHelpers.WriteActionToLog(target);
        }
        internal static void PatchTarget(Patcher p, Target target)
        {
            p.BackupExceptionHandlersIndices();

            switch (target.Action)
            {
            case ActionMethod.Patch:
                p.Patch(target);
                break;

            case ActionMethod.Insert:
                p.Insert(target);
                break;

            case ActionMethod.Replace:
                p.Replace(target);
                break;

            case ActionMethod.Remove:
                p.Remove(target);
                break;

            case ActionMethod.EmptyBody:
                p.EmptyBody(target);
                break;

            case ActionMethod.ReturnBody:
                p.ReturnBody(target, Convert.ToBoolean(target.Optional));
                break;

            default:
                throw new PatcherException("Invalid action method", target.FullName);
            }

            p.FixOffsets();
            p.FixExceptionHandlers();
            p.FixBranches();
        }
        internal static void ParseILCodes(Patcher p, Target target)
        {
            target.Instructions = new Instruction[target.ILCodes.Count];

            for (int i = 0; i < target.Instructions.Length; i++)
            {
                string opcode = target.ILCodes[i].OpCode;

                if (opcode == null)
                {
                    throw new PatcherException("OpCode is empty", target.FullName);
                }

                target.Instructions[i] = new Instruction(Helpers.GetOpCodeFromString(opcode.Replace('_', '.')));
            }

            for (int i = 0; i < target.Instructions.Length; i++)
            {
                string operand = target.ILCodes[i].Operand;

                if (operand != null)
                {
                    switch (target.Instructions[i].OpCode.OperandType)
                    {
                    case OperandType.InlineBrTarget:
                    case OperandType.ShortInlineBrTarget:
                        if (target.Action == ActionMethod.Patch)
                        {
                            target.Instructions[i].Operand = p.GetInstruction(target, operand.ToInt());
                        }
                        else
                        {
                            target.Instructions[i].Operand = p.GetInstruction(operand.ToInt());
                        }
                        break;

                    case OperandType.InlineField:
                        target.Instructions[i].Operand = p.FindField(operand);
                        break;

                    case OperandType.InlineI:
                        target.Instructions[i].Operand = operand.ToInt();
                        break;

                    case OperandType.InlineI8:
                        target.Instructions[i].Operand = operand.ToLong();
                        break;

                    case OperandType.InlineMethod:
                        target.Instructions[i].Operand = p.FindMethod(operand);
                        break;

                    case OperandType.InlineNone:
                    case OperandType.InlinePhi:
                    case OperandType.NOT_USED_8:
                        target.Instructions[i].Operand = null;
                        break;

                    case OperandType.InlineR:
                        target.Instructions[i].Operand = operand.ToDouble();
                        break;

                    case OperandType.InlineSig:
                        target.Instructions[i].Operand = p.FindMethod(operand).MethodSig;
                        break;

                    case OperandType.InlineString:
                        target.Instructions[i].Operand = operand;
                        break;

                    case OperandType.InlineSwitch:
                        string[] array = operand.Split(Constants.DefaultSeparator);

                        Instruction[] instructions = new Instruction[array.Length];

                        for (var j = 0; j < array.Length; j++)
                        {
                            if (target.Action == ActionMethod.Patch)
                            {
                                instructions[j] = p.GetInstruction(target, array[j].ToInt());
                            }
                            else
                            {
                                instructions[j] = p.GetInstruction(array[j].ToInt());
                            }
                        }

                        target.Instructions[i].Operand = instructions;
                        break;

                    case OperandType.InlineTok:
                        target.Instructions[i].Operand = p.FindMethodFieldOrType(operand);
                        break;

                    case OperandType.InlineType:
                        target.Instructions[i].Operand = p.FindType(operand);
                        break;

                    case OperandType.InlineVar:
                        target.Instructions[i].Operand = p.Method.Parameters[operand.ToInt()];
                        break;

                    case OperandType.ShortInlineI:
                        target.Instructions[i].Operand = target.Instructions[i].OpCode.Code == Code.Ldc_I4_S ? (object)operand.ToSByte() : operand.ToByte();
                        break;

                    case OperandType.ShortInlineR:
                        target.Instructions[i].Operand = operand.ToFloat();
                        break;

                    case OperandType.ShortInlineVar:
                        target.Instructions[i].Operand = p.Method.Parameters[operand.ToInt()];
                        break;
                    }
                }
            }

            target.ILCodes = null; //We don't need that anymore.
        }
        public override void Process()
        {
            int patchedFileCount = 0;

            try
            {
                foreach (var patch in CurrentScript.PatchList)
                {
                    foreach (string path in patch.TargetInfo.TargetFiles)
                    {
                        string filePath = path;

                        if (!File.Exists(filePath))
                        {
                            Logger.Error($"File not found -> {filePath}");

                            using (var ofd = new OpenFileDialog())
                            {
                                ofd.FileName        = Path.GetFileName(filePath);
                                ofd.Filter          = "Executable files (.exe;*.dll)|*.exe;*.dll|All files (*.*)|*.*";
                                ofd.CheckFileExists = true;

                                string directoryName = Path.GetDirectoryName(filePath);

                                if (Directory.Exists(directoryName))
                                {
                                    ofd.InitialDirectory = directoryName;
                                }
                                else
                                {
                                    ofd.RestoreDirectory = true;
                                }

                                if (ofd.ShowDialog() == DialogResult.OK)
                                {
                                    filePath = ofd.FileName;
                                }
                                else
                                {
                                    Logger.Log("[Skipping file]");
                                    Logger.Log();
                                    continue;
                                }
                            }
                        }

                        bool keepOldMaxStack = patch.TargetInfo.KeepOldMaxStack;

                        using (var p = new Patcher(filePath, keepOldMaxStack))
                        {
                            Logger.Log($"[File Path] -> {filePath} {(keepOldMaxStack ? "-> KeepOldMaxStack: True" : string.Empty)}");

                            foreach (var target in patch.TargetList)
                            {
                                ProcessInternal(p, target);
                            }

                            p.Save(Convert.ToBoolean(CurrentScript.PatcherOptions.PatcherInfo.MakeBackup));
                        }

                        patchedFileCount++;

                        Logger.Log($"[File Patched] -> {filePath}");
                        Logger.Log();
                    }

                    Logger.Log();
                }
            }
            catch (Exception ex)
            {
                Logger.Error($"{ex.Message}{(Program.IsDebugModeEnabled ? $"\r\n{ex.StackTrace}" : string.Empty)}");
                Logger.Log();
            }

            Logger.Info(patchedFileCount > 0 ? $"Patching process finished! [{patchedFileCount} file(s) patched]" : "Nothing patched!");
        }