示例#1
0
 internal void ResolveReferences(ScriptExpressionTable allExpressions)
 {
     if (_nextIndex.IsValid)
     {
         Next = allExpressions.FindExpression(_nextIndex);
     }
 }
示例#2
0
        private bool GenerateVariableReference(ScriptExpression expression, IndentedTextWriter output, bool islocal = false)
        {
            _onNewLine = false;
            string varDesc = islocal ? ("var_" + expression.Value.ToString() + "#") : "";

            output.Write(varDesc + expression.StringValue);
            return(true);
        }
示例#3
0
        private bool GenerateScriptReference(ScriptExpression expression, IndentedTextWriter output)
        {
            var expressionIndex = new DatumIndex(expression.Value.UintValue);

            _nextFunctionIsScript = true;
            GenerateCode(_scripts.Expressions.FindExpression(expressionIndex), output);
            _nextFunctionIsScript = false;
            return(true);
        }
示例#4
0
        /// <summary>
        /// Determines whether an expression is a multiline construct.
        /// </summary>
        /// <param name="expression"></param>
        /// <returns>Returns true if the expression is a multiline construct.</returns>
        private bool IsMultilineExpression(ScriptExpression expression)
        {
            if (expression.Type == ScriptExpressionType.Group)
            {
                FunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode);
                return(info.Name == "if" || info.Name == "or" || info.Name == "and" || info.Name.StartsWith("begin"));
            }

            return(false);
        }
示例#5
0
 private uint GetValue(ScriptExpression expression, ScriptValueType type, Endian endian)
 {
     if (endian == Endian.BigEndian)
     {
         return(expression.Value.UintValue >> (32 - (type.Size * 8)));
     }
     else
     {
         return(expression.Value.UintValue);
     }
 }
示例#6
0
        private bool GenerateGroup(ScriptExpression expression, IndentedTextWriter output)
        {
            var childIndex = new DatumIndex(expression.Value.UintValue);

            if (!childIndex.IsValid)
            {
                throw new InvalidOperationException("Group expression has no child");
            }

            GenerateCode(_scripts.Expressions.FindExpression(childIndex), output);
            return(true);
        }
示例#7
0
        /// <summary>
        /// The decompiler generates a cond construct based on an expression.
        /// </summary>
        /// <param name="output">The output.</param>
        /// <param name="expression">The cond 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 GenerateCond(IndentedTextWriter output, ScriptExpression expression, bool newLine)
        {
            int startIndent = output.Indent;

            // Handle the initial con group.
            if (!_cond)
            {
                // indicate that the following expressions are part of a cond construct.
                _cond       = true;
                _condIndent = output.Indent + 1;

                output.WriteLine("(cond");

                // increase indent for the first conditional and write the opening parenthesis.
                output.Indent++;
                output.Write("(");

                // generate code.
                DatumIndex nameIndex = new DatumIndex(expression.Value.UintValue);
                FollowRootIndex(output, nameIndex, false, BranchType.Cond);

                // write the closing parenthesis of the last conditional.
                output.Indent = startIndent + 1;
                output.WriteLine(")");

                // write the closing parenthesis of the cond call.
                output.Indent = startIndent;
                output.Write(")");

                _cond = false;
            }

            // handle all following conditionals.
            else
            {
                output.Indent = _condIndent;

                // close the previous cond group and open the current one.
                output.WriteLine(")");
                output.Write("(");

                // generate code.
                DatumIndex nameIndex = new DatumIndex(expression.Value.UintValue);
                FollowRootIndex(output, nameIndex, false, BranchType.Cond);

                output.Indent = startIndent;
            }

            HandleNewLine(output, newLine);
            return(true);
        }
示例#8
0
        private bool GenerateVariableDecl(ScriptExpression expression, IndentedTextWriter output)
        {
            _onNewLine = false;
            output.Write("(local ");
            var expressionIndex = new DatumIndex(expression.Value.UintValue);

            _nextExpressionIsVar = true;
            _varTypeWritten      = false;
            GenerateCode(_scripts.Expressions.FindExpression(expressionIndex), output);
            _nextExpressionIsVar = false;
            localVarCounter++;
            output.Write(")");
            return(true);
        }
