Пример #1
0
        // Interpreting
        public static string[] ParseScript(uint[] cmd, int sanity = -1)
        {
            // sub_148CBC Moon v1.0
            List <string> parse      = new List <string>();
            const int     sanityMode = 0; // todo

            string ErrorNear(int line, string error)
            {
                var start   = Math.Max(line - 6, 0);
                var end     = Math.Min(line + 6, cmd.Length - 1);
                var toPrint = cmd.Skip(start).Take(end - start);
                var message = $"Error at line {line}:" + Environment.NewLine;

                message += string.Join(" ", toPrint.Select(b => $"{b:X2}")) + Environment.NewLine;

                for (var x = 0; x < line - start; x++)
                {
                    message += "   ";
                }

                message += "^^" + Environment.NewLine;
                message += error;

                return(message);
            }

            int i = 0;             // Current Offset of decompressed instructions

            while (i < cmd.Length) // read away
            {
                // Read a Command

                string instrLine;
                var    line       = i;
                var    opcodeval  = cmd[i++];
                var    opcodesafe = opcodeval & 0xFFFF;

                if (!Enum.IsDefined(typeof(AmxOpCode), opcodesafe))
                {
                    throw new ArgumentException(ErrorNear(line, $"Invalid command ID: {opcodesafe:X4} ({opcodesafe})"));
                }

                var opcode = (AmxOpCode)opcodesafe;

                if (!OpCodeTypes.TryGetValue(opcode, out var optype))
                {
                    throw new ArgumentException(ErrorNear(line, $"Unknown OpCode: {opcodesafe:X4} ({opcodesafe})"));
                }

                switch (optype)
                {
                default:
                    throw new ArgumentException("Invalid Command Type");

                case AmxOpCodeType.NoParams:
                {
                    instrLine = EchoIntCommand(opcode);
                    break;
                }

                case AmxOpCodeType.OneParam:
                {
                    var param = (int)cmd[i++];

                    instrLine = EchoIntCommand(opcode, param);
                    break;
                }

                case AmxOpCodeType.TwoParams:
                {
                    var param1 = (int)cmd[i++];
                    var param2 = (int)cmd[i++];

                    instrLine = EchoIntCommand(opcode, param1, param2);
                    break;
                }

                case AmxOpCodeType.ThreeParams:
                {
                    var param1 = (int)cmd[i++];
                    var param2 = (int)cmd[i++];
                    var param3 = (int)cmd[i++];

                    instrLine = EchoIntCommand(opcode, param1, param2, param3);
                    break;
                }

                case AmxOpCodeType.FourParams:
                {
                    var param1 = (int)cmd[i++];
                    var param2 = (int)cmd[i++];
                    var param3 = (int)cmd[i++];
                    var param4 = (int)cmd[i++];

                    instrLine = EchoIntCommand(opcode, param1, param2, param3, param4);
                    break;
                }

                case AmxOpCodeType.FiveParams:
                {
                    var param1 = (int)cmd[i++];
                    var param2 = (int)cmd[i++];
                    var param3 = (int)cmd[i++];
                    var param4 = (int)cmd[i++];
                    var param5 = (int)cmd[i++];

                    instrLine = EchoIntCommand(opcode, param1, param2, param3, param4, param5);
                    break;
                }

                case AmxOpCodeType.Jump:
                {
                    var jumpOffset = (int)cmd[i++];
                    var jumpDest   = (line * 4) + jumpOffset;

                    instrLine = $"{Commands[opcode].PadRight(MaxCommandLength, ' ')} => 0x{jumpDest:X4} ({jumpOffset})";
                    break;
                }

                case AmxOpCodeType.Packed:
                {
                    var param = (short)(opcodeval >> 16);

                    instrLine = EchoIntCommand(opcode, param);
                    break;
                }

                case AmxOpCodeType.CaseTable:
                {
                    //var jOffset = (i * 4) - 4; // this may be the correct jump start point...
                    var count = cmd[i++];         // switch case table
                                                  // sanity check

                    // Populate Switch-Case Tree
                    var tree = new List <string>();

                    // Cases
                    for (int j = 0; j < count; j++)
                    {
                        var jmp      = (int)cmd[i++];
                        var toOffset = ((i - 2) * 4) + jmp;
                        var ifValue  = (int)cmd[i++];
                        tree.Add($"\t{ifValue} => 0x{toOffset:X4} ({jmp})");
                    }

                    // Default
                    {
                        int jmp      = (int)cmd[i++];
                        var toOffset = ((i - 2) * 4) + jmp;
                        tree.Add($"\t* => 0x{toOffset:X4} ({jmp})");
                    }

                    instrLine = Commands[opcode] + Environment.NewLine + string.Join(Environment.NewLine, tree);
                    break;
                }
                }

                if (opcode == AmxOpCode.RET || opcode == AmxOpCode.RETN || opcode == AmxOpCode.IRETN)
                {
                    // Newline after return
                    instrLine += Environment.NewLine;
                }

                if (parse.Count == 0 && opcode == AmxOpCode.HALT_P)
                {
                    // Newline after 0x0000 HALT.P
                    instrLine += Environment.NewLine;
                }

                parse.Add($"0x{line * 4:X4}: [{opcodeval & 0x7FF:X2}] {instrLine}");
            }

            if (sanity >= 0 && sanity != sanityMode)
            {
                throw new ArgumentException();
            }

            return(parse.ToArray());
        }