private bool GenerateExpressionCode(ScriptExpression expression, IndentedTextWriter output)
        {
            if (expression.LineNumber == 0)
            {
                return(false);
            }

            _onNewLine = false;
            ScriptValueType type       = _opcodes.GetTypeInfo((ushort)expression.ReturnType);
            ScriptValueType actualType = type;

            if (type.Name != "function_name")
            {
                // Check if a typecast is occurring
                actualType = _opcodes.GetTypeInfo(expression.Opcode);

                if (actualType.Quoted)
                {
                    if (expression.Value != 0xFFFFFFFF)
                    {
                        output.Write("\"{0}\"", expression.StringValue);
                    }
                    else
                    {
                        output.Write("none");
                    }
                    return(true);
                }
            }

            uint value = GetValue(expression, type);

            switch (type.Name)
            {
            case "void":
                return(false);

            case "boolean":
                if (value > 0)
                {
                    output.Write("true");
                }
                else
                {
                    output.Write("false");
                }
                break;

            case "short":
            case "long":
                // Signed integer
                output.Write((int)value);
                break;

            case "real":
                // Eww
                var floatBytes = new byte[4];
                floatBytes[0] = (byte)(value & 0xFF);
                floatBytes[1] = (byte)((value >> 8) & 0xFF);
                floatBytes[2] = (byte)((value >> 16) & 0xFF);
                floatBytes[3] = (byte)((value >> 24) & 0xFF);
                output.Write(BitConverter.ToSingle(floatBytes, 0));
                break;

            case "function_name":
                if (_nextFunctionIsScript)
                {
                    output.Write(expression.StringValue);                             // halo online seems weird in that the "opcode" value that is actually a script index in this case is greater than the number of scripts
                    //output.Write(_scripts.Scripts[expression.Opcode].Name);
                    _nextFunctionIsScript = false;
                }
                else
                {
                    ScriptFunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode);
                    if (info == null)
                    {
                        output.Write("unknown_" + expression.Opcode.ToString("X") + "(" + expression.StringValue + ")");                          //throw new InvalidOperationException("Unrecognized function opcode 0x" + expression.Opcode.ToString("X"));
                    }
                    else
                    {
                        output.Write(info.Name);
                    }
                }
                break;

            case "unit_seat_mapping":
                // This isn't the technical way of doing this,
                // but since seat mapping names aren't stored anywhere,
                // it would be tricky to resolve them unless we just use an index for now
                if (expression.Value != 0xFFFFFFFF)
                {
                    output.Write(expression.Value & 0xFFFF);
                }
                else
                {
                    output.Write("none");
                }
                break;

            default:
                string enumValue = actualType.GetEnumValue(value);
                if (enumValue != null)
                {
                    output.Write(enumValue);
                }
                else if (expression.Value == 0xFFFFFFFF)
                {
                    output.Write("none");
                }
                else
                {
                    enumValue = expression.StringValue;
                    if (enumValue != null)
                    {
                        output.Write(enumValue);
                    }
                    else
                    {
                        output.Write("0x{0:X}", value);
                    }
                }
                break;
            }
            return(true);
        }