示例#9
0
        private bool HandleExpression(ScriptExpression expression, IndentedTextWriter output)
        {
            short realtype    = (short)expression.Type;
            short clippedtype = (short)((short)expression.Type & 0xFF);

            switch ((ScriptExpressionType)clippedtype)
            {
            case ScriptExpressionType.Expression:
            case ScriptExpressionType.Expression4:
                return(GenerateExpressionCode(expression, output));

            case ScriptExpressionType.GlobalsReference:
            case ScriptExpressionType.GlobalsReference4:
            {
                if ((realtype & 0xFF00) > 0)
                {
                    return(GenerateVariableReference(expression, output, true));
                }
                else
                {
                    return(GenerateGlobalsReference(expression, output));
                }
            }


            case ScriptExpressionType.ParameterReference:
            case ScriptExpressionType.ParameterReference4:
                return(GenerateParameterReference(expression, output));

            case ScriptExpressionType.ScriptReference:
            case ScriptExpressionType.ScriptReference4:
                return(GenerateScriptReference(expression, output));

            case ScriptExpressionType.Group:
            case ScriptExpressionType.Group4:
                return(GenerateGroup(expression, output));

            case ScriptExpressionType.VariableReference4:
                return(GenerateVariableReference(expression, output));

            case ScriptExpressionType.VariableDecl4:
                return(GenerateVariableDecl(expression, output));

            default:
                throw new InvalidOperationException("Unknown script expression type");
            }
        }
示例#10
0
        /// <summary>
        /// The decompiler generates a function group based on an expression.
        /// </summary>
        /// <param name="output">The output.</param>
        /// <param name="expression">The group 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 GenerateGroup(IndentedTextWriter output, ScriptExpression expression, bool newLine)
        {
            DatumIndex   nameIndex = new DatumIndex(expression.Value.UintValue);
            FunctionInfo info      = _opcodes.GetFunctionInfo(expression.Opcode);

            // filter out begin groups which were added by the compiler.
            if (expression.LineNumber == 0)
            {
                if (info.Name == "if")
                {
                    throw new Exception("The decompiler failed to catch a cond call.");
                }

                FollowRootIndex(output, nameIndex, true, BranchType.CompilerBegin);
                return(true);
            }

            int startIndent = output.Indent;

            // write the call's opening parenthesis and name.
            output.Write($"({info.Name}");

            // handle regular begin calls.
            if (info.Name.StartsWith("begin") || info.Name == "or" || info.Name == "and" || info.Name == "branch")
            {
                FollowRootIndex(output, nameIndex, true, BranchType.Multiline);
                output.Indent = startIndent;
            }
            // handle if calls.
            else if (info.Name == "if")
            {
                FollowRootIndex(output, nameIndex, false, BranchType.If);
                output.Indent = startIndent;
            }
            // handle all other (normal) calls.
            else
            {
                FollowRootIndex(output, nameIndex, false, BranchType.Call);
            }

            // write the call's closing parenthesis.
            output.Write(")");

            HandleNewLine(output, newLine);
            return(true);
        }
示例#11
0
        /// <summary>
        /// The decompiler generates a script reference based on an expression.
        /// </summary>
        /// <param name="output">The output.</param>
        /// <param name="expression">The script reference 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 GenerateScriptReference(IndentedTextWriter output, ScriptExpression expression, bool newLine)
        {
            // we need to retrieve the script's name from its function_name expression. Otherwise branch calls will become corrupt.
            DatumIndex nameIndex = new DatumIndex(expression.Value.UintValue);
            var        nameExp   = _scripts.Expressions.FindExpression(nameIndex);

            // write the call's opening parenthesis and name.
            output.Write($"({nameExp.StringValue}");

            // write code
            FollowRootIndex(output, nameIndex, false, BranchType.Call);

            // write the call's closing parenthesis.
            output.Write(")");
            HandleNewLine(output, newLine);
            return(true);
        }
示例#12
0
 /// <summary>
 /// Retrieves an expression's value. Takes endianness into account.
 /// </summary>
 /// <param name="expression">The expression from which the value is being retrieved.</param>
 /// <param name="type">The value type of the expression.</param>
 /// <returns></returns>
 private uint GetValue(ScriptExpression expression, ScriptValueType type)
 {
     if (_endian == Endian.BigEndian)
     {
         return(expression.Value.UintValue >> (32 - (type.Size * 8)));
     }
     else
     {
         var  bytes  = BitConverter.GetBytes(expression.Value.UintValue);
         uint result = type.Size switch
         {
             4 => expression.Value.UintValue,
             2 => BitConverter.ToUInt16(bytes, 0),
             1 => bytes[0],
             0 => 0,
             _ => throw new ArgumentException($"Script value types can only have a size of 0, 1, 2 or 4 bytes. The size {type.Size} is invalid.")
         };
         return(result);
     }
 }
