Example #1
0
        public override ScriptOp LoadOperation(int offset)
        {
            Reader.BaseStream.Position = offset;
            var opCodeIndex = Reader.ReadByte();

            // 0x7B is the literal highest for Bo2
            if (opCodeIndex > 0x7B)
            {
                return(null);
            }

            ScriptOp operation = new ScriptOp()
            {
                Metadata     = ScriptOpMetadata.OperationInfo[opCodeIndex],
                OpCodeOffset = (int)Reader.BaseStream.Position - 1,
            };

            // Use a type rather than large switch for each operation
            // so we can easily fix bugs and adjust across multiple op codes
            switch (operation.Metadata.OperandType)
            {
            case ScriptOperandType.None:
            {
                break;
            }

            case ScriptOperandType.Int8:
            {
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadSByte()));
                break;
            }

            case ScriptOperandType.UInt8:
            {
                if (operation.Metadata.OpCode == ScriptOpCode.GetNegByte)
                {
                    operation.Operands.Add(new ScriptOpOperand(-Reader.ReadByte()));
                }
                else
                {
                    operation.Operands.Add(new ScriptOpOperand(Reader.ReadByte()));
                }
                break;
            }

            case ScriptOperandType.Int16:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 2);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadInt16()));
                break;
            }

            case ScriptOperandType.UInt16:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 2);
                if (operation.Metadata.OpCode == ScriptOpCode.GetNegUnsignedShort)
                {
                    operation.Operands.Add(new ScriptOpOperand(-Reader.ReadUInt16()));
                }
                else
                {
                    operation.Operands.Add(new ScriptOpOperand(Reader.ReadUInt16()));
                }
                break;
            }

            case ScriptOperandType.Int32:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadInt32()));
                break;
            }

            case ScriptOperandType.UInt32:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadUInt32()));
                break;
            }

            case ScriptOperandType.Hash:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand("\"" + GetHashValue(Reader.ReadUInt32(), "hash_") + "\""));
                break;
            }

            case ScriptOperandType.Float:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadSingle()));
                break;
            }

            case ScriptOperandType.Vector:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadSingle(), Reader.ReadSingle(), Reader.ReadSingle()));
                break;
            }

            case ScriptOperandType.VectorFlags:
            {
                var flags = Reader.ReadByte();

                // Set each flag, it's either 1.0, -1.0, or simply 0.0
                operation.Operands.Add(new ScriptOpOperand(
                                           string.Format("({0}, {1}, {2})",
                                                         (flags & 0x20) != 0 ? 1.0f : (flags & 0x10) != 0 ? -1.0f : 0.0f,
                                                         (flags & 0x08) != 0 ? 1.0f : (flags & 0x04) != 0 ? -1.0f : 0.0f,
                                                         (flags & 0x02) != 0 ? 1.0f : (flags & 0x01) != 0 ? -1.0f : 0.0f)));
                break;
            }

            case ScriptOperandType.String:
            {
                // If it's anim animation, etc. we can just read at the location, but for strings
                // we can just grab via pointer
                switch (operation.Metadata.OpCode)
                {
                case ScriptOpCode.GetString:
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 2);
                    operation.Operands.Add(new ScriptOpOperand("\"" + GetString((int)Reader.BaseStream.Position).Value + "\""));
                    Reader.BaseStream.Position += 2;
                    break;

                case ScriptOpCode.GetIString:
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 2);
                    operation.Operands.Add(new ScriptOpOperand("&\"" + GetString((int)Reader.BaseStream.Position).Value + "\""));
                    Reader.BaseStream.Position += 2;
                    break;

                default:
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                    operation.Operands.Add(new ScriptOpOperand("%" + Reader.PeekNullTerminatedString(Reader.ReadInt32())));
                    break;
                }

                break;
            }

            case ScriptOperandType.VariableName:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 2);
                operation.Operands.Add(new ScriptOpOperand(Reader.PeekNullTerminatedString(Reader.ReadUInt16())));
                break;
            }

            case ScriptOperandType.FunctionPointer:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand(Reader.PeekNullTerminatedString(Reader.ReadInt32())));
                break;
            }

            case ScriptOperandType.Call:
            {
                // Skip param count, it isn't stored here until in memory
                Reader.BaseStream.Position += 1;
                try
                {
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                    operation.Operands.Add(new ScriptOpOperand(Reader.PeekNullTerminatedString(Reader.ReadInt32())));
                }
                catch
                {
                    return(null);
                }
                break;
            }

            case ScriptOperandType.VariableList:
            {
                var varCount = Reader.ReadByte();

                for (int i = 0; i < varCount; i++)
                {
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 2);
                    operation.Operands.Add(new ScriptOpOperand(Reader.PeekNullTerminatedString(Reader.ReadUInt16())));
                }

                break;
            }

            case ScriptOperandType.SwitchEnd:
            {
                var switches = LoadEndSwitch();

                foreach (var switchBlock in switches)
                {
                    operation.Operands.Add(new ScriptOpOperand(switchBlock));
                }
                break;
            }

            default:
            {
                throw new ArgumentException("Invalid Op Type", "OpType");
            }
            }

            operation.OpCodeSize = (int)Reader.BaseStream.Position - offset;

            return(operation);
        }