Beispiel #2
0
        private bool GenerateExpressionCode(ScriptExpression expression, IndentedTextWriter output)
        {
            if (expression.LineNumber == 0)
            {
                return(false);
            }

            _onNewLine = false;
            ScriptValueType type       = _opcodes.GetTypeInfo((ushort)expression.ReturnType);
            ScriptValueType actualType = type;

            if (type.Name != "function_name")
            {
                // Check if a typecast is occurring

                if (expression.Opcode != 0xFFFF)
                {
                    actualType = _opcodes.GetTypeInfo(expression.Opcode);

                    if (actualType.Quoted)
                    {
                        if (expression.Value.UintValue != 0xFFFFFFFF)
                        {
                            output.Write("\"{0}\"", expression.StringValue);
                        }
                        else
                        {
                            output.Write("none");
                        }
                        return(true);
                    }
                }
            }

            uint value = GetValue(expression, type, _endian);

            byte[] val = BitConverter.GetBytes(value);

            switch (type.Name)
            {
            case "void":
                return(false);

            case "boolean":
                if (BitConverter.ToBoolean(val, 0))
                {
                    output.Write("true");
                }
                else
                {
                    output.Write("false");
                }
                break;

            case "short":
                output.Write(BitConverter.ToInt16(val, 0));
                break;

            case "long":
                // Signed integer
                output.Write((int)value);
                break;

            case "real":
                // Eww
                //var floatBytes = new byte[4];
                //floatBytes[0] = (byte) (value & 0xFF);
                //floatBytes[1] = (byte) ((value >> 8) & 0xFF);
                //floatBytes[2] = (byte) ((value >> 16) & 0xFF);
                //floatBytes[3] = (byte) ((value >> 24) & 0xFF);
                var fl = BitConverter.ToSingle(val, 0);
                output.Write(fl.ToString("0.0#######", CultureInfo.InvariantCulture));
                break;

            case "function_name":
                if (_nextFunctionIsScript)
                {
                    if (expression.Opcode >= _scripts.Scripts.Count)
                    {
                        output.Write("import#" + expression.StringValue);
                    }
                    else
                    {
                        output.Write(expression.StringValue);                                 // todo: there are cases (h3 xbox mainmenu's campaign_cam specifically) where the function_name expression's opcode value is +1 from what it should be, and the expression prior has the right index.
                    }
                    // the current state of this script code doesnt seem to be good enough to step back so here is the hacky fix implemented in the HO fork.

                    //output.Write(_scripts.Scripts[expression.Opcode].Name);

                    _nextFunctionIsScript = false;
                }
                else
                {
                    FunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode);
                    if (info == null)
                    {
                        output.Write("UNNAMED_OPCODE_" + expression.Opcode.ToString("X4") + "#" + expression.StringValue);
                    }
                    else
                    {
                        output.Write(info.Name);
                    }
                    //throw new InvalidOperationException("Unrecognized function opcode 0x" + expression.Opcode.ToString("X"));
                }
                break;

            case "unit_seat_mapping":
                // This isn't the technical way of doing this,
                // but since seat mapping names aren't stored anywhere,
                // it would be tricky to resolve them unless we just use an index for now
                if (expression.Value.UintValue != 0xFFFFFFFF)
                {
                    output.Write(expression.StringValue);
                }
                else
                {
                    output.Write("none");
                }
                break;

            case "unparsed":
                break;

            default:
                string enumValue = actualType.GetEnumValue(value);
                if (enumValue != null)
                {
                    output.Write(enumValue);
                }
                else if (expression.Value.IsNull)
                {
                    output.Write("none");
                }
                else
                {
                    enumValue = expression.StringValue;
                    if (enumValue != null)
                    {
                        output.Write(enumValue);
                    }
                    else
                    {
                        output.Write("0x{0:X}", value);
                    }
                }
                break;
            }
            return(true);
        }
Beispiel #3
0
        /// <summary>
        /// The decompiler generates a literal (expression) on an expression.
        /// </summary>
        /// <param name="output">The output.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="newLine">Indicates whether the expressions of the branch start on a new line.</param>
        /// <returns>Returns true if code was generated.</returns>
        private bool GenerateExpression(IndentedTextWriter output, ScriptExpression expression, bool newLine)
        {
            ScriptValueType type       = _opcodes.GetTypeInfo(expression.ReturnType);
            ScriptValueType actualType = type;

            // Check if a typecast is occurring
            if (expression.Opcode != 0xFFFF)
            {
                actualType = _opcodes.GetTypeInfo(expression.Opcode);

                // Simply write the string for quoted expressions.
                if (actualType.Quoted)
                {
                    // Don't quote the keyword none.
                    if (expression.Value.IsNull || expression.StringValue == "none")
                    {
                        output.Write("none");
                    }
                    else
                    {
                        output.Write("\"{0}\"", ScriptStringHelpers.Escape(expression.StringValue));
                    }
                    return(false);
                }
            }

            uint value = GetValue(expression, actualType);

            byte[] val = BitConverter.GetBytes(value);
            string text;


            switch (actualType.Name)
            {
            case "void":
                text = "";
                break;

            case "ai_command_script":
            case "script":
                short index = BitConverter.ToInt16(val, 0);
                text = _scripts.Scripts[index].Name;
                break;

            case "boolean":
                text = BitConverter.ToBoolean(val, 0) ? "true" : "false";
                break;

            case "short":
                text = BitConverter.ToInt16(val, 0).ToString();
                break;

            case "long":
                // Signed integer
                int signed = (int)value;
                text = signed.ToString();
                break;

            case "real":
                float fl = BitConverter.ToSingle(val, 0);
                text = fl.ToString("0.0#######", CultureInfo.InvariantCulture);
                break;

            case "ai_line":
                text = expression.StringValue == "" ? "\"\"" : expression.StringValue;
                break;

            case "unit_seat_mapping":
                text = expression.Value.IsNull ? "none" : expression.StringValue;
                break;

            default:
                if (expression.Value.IsNull)
                {
                    text = "none";
                }
                else if (actualType.IsEnum)
                {
                    string enumValue = actualType.GetEnumValue(value);
                    if (enumValue != null)
                    {
                        text = enumValue;
                    }
                    else
                    {
                        throw new NotImplementedException("Unknown Enum Value.");
                    }
                }
                else
                {
                    //throw new NotImplementedException($"Unhandled Return Type: \"{actualType.Name}\".");
                    text = expression.StringValue;
                }

                break;
            }

            output.Write(text);
            HandleNewLine(output, newLine);
            return(false);
        }