示例#13
0
        /// <summary>
        /// Decides how an expression will be handled and which actions to perform, based on the expression type.
        /// </summary>
        /// <param name="output">The output.</param>
        /// <param name="expression">The expression, which is being handled.</param>
        /// <param name="newLine">Indicates whether the expressions of the branch start on a new line.</param>
        private void HandleExpression(IndentedTextWriter output, ScriptExpression expression, bool newLine)
        {
            ushort ifOp        = _opcodes.GetFunctionInfo("if")[0].Opcode;
            ushort funcNameOp  = _opcodes.GetTypeInfo("function_name").Opcode;
            short  clippedtype = (short)((short)expression.Type & 0xFF);

            bool _ = (ScriptExpressionType)clippedtype switch
            {
                ScriptExpressionType.Group when expression.Opcode == ifOp && expression.LineNumber == 0 => GenerateCond(output, expression, newLine),
                ScriptExpressionType.Group => GenerateGroup(output, expression, newLine),

                ScriptExpressionType.Expression when expression.ReturnType == funcNameOp => true,
                ScriptExpressionType.Expression => GenerateExpression(output, expression, newLine),

                ScriptExpressionType.ScriptReference => GenerateScriptReference(output, expression, newLine),
                ScriptExpressionType.GlobalsReference => GenerateGlobalsReference(output, expression, newLine),
                ScriptExpressionType.ParameterReference => GenerateParameterReference(output, expression, newLine),

                _ => throw new NotImplementedException($"The Decompiler encountered an unknown Expression Type: \"{(ScriptExpressionType)clippedtype}\".")
            };
        }
        private bool HandleExpression(ScriptExpression expression, IndentedTextWriter output)
        {
            switch (expression.Type)
            {
            case ScriptExpressionType.Expression:
                return(GenerateExpressionCode(expression, output));

            case ScriptExpressionType.GlobalsReference:
                return(GenerateGlobalsReference(expression, output));

            case ScriptExpressionType.ParameterReference:
                return(GenerateParameterReference(expression, output));

            case ScriptExpressionType.ScriptReference:
                return(GenerateScriptReference(expression, output));

            case ScriptExpressionType.Group:
                return(GenerateGroup(expression, output));

            default:
                throw new InvalidOperationException("Unknown script expression type");
            }
        }
        private uint GetValue(ScriptExpression expression, ScriptValueType type)
        {
            //var valBytes = new byte[4];
            uint newVal = 0;

            byte[] valBytes = new byte[4];

            switch (type.Size)
            {
            case 1:
                valBytes[0] = 0;
                valBytes[1] = 0;
                valBytes[2] = 0;
                valBytes[3] = (byte)(expression.Value);
                break;

            case 2:
                valBytes[0] = 0;
                valBytes[1] = 0;
                valBytes[2] = (byte)(expression.Value);
                valBytes[3] = (byte)(expression.Value >> 8);
                break;

            default:
            case 4:
                valBytes[0] = (byte)(expression.Value);
                valBytes[1] = (byte)(expression.Value >> 8);
                valBytes[2] = (byte)(expression.Value >> 16);
                valBytes[3] = (byte)(expression.Value >> 24);
                break;
            }

            newVal = BitConverter.ToUInt32(valBytes, 0);

            return(newVal >> (32 - (type.Size * 8)));
            //return expression.Value >> (32 - (type.Size*8));
        }
示例#16
0
		internal void ResolveReferences(ScriptExpressionTable allExpressions)
		{
			if (_nextIndex.IsValid)
				Next = allExpressions.FindExpression(_nextIndex);
		}