Example #2
0
        public override ScriptOp LoadOperation(int offset)
        {
            Reader.BaseStream.Position = offset;
            var      opCodeIndex = Reader.ReadUInt16();
            ScriptOp operation;

            // This is literally close to how Black Ops 3 handles it
            // as in, the value is literally an index
            if ((opCodeIndex & 0x2000) == 0)
            {
                if (opCodeIndex > 0x4000)
                {
                    return(null);
                }

                var opCode = OpCodeTable[opCodeIndex];

                if (opCode == ScriptOpCode.Invalid)
                {
                    return(null);
                }

                operation = new ScriptOp()
                {
                    Metadata     = ScriptOpMetadata.OperationInfo[(int)opCode],
                    OpCodeOffset = (int)Reader.BaseStream.Position - 2,
                };
            }
            else
            {
                throw new ArgumentException("Invalid Op Code");
            }

            // Use a type rather than large switch for each operation
            // so we can easily fix bugs and adjust across multiple op codes
            // Like Black Ops 2 all are aligned to different values
            switch (operation.Metadata.OperandType)
            {
            case ScriptOperandType.None:
            {
                break;
            }

            case ScriptOperandType.Int8:
            {
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadSByte()));
                break;
            }

            case ScriptOperandType.UInt8:
            {
                if (operation.Metadata.OpCode == ScriptOpCode.GetNegByte)
                {
                    operation.Operands.Add(new ScriptOpOperand(-Reader.ReadByte()));
                }
                else
                {
                    operation.Operands.Add(new ScriptOpOperand(Reader.ReadByte()));
                }
                break;
            }

            case ScriptOperandType.Int16:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 2);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadInt16()));
                break;
            }

            case ScriptOperandType.UInt16:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 2);
                if (operation.Metadata.OpCode == ScriptOpCode.GetNegUnsignedShort)
                {
                    operation.Operands.Add(new ScriptOpOperand(-Reader.ReadUInt16()));
                }
                else
                {
                    operation.Operands.Add(new ScriptOpOperand(Reader.ReadUInt16()));
                }
                break;
            }

            case ScriptOperandType.Int32:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadInt32()));
                break;
            }

            case ScriptOperandType.UInt32:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadUInt32()));
                break;
            }

            case ScriptOperandType.Hash:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand("\"" + GetHashValue(Reader.ReadUInt32(), "hash_") + "\""));
                break;
            }

            case ScriptOperandType.Float:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadSingle()));
                break;
            }

            case ScriptOperandType.Vector:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                operation.Operands.Add(new ScriptOpOperand(Reader.ReadSingle()));
                break;
            }

            case ScriptOperandType.VectorFlags:
            {
                var flags = Reader.ReadByte();

                // Set each flag, it's either 1.0, -1.0, or simply 0.0
                operation.Operands.Add(new ScriptOpOperand(
                                           string.Format("({0}, {1}, {2})",
                                                         (flags & 0x20) != 0 ? 1.0f : (flags & 0x10) != 0 ? -1.0f : 0.0f,
                                                         (flags & 0x08) != 0 ? 1.0f : (flags & 0x04) != 0 ? -1.0f : 0.0f,
                                                         (flags & 0x02) != 0 ? 1.0f : (flags & 0x01) != 0 ? -1.0f : 0.0f)));
                break;
            }

            case ScriptOperandType.String:
            {
                // If it's anim animation, etc. we can just read at the location, but for strings
                // we can just grab via pointer
                switch (operation.Metadata.OpCode)
                {
                case ScriptOpCode.GetString:
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                    operation.Operands.Add(new ScriptOpOperand("\"" + GetString((int)Reader.BaseStream.Position)?.Value + "\""));
                    Reader.BaseStream.Position += 4;
                    break;

                case ScriptOpCode.GetIString:
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                    operation.Operands.Add(new ScriptOpOperand("&\"" + GetString((int)Reader.BaseStream.Position)?.Value + "\""));
                    Reader.BaseStream.Position += 4;
                    break;

                case ScriptOpCode.GetAnimation:
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 8);
                    operation.Operands.Add(new ScriptOpOperand("%" + Reader.PeekNullTerminatedString(Reader.ReadInt32())));
                    Reader.BaseStream.Position += 4;
                    break;
                }

                break;
            }

            case ScriptOperandType.VariableName:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);

                var name = GetHashValue(Reader.ReadUInt32(), "var_");
                operation.Operands.Add(new ScriptOpOperand(name));
                break;
            }

            case ScriptOperandType.FunctionPointer:
            {
                Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 8);
                operation.Operands.Add(new ScriptOpOperand("&" + GetHashValue(Reader.ReadUInt32(), "function_")));
                Reader.BaseStream.Position += 4;
                break;
            }

            case ScriptOperandType.Call:
            {
                if (operation.Metadata.OpCode == ScriptOpCode.ClassFunctionCall)
                {
                    var paramterCount = Reader.ReadByte();
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                    operation.Operands.Add(new ScriptOpOperand(GetHashValue(Reader.ReadUInt32(), "function_")));
                    operation.Operands.Add(new ScriptOpOperand(paramterCount));
                }
                else
                {
                    // Skip param count, it isn't stored here until in memory
                    Reader.BaseStream.Position += 1;
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 8);
                    operation.Operands.Add(new ScriptOpOperand(GetHashValue(Reader.ReadUInt32(), "function_")));
                    Reader.BaseStream.Position += 4;
                }
                break;
            }

            case ScriptOperandType.VariableList:
            {
                var varCount = Reader.ReadByte();

                for (int i = 0; i < varCount; i++)
                {
                    Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 4);
                    operation.Operands.Add(new ScriptOpOperand(GetHashValue(Reader.ReadUInt32(), "var_")));
                    Reader.BaseStream.Position += 1;
                }

                break;
            }

            case ScriptOperandType.SwitchEnd:
            {
                var switches = LoadEndSwitch();

                foreach (var switchBlock in switches)
                {
                    operation.Operands.Add(new ScriptOpOperand(switchBlock));
                }
                break;
            }

            default:
            {
                throw new ArgumentException("Invalid Op Type", "OpType");
            }
            }

            // Ensure we're at the next op, all operations are aligned to 2 bytes
            Reader.BaseStream.Position += Utility.ComputePadding((int)Reader.BaseStream.Position, 2);

            operation.OpCodeSize = (int)Reader.BaseStream.Position - offset;

            return(operation);
        }