示例#17
0
		private void GenerateCode(ScriptExpression expression, IndentedTextWriter output)
		{
			int firstIndentedArg = int.MaxValue;
			bool isFunctionCall = false;

			if (expression.Type == ScriptExpressionType.Expression)
			{
				ScriptValueType type = _opcodes.GetTypeInfo((ushort) expression.ReturnType);
				if (type.Name == "function_name")
				{
					isFunctionCall = true;

					if (!_nextFunctionIsScript)
					{
						ScriptFunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode);
						if (info != null)
						{
							if (info.Name.StartsWith("begin"))
							{
								firstIndentedArg = 0;
								if (expression.LineNumber > 0 && !_onNewLine)
								{
									output.Indent++;
									output.WriteLine();
								}
							}
							else if (info.Name == "if")
							{
								firstIndentedArg = 1;
							}
						}
					}
					if (expression.LineNumber > 0)
						output.Write("(");
				}
			}

			bool wroteAnything = HandleExpression(expression, output);
			int startIndent = output.Indent;

			int currentArg = 0;
			ScriptExpression sibling = expression.Next;
			while (sibling != null)
			{
				if (wroteAnything)
				{
					if (currentArg == firstIndentedArg)
						output.Indent++;
					if (currentArg >= firstIndentedArg || output.Indent != startIndent)
					{
						output.WriteLine();
						_onNewLine = true;
					}
					else
					{
						output.Write(" ");
					}
				}

				wroteAnything = HandleExpression(sibling, output);
				sibling = sibling.Next;
				currentArg++;
			}

			if (isFunctionCall && expression.LineNumber > 0)
			{
				if (output.Indent != startIndent)
				{
					output.Indent = startIndent;
					if (wroteAnything)
						output.WriteLine();
					output.Write(")");
					_onNewLine = true;
				}
				else
				{
					output.Write(")");
				}
			}
		}
示例#18
0
		private uint GetValue(ScriptExpression expression, ScriptValueType type)
		{
			//var valBytes = new byte[4];
			uint newVal = 0;
			byte[] valBytes = new byte[4];

			switch(type.Size)
			{
				case 1:
					valBytes[0] = 0;
					valBytes[1] = 0;
					valBytes[2] = 0;
					valBytes[3] = (byte)(expression.Value);
					break;
				case 2:
					valBytes[0] = 0;
					valBytes[1] = 0;
					valBytes[2] = (byte)(expression.Value);
					valBytes[3] = (byte)(expression.Value >> 8);
					break;
				default:
				case 4:
					valBytes[0] = (byte)(expression.Value);
					valBytes[1] = (byte)(expression.Value >> 8);
					valBytes[2] = (byte)(expression.Value >> 16);
					valBytes[3] = (byte)(expression.Value >> 24);
					break;
			}

			newVal = BitConverter.ToUInt32(valBytes, 0);

			return newVal >> (32 - (type.Size * 8));
			//return expression.Value >> (32 - (type.Size*8));
		}
示例#19
0
		private bool GenerateGroup(ScriptExpression expression, IndentedTextWriter output)
		{
			var childIndex = new DatumIndex(expression.Value);
			if (!childIndex.IsValid)
				throw new InvalidOperationException("Group expression has no child");

			GenerateCode(_scripts.Expressions.FindExpression(childIndex), output);
			return true;
		}
示例#20
0
 private bool GenerateParameterReference(ScriptExpression expression, IndentedTextWriter output)
 {
     _onNewLine = false;
     output.Write(expression.StringValue);
     return(true);
 }
示例#21
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);
        }
示例#22
0
 private uint GetValue(ScriptExpression expression, ScriptValueType type)
 {
     return expression.Value >> (32 - (type.Size*8));
 }
        private void GenerateCode(ScriptExpression expression, IndentedTextWriter output)
        {
            int  firstIndentedArg = int.MaxValue;
            bool isFunctionCall   = false;

            if (expression.Type == ScriptExpressionType.Expression)
            {
                ScriptValueType type = _opcodes.GetTypeInfo((ushort)expression.ReturnType);
                if (type.Name == "function_name")
                {
                    isFunctionCall = true;

                    if (!_nextFunctionIsScript)
                    {
                        ScriptFunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode);
                        if (info != null)
                        {
                            if (info.Name.StartsWith("begin"))
                            {
                                firstIndentedArg = 0;
                                if (expression.LineNumber > 0 && !_onNewLine)
                                {
                                    output.Indent++;
                                    output.WriteLine();
                                }
                            }
                            else if (info.Name == "if")
                            {
                                firstIndentedArg = 1;
                            }
                        }
                    }
                    if (expression.LineNumber > 0)
                    {
                        output.Write("(");
                    }
                }
            }

            bool wroteAnything = HandleExpression(expression, output);
            int  startIndent   = output.Indent;

            int currentArg           = 0;
            ScriptExpression sibling = expression.Next;

            while (sibling != null)
            {
                if (wroteAnything)
                {
                    if (currentArg == firstIndentedArg)
                    {
                        output.Indent++;
                    }
                    if (currentArg >= firstIndentedArg || output.Indent != startIndent)
                    {
                        output.WriteLine();
                        _onNewLine = true;
                    }
                    else
                    {
                        output.Write(" ");
                    }
                }

                wroteAnything = HandleExpression(sibling, output);
                sibling       = sibling.Next;
                currentArg++;
            }

            if (isFunctionCall && expression.LineNumber > 0)
            {
                if (output.Indent != startIndent)
                {
                    output.Indent = startIndent;
                    if (wroteAnything)
                    {
                        output.WriteLine();
                    }
                    output.Write(")");
                    _onNewLine = true;
                }
                else
                {
                    output.Write(")");
                }
            }
        }
 public void WriteExpression(ScriptExpression expression, IndentedTextWriter output)
 {
     _onNewLine = true;
     GenerateCode(expression, output);
 }
        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);
        }
示例#26
0
 private void WriteExpression(ScriptExpression expression, IndentedTextWriter output)
 {
     _onNewLine      = true;
     localVarCounter = 0;
     GenerateCode(expression, output, true);
 }
示例#27
0
        private void GenerateCode(ScriptExpression expression, IndentedTextWriter output, bool firstrun = false)
        {
            int  firstIndentedArg = int.MaxValue;
            bool isFunctionCall   = false;

            if (expression.Type == ScriptExpressionType.Expression || expression.Type == ScriptExpressionType.Expression4)
            {
                ScriptValueType type = _opcodes.GetTypeInfo((ushort)expression.ReturnType);
                if (type.Name == "function_name")
                {
                    isFunctionCall = true;

                    if (!_nextFunctionIsScript)
                    {
                        FunctionInfo info = _opcodes.GetFunctionInfo(expression.Opcode);
                        if (info != null)
                        {
                            if (info.Name.StartsWith("begin"))
                            {
                                firstIndentedArg = 0;
                                if (expression.LineNumber > 0 && !_onNewLine)
                                {
                                    output.Indent++;
                                    output.WriteLine();
                                }
                            }
                            else if (info.Name == "if")
                            {
                                firstIndentedArg = 1;
                            }
                        }
                    }
                    if (expression.LineNumber > 0)
                    {
                        output.Write("(");
                    }
                }
            }

            bool wroteAnything = HandleExpression(expression, output);
            int  startIndent   = output.Indent;

            int currentArg = 0;

            if (_h4 && firstrun)
            {
                firstIndentedArg = 0;
                currentArg       = 1;
                _h4 = false;
            }

            ScriptExpression sibling = expression.NextExpression;

            while (sibling != null)
            {
                if (wroteAnything && !_nextExpressionIsVar)
                {
                    if (currentArg == firstIndentedArg)
                    {
                        output.Indent++;
                    }
                    if (currentArg >= firstIndentedArg)
                    {
                        output.WriteLine();
                        _onNewLine = true;
                    }
                    else if (output.Indent != startIndent)
                    {
                        output.WriteLine();
                        _onNewLine = true;
                    }
                    else
                    {
                        output.Write(" ");
                    }
                }

                if (!_nextExpressionIsVar)
                {
                    wroteAnything = HandleExpression(sibling, output);
                }
                else if ((_nextExpressionIsVar && sibling.Opcode != 0xFFFF))
                {
                    if (!_varTypeWritten)
                    {
                        ScriptValueType type = _opcodes.GetTypeInfo((ushort)sibling.ReturnType);
                        output.Write(type.Name + " var_" + localVarCounter.ToString() + " ");
                        _varTypeWritten = true;
                    }

                    wroteAnything = HandleExpression(sibling, output);
                }

                sibling = sibling.NextExpression;
                currentArg++;
            }

            if (isFunctionCall && expression.LineNumber > 0)
            {
                if (output.Indent != startIndent)
                {
                    output.Indent = startIndent;
                    if (wroteAnything)
                    {
                        output.WriteLine();
                    }
                    output.Write(")");
                    _onNewLine = true;
                }
                else
                {
                    output.Write(")");
                }
            }
        }
示例#28
0
 /// <summary>
 /// The decompiler generates a script parameter reference based on an expression.
 /// </summary>
 /// <param name="output">The output.</param>
 /// <param name="expression">The parameter reference 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 GenerateParameterReference(IndentedTextWriter output, ScriptExpression expression, bool newLine)
 {
     output.Write(expression.StringValue);
     HandleNewLine(output, newLine);
     return(true);
 }
示例#29
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);
        }
示例#30
0
		private bool GenerateParameterReference(ScriptExpression expression, IndentedTextWriter output)
		{
			_onNewLine = false;
			output.Write(expression.StringValue);
			return true;
		}
示例#31
0
        /// <summary>
        /// The decompiler follows a branch based on a datum index and generates code. Also handles most of the text formatting.
        /// </summary>
        /// <param name="output">The output.</param>
        /// <param name="root">The datumn index to follow.</param>
        /// <param name="newLine">Indicates whether the expressions of the branch start on a new line.</param>
        /// <param name="type">The type of the branch.</param>
        private void FollowRootIndex(IndentedTextWriter output, DatumIndex root, bool newLine, BranchType type)
        {
            ScriptExpression exp = _scripts.Expressions.FindExpression(root);
            int index            = 0;

            // iterate through the branch.
            while (exp != null)
            {
                int  startIndent          = output.Indent;
                bool endOfExpression      = exp.NextExpression is null;
                bool endOfInlineMultiline = false;

                // Remove the last expression in cond calls, which were added by the compiler.
                if (type == BranchType.Cond && endOfExpression && exp.Type == ScriptExpressionType.Expression && exp.LineNumber == 0)
                {
                    return;
                }
                // if: indent the condition if it is a multiline expression.
                else if (type == BranchType.If && index == 1 && IsMultilineExpression(exp))
                {
                    output.WriteLine();
                    output.Indent++;
                }
                // if: indent after the condition.
                else if (type == BranchType.If && index == 2)
                {
                    output.WriteLine();
                    output.Indent++;
                }
                // begin, and, or (multiline): indent after the function name.
                else if (type == BranchType.Multiline && index == 1)
                {
                    output.WriteLine();
                    output.Indent++;
                }
                // cond: indent after the condition.
                else if (type == BranchType.Cond && index == 2)
                {
                    output.WriteLine();
                    output.Indent++;
                }
                // make begin, or and if calls always start on a new line.
                else if (type == BranchType.Call && IsMultilineExpression(exp))
                {
                    output.WriteLine();
                    output.Indent++;
                    endOfInlineMultiline = true;
                }

                // write code.
                HandleExpression(output, exp, newLine);

                // insert space between the parameters of calls and script references.
                if ((type == BranchType.Call || type == BranchType.If) && !endOfExpression && !newLine)
                {
                    output.Write(" ");
                }

                // handle the line break after inline multiline expressions and reset the indent.
                if (endOfInlineMultiline && !endOfExpression)
                {
                    output.WriteLine();
                    output.Indent = startIndent;
                }
                // handle the line break after if statements which end on a multiline expression.
                else if (type == BranchType.If && IsMultilineExpression(exp) && endOfExpression)
                {
                    output.WriteLine();
                }
                // If a regular call ends on a multiline call, insert a line break and reset the indent. Mostly applies to sleep_until in combination with or.
                else if (type == BranchType.Call && IsMultilineExpression(exp) && endOfExpression)
                {
                    output.WriteLine();
                    output.Indent = startIndent;
                }


                index++;
                exp = exp.NextExpression;
            }
        }
示例#32
0
		private bool GenerateScriptReference(ScriptExpression expression, IndentedTextWriter output)
		{
			var expressionIndex = new DatumIndex(expression.Value);

			_nextFunctionIsScript = true;
			GenerateCode(_scripts.Expressions.FindExpression(expressionIndex), output);
			_nextFunctionIsScript = false;
			return true;
		}
示例#33
0
		private bool HandleExpression(ScriptExpression expression, IndentedTextWriter output)
		{
			switch (expression.Type)
			{
				case ScriptExpressionType.Expression:
					return GenerateExpressionCode(expression, output);

				case ScriptExpressionType.GlobalsReference:
					return GenerateGlobalsReference(expression, output);

				case ScriptExpressionType.ParameterReference:
					return GenerateParameterReference(expression, output);

				case ScriptExpressionType.ScriptReference:
					return GenerateScriptReference(expression, output);

				case ScriptExpressionType.Group:
					return GenerateGroup(expression, output);

				default:
					throw new InvalidOperationException("Unknown script expression type");
			}
		}
示例#34
0
		public void WriteExpression(ScriptExpression expression, IndentedTextWriter output)
		{
			_onNewLine = true;
			GenerateCode(expression, output);
		}
示例#35
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
				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;
		}
示例#36
0
 private uint GetValue(ScriptExpression expression, ScriptValueType type)
 {
     return(expression.Value >> (32 - (type.Size * 8)));
 }