Esempio n. 1
0
        DecompileContext CreateDecompileContext(IShowContext ctx)
        {
            var decompileContext     = new DecompileContext();
            var decompilationContext = new DecompilationContext();

            decompilationContext.GetDisableAssemblyLoad = () => decompileFileTabContentFactory.FileManager.DisableAssemblyLoad();
            decompilationContext.IsBodyModified         = m => decompileFileTabContentFactory.MethodAnnotations.IsBodyModified(m);
            var output     = new AvalonEditTextOutput();
            var dispatcher = Dispatcher.CurrentDispatcher;

            decompileContext.DecompileNodeContext = new DecompileNodeContext(decompilationContext, language, output, dispatcher);
            if (ctx.IsRefresh)
            {
                decompileContext.SavedRefPos = ((ITextEditorUIContext)ctx.UIContext).SaveReferencePosition();
                if (decompileContext.SavedRefPos != null)
                {
                    ctx.OnShown = e => {
                        if (e.Success && !e.HasMovedCaret)
                        {
                            e.HasMovedCaret = ((ITextEditorUIContext)ctx.UIContext).RestoreReferencePosition(decompileContext.SavedRefPos);
                            if (!e.HasMovedCaret)
                            {
                                ((ITextEditorUIContext)ctx.UIContext).ScrollAndMoveCaretTo(1, 1);
                                e.HasMovedCaret = true;
                            }
                        }
                    };
                }
            }
            return(decompileContext);
        }
Esempio n. 2
0
 public static void ResolveFunction(DecompileContext ctx, ASTFunction func)
 {
     // Handle code-entry-specific types
     if (ctx.CodeAssetTypes.HasValue)
     {
         if (ctx.CodeAssetTypes.Value.FunctionArgs != null &&
             ctx.CodeAssetTypes.Value.FunctionArgs.TryGetValue(func.Function.Name.Content, out AssetType[] types))
        DecompileContext CreateDecompileContext(IShowContext ctx)
        {
            var decompileContext     = new DecompileContext();
            var decompilationContext = new DecompilationContext();

            decompilationContext.CalculateBinSpans      = true;
            decompilationContext.GetDisableAssemblyLoad = () => decompileDocumentTabContentFactory.DocumentService.DisableAssemblyLoad();
            decompilationContext.IsBodyModified         = m => decompileDocumentTabContentFactory.MethodAnnotations.IsBodyModified(m);
            var dispatcher = Dispatcher.CurrentDispatcher;

            decompileContext.DocumentViewerContentFactory = decompileDocumentTabContentFactory.DocumentViewerContentFactoryProvider.Create();
            decompileContext.DecompileNodeContext         = new DecompileNodeContext(decompilationContext, Decompiler, decompileContext.DocumentViewerContentFactory.Output, dispatcher);
            if (ctx.IsRefresh)
            {
                decompileContext.SavedRefPos = ((IDocumentViewer)ctx.UIContext).SaveReferencePosition();
                if (decompileContext.SavedRefPos != null)
                {
                    ctx.OnShown = e => {
                        if (e.Success && !e.HasMovedCaret)
                        {
                            e.HasMovedCaret = ((IDocumentViewer)ctx.UIContext).RestoreReferencePosition(decompileContext.SavedRefPos);
                            if (!e.HasMovedCaret)
                            {
                                ((IDocumentViewer)ctx.UIContext).MoveCaretToPosition(0);
                                e.HasMovedCaret = true;
                            }
                        }
                    };
                }
            }
            return(decompileContext);
        }
 // Processes "isstaticok" jumps (by removing them), and marks the block
 public static void ProcessStatic(DecompileContext ctx)
 {
     foreach (Block b in ctx.Blocks.List)
     {
         if (b.Instructions.Count >= 2)
         {
             if (b.Instructions[^ 1].Kind == Instruction.Opcode.Bt)
Esempio n. 5
0
        public string Decompile()
        {
            StringBuilder    sb      = new StringBuilder();
            StringWriter     sw      = new StringWriter(sb);
            DecompileContext context = new DecompileContext(sw, this.ShaderIR);

            context.Write();
            return(sb.ToString());
        }
Esempio n. 6
0
        public BlockStatement Process(DecompileContext context, BlockStatement statement)
        {
            foreach (var b in context.Blocks)
            {
                ExpressionPropagation(b);
            }

            return(statement);
        }
Esempio n. 7
0
 public bool Evaluate(DecompileContext ctx, ASTNode node, ASTNode parent)
 {
     foreach (var cond in Conditions)
     {
         if (cond.Evaluate(ctx, node, parent))
         {
             return(true);
         }
     }
     return(false);
 }
Esempio n. 8
0
 public bool Evaluate(DecompileContext ctx, ASTNode node, ASTNode parent)
 {
     if (node.Kind != NodeKind)
     {
         return(true);
     }
     if (node.ToString() != NodeValue)
     {
         return(true);
     }
     return(false);
 }
Esempio n. 9
0
 public bool Evaluate(DecompileContext ctx, ASTNode node, ASTNode parent)
 {
     if (node.Kind == ASTNode.StatementKind.Int16)
     {
         if ((node as ASTInt16).Value == 0)
         {
             return(false);
         }
     }
     // todo? other types like int32/64?
     return(true);
 }
Esempio n. 10
0
        DecompileContext CreateDecompileContext()
        {
            var decompileContext     = new DecompileContext();
            var decompilationContext = new DecompilationContext();

            decompilationContext.GetDisableAssemblyLoad = () => decompileFileTabContentFactory.FileManager.DisableAssemblyLoad();
            decompilationContext.IsBodyModified         = m => decompileFileTabContentFactory.MethodAnnotations.IsBodyModified(m);
            var output     = new AvalonEditTextOutput();
            var dispatcher = Dispatcher.CurrentDispatcher;

            decompileContext.DecompileNodeContext = new DecompileNodeContext(decompilationContext, language, output, dispatcher);
            return(decompileContext);
        }
Esempio n. 11
0
        public void TestDecompileBlock()
        {
            var    path = "..\\..\\Res\\Initialize.tjs.comp";
            Module md   = new Module(path);
            var    mt   = md.TopLevel.ResolveMethod();

            mt.Compact();

            DecompileContext context = new DecompileContext(md.TopLevel);

            context.ScanBlocks(mt.Instructions);
            context.ComputeDominators();
            context.ComputeNaturalLoops();

            context.FillInBlocks(mt.Instructions);

            var pass1 = new RegMemberPass();
            var entry = pass1.Process(context, new BlockStatement());
            var pass2 = new ExpressionPass();

            entry = pass2.Process(context, entry);

            var b  = context.Blocks[1];
            var s1 = b.Statements.FirstOrDefault();

            var pass3 = new ControlFlowPass();

            entry = pass3.Process(context, entry);
            var c = entry.Statements.Count;

            foreach (var st in entry.Statements)
            {
                var s = st;
            }

            var pass4 = new StatementCollectPass();

            entry = pass4.Process(context, entry);

            foreach (var statement in entry.Statements)
            {
                var s = statement;
            }

            var       sWriter = new StringWriter();
            TjsWriter writer  = new TjsWriter(sWriter);

            writer.WriteBlock(entry);
            sWriter.Flush();
            var result = sWriter.ToString();
        }
Esempio n. 12
0
        /// Finds all the if statements within a list of blocks
        public static List <IfStatement> Find(DecompileContext ctx)
        {
            List <IfStatement> res = new List <IfStatement>();

            // Reusable data structures for later
            List <Node>  visited      = new List <Node>();
            Stack <Node> work         = new Stack <Node>();
            List <Node>  otherVisited = new List <Node>();

            foreach (Block b in ctx.Blocks.List)
            {
                if (b.Instructions.Count >= 1)
                {
                    var instr = b.Instructions[^ 1];
Esempio n. 13
0
        DecompileContext CreateDecompileContext(string filename)
        {
            var decompileContext = new DecompileContext();

            try {
                decompileContext.Writer = new StreamWriter(filename);
                decompileContext.Output = new TextWriterDecompilerOutput(decompileContext.Writer);
                return(decompileContext);
            }
            catch {
                decompileContext.Dispose();
                throw;
            }
        }
Esempio n. 14
0
        public BlockStatement Process(DecompileContext context, BlockStatement statement)
        {
            Dictionary <Block, List <IAstNode> > blockStmts = new Dictionary <Block, List <IAstNode> >();

            foreach (var block in context.Blocks)
            {
                var newStmts = new List <IAstNode>();
                var loop     = context.LoopSet.FirstOrDefault(l => l.Header == block);
                if (loop != null)
                {
                    newStmts.Add(loop.LoopLogic.ToStatement());
                    block.Hidden = false; //TODO: temp fix
                }
                else
                {
                    foreach (var node in block.Statements)
                    {
                        switch (node)
                        {
                        case GotoExpression _:
                        case ConditionExpression _:
                            break;

                        case Expression expr:
                            newStmts.Add(new ExpressionStatement(expr));
                            break;

                        case Statement stmt:
                            newStmts.Add(stmt);
                            break;
                        }
                    }
                }

                blockStmts[block] = newStmts;
            }

            foreach (var block in context.Blocks)
            {
                if (block.Hidden)
                {
                    continue;
                }

                statement.Statements.AddRange(blockStmts[block]);
            }

            return(statement);
        }
Esempio n. 15
0
        public BlockStatement Process(DecompileContext context, BlockStatement statement)
        {
            var entry = context.EntryBlock;

            if (context.Object.ContextType == TjsContextType.TopLevel)
            {
                This.HideInstance      = true;
                ThisProxy.HideInstance = true;
            }
            else
            {
                This.HideInstance      = false;
                ThisProxy.HideInstance = false;
            }

            //Add global
            var exps = new Dictionary <int, Expression>
            {
                { Const.ThisReg, This },
                { Const.ThisProxyReg, ThisProxy },
            };
            //Add params
            var argCount = context.Object.FuncDeclArgCount;

            for (short i = 0; i < argCount; i++)
            {
                short slot = (short)(-i - 3);
                var   v    = new Variable(slot)
                {
                    IsParameter = true
                };
                context.Vars.Add(slot, v);
                exps.Add(slot, new LocalExpression(v));
            }

            BlockProcess(context, entry, exps);

            //foreach (var variable in exps.Where(exp => exp.Value.Type == AstNodeType.LocalExpression).Select(exp =>
            //{
            //    var l = (LocalExpression)exp.Value;
            //    return new Variable(exp.Key) {VarType = l.DataType, IsParameter = l.IsParameter, Name = l.ToString()};
            //}))
            //{
            //    context.Vars.Add(variable.Slot, variable);
            //}

            return(statement);
        }
Esempio n. 16
0
        /// Finds all the try statements within a list of blocks, and processes
        public static List <TryStatement> FindAndClean(DecompileContext ctx)
        {
            List <TryStatement> res = new List <TryStatement>();

            foreach (Block b in ctx.Blocks.List)
            {
                if (b.ControlFlow == Block.ControlFlowType.TryHook)
                {
                    int finallyAddress = b.Branches[0].Address;
                    int catchAddress   = b.Branches.Count == 3 ? b.Branches[1].Address : -1;
                    res.Add(new TryStatement(b, finallyAddress, catchAddress));
                }
                else if (b.Instructions.Count >= 3 && b.Instructions[^ 1].Kind == Instruction.Opcode.B &&
                         b.Instructions[^ 2].Kind == Instruction.Opcode.Popz)
                {
                    Instruction call = b.Instructions[^ 3];
Esempio n. 17
0
        DecompileContext CreateDecompileContext(string filename)
        {
            var decompileContext = new DecompileContext();

            try {
                var decompilationContext = new DecompilationContext();
                decompileContext.Writer = new StreamWriter(filename);
                var output     = new PlainTextOutput(decompileContext.Writer);
                var dispatcher = Dispatcher.CurrentDispatcher;
                decompileContext.DecompileNodeContext = new DecompileNodeContext(decompilationContext, language, output, dispatcher);
                return(decompileContext);
            }
            catch {
                decompileContext.Dispose();
                throw;
            }
        }
Esempio n. 18
0
        public void DecompileAllScripts()
        {
            DecompileContext context = new DecompileContext(data, true);

            Parallel.ForEach(data.Code, (code) =>
            {
                //Console.WriteLine(code.Name.Content);
                try
                {
                    Decompiler.Decompile(code, context);
                }
                catch (Exception e)
                {
                    throw new Exception("Failed to decompile script " + code.Name.Content, e);
                }
            });
        }
Esempio n. 19
0
        DecompileContext CreateDecompileContext(string filename)
        {
            var decompileContext = new DecompileContext();

            try {
                var decompilationContext = new DecompilationContext();
                decompileContext.Writer = new StreamWriter(filename);
                var output     = new TextWriterDecompilerOutput(decompileContext.Writer);
                var dispatcher = Dispatcher.CurrentDispatcher;
                decompileContext.DecompileNodeContext = new DecompileNodeContext(decompilationContext, decompiler, output, NullDocumentWriterService.Instance, dispatcher);
                return(decompileContext);
            }
            catch {
                decompileContext.Dispose();
                throw;
            }
        }
        public static void InsertNodes(DecompileContext ctx)
        {
            ctx.PredecessorsToClear = new List <Node>();

            // Process basic branch statements in nested order
            List <Node> toProcess = new List <Node>(ctx.SwitchStatementNodes.Count + ctx.IfStatementNodes.Count +
                                                    ctx.TryStatementNodes.Count);

            toProcess.AddRange(ctx.SwitchStatementNodes);
            toProcess.AddRange(ctx.IfStatementNodes);
            toProcess.AddRange(ctx.TryStatementNodes);
            toProcess = toProcess.OrderBy(s => s.EndAddress).ThenByDescending(s => s.Address).ToList();
            foreach (var node in toProcess)
            {
                switch (node.Kind)
                {
                case Node.NodeType.IfStatement:
                    IfStatements.InsertNode(ctx, node as IfStatement);
                    break;

                case Node.NodeType.SwitchStatement:
                    SwitchStatements.InsertNode(ctx, node as SwitchStatement);
                    break;

                case Node.NodeType.TryStatement:
                    TryStatements.InsertNode(ctx, node as TryStatement);
                    break;
                }
            }

            // Clear predecessors after the fact
            foreach (var node in ctx.PredecessorsToClear)
            {
                foreach (var pred in node.Predecessors)
                {
                    for (int i = pred.Branches.Count - 1; i >= 0; i--)
                    {
                        if (pred.Branches[i] == node)
                        {
                            pred.Branches[i] = new Block(-1, -1); // Don't actually remove: causes problems writing AST
                        }
                    }
                }
            }
        }
Esempio n. 21
0
        public BlockStatement Process(DecompileContext context, BlockStatement statement)
        {
            _context = context;
            _context.LoopSetSort();

            IntervalAnalysisDoWhilePass();

            foreach (var b in _context.Blocks)
            {
                if (b.Hidden)
                {
                    continue;
                }

                if (StructureIfElse(b, out var logic))
                {
                    if (logic.Else.IsBreak)
                    {
                        //can be while!
                        var loop = context.LoopSet.FirstOrDefault(l => l.Header == b);
                        if (loop != null && loop.LoopLogic is DoWhileLogic dw)
                        {
                            dw.IsWhile   = true;
                            dw.Condition = logic.Condition;
                            dw.Body      = logic.Then.Blocks;
                        }
                        else
                        {
                            b.Statements.Replace(logic.Condition, logic.Simplify().ToStatement());
                        }
                    }
                    else
                    {
                        b.Statements.Replace(logic.Condition, logic.Simplify().ToStatement());
                    }
                }
            }

            return(statement);
        }
Esempio n. 22
0
            public bool Evaluate(DecompileContext ctx, ASTNode node, ASTNode parent)
            {
                if (parent.Kind != ASTNode.StatementKind.Function)
                {
                    return(false);
                }
                ASTFunction func = parent as ASTFunction;

                if (Index >= func.Children.Count)
                {
                    return(false);
                }
                ASTNode arg = func.Children[Index];

                if (arg.Kind != NodeKind)
                {
                    return(false);
                }
                if (arg.ToString() != NodeValue)
                {
                    return(false);
                }
                return(true);
            }
Esempio n. 23
0
		DecompileContext CreateDecompileContext(IShowContext ctx) {
			var decompileContext = new DecompileContext();
			var decompilationContext = new DecompilationContext();
			decompilationContext.CalculateILRanges = true;
			decompilationContext.GetDisableAssemblyLoad = () => decompileFileTabContentFactory.FileManager.DisableAssemblyLoad();
			decompilationContext.IsBodyModified = m => decompileFileTabContentFactory.MethodAnnotations.IsBodyModified(m);
			var output = new AvalonEditTextOutput();
			var dispatcher = Dispatcher.CurrentDispatcher;
			decompileContext.DecompileNodeContext = new DecompileNodeContext(decompilationContext, language, output, dispatcher);
			if (ctx.IsRefresh) {
				decompileContext.SavedRefPos = ((ITextEditorUIContext)ctx.UIContext).SaveReferencePosition();
				if (decompileContext.SavedRefPos != null) {
					ctx.OnShown = e => {
						if (e.Success && !e.HasMovedCaret) {
							e.HasMovedCaret = ((ITextEditorUIContext)ctx.UIContext).RestoreReferencePosition(decompileContext.SavedRefPos);
							if (!e.HasMovedCaret) {
								((ITextEditorUIContext)ctx.UIContext).ScrollAndMoveCaretTo(1, 1);
								e.HasMovedCaret = true;
							}
						}
					};
				}
			}
			return decompileContext;
		}
Esempio n. 24
0
		public abstract void Create(DecompileContext ctx);
Esempio n. 25
0
        private async void DecompileCode(UndertaleCode code)
        {
            LoaderDialog dialog = new LoaderDialog("Decompiling", "Decompiling, please wait... This can take a while on complex scripts");

            dialog.Owner = Window.GetWindow(this);

            FlowDocument document = new FlowDocument();

            document.PagePadding = new Thickness(0);
            document.PageWidth   = 2048; // Speed-up.
            document.FontFamily  = new FontFamily("Lucida Console");
            Paragraph par = new Paragraph();

            par.Margin = new Thickness(0);

            UndertaleCode gettextCode = null;

            if (gettext == null)
            {
                gettextCode = (Application.Current.MainWindow as MainWindow).Data.Code.ByName("gml_Script_textdata_en");
            }

            string dataPath        = System.IO.Path.GetDirectoryName((Application.Current.MainWindow as MainWindow).FilePath);
            string gettextJsonPath = (dataPath != null) ? System.IO.Path.Combine(dataPath, "lang/lang_en.json") : null;

            var  dataa = (Application.Current.MainWindow as MainWindow).Data;
            Task t     = Task.Run(() =>
            {
                int estimatedLineCount = (int)Math.Round(code.Length * .056D);
                bool skipFormatting    = (estimatedLineCount > 5000);

                DecompileContext context = new DecompileContext(dataa, !skipFormatting);
                string decompiled        = null;
                Exception e = null;
                try
                {
                    decompiled = Decompiler.Decompile(code, context).Replace("\r\n", "\n");
                }
                catch (Exception ex)
                {
                    e = ex;
                }

                if (gettextCode != null)
                {
                    UpdateGettext(gettextCode);
                }

                if (gettextJSON == null && gettextJsonPath != null && File.Exists(gettextJsonPath))
                {
                    string err = UpdateGettextJSON(File.ReadAllText(gettextJsonPath));
                    if (err != null)
                    {
                        e = new Exception(err);
                    }
                }

                Dispatcher.Invoke(() =>
                {
                    if (e != null)
                    {
                        Brush exceptionBrush = new SolidColorBrush(Color.FromRgb(255, 0, 0));
                        par.Inlines.Add(new Run("EXCEPTION!\n")
                        {
                            Foreground = exceptionBrush, FontWeight = FontWeights.Bold
                        });
                        par.Inlines.Add(new Run(e.ToString())
                        {
                            Foreground = exceptionBrush
                        });
                    }
                    else if (decompiled != null)
                    {
                        string[] lines = decompiled.Split('\n');
                        if (skipFormatting)
                        {
                            for (var i = 0; i < lines.Length; i++)
                            {
                                string toWrite = lines[i];
                                if (((i + 1) % 100) != 0 && lines.Length > i + 1)
                                {
                                    toWrite += "\n"; // Write a new-line if we're not making a new paragraph.
                                }
                                if (i > 0 && i % 100 == 0)
                                { // Splitting into different paragraphs significantly increases selection performance.
                                    document.Blocks.Add(par);
                                    par        = new Paragraph();
                                    par.Margin = new Thickness(0);
                                }

                                par.Inlines.Add(toWrite);
                            }
                        }
                        else
                        {
                            Brush keywordBrush  = new SolidColorBrush(Color.FromRgb(0, 0, 150));
                            Brush constBrush    = new SolidColorBrush(Color.FromRgb(0, 100, 150));
                            Brush stringBrush   = new SolidColorBrush(Color.FromRgb(0, 0, 200));
                            Brush commentBrush  = new SolidColorBrush(Color.FromRgb(0, 150, 0));
                            Brush funcBrush     = new SolidColorBrush(Color.FromRgb(100, 100, 0));
                            Brush assetBrush    = new SolidColorBrush(Color.FromRgb(0, 150, 100));
                            Brush argumentBrush = new SolidColorBrush(Color.FromRgb(80, 131, 80));

                            Dictionary <string, UndertaleFunction> funcs = new Dictionary <string, UndertaleFunction>();
                            foreach (var x in (Application.Current.MainWindow as MainWindow).Data.Functions)
                            {
                                funcs.Add(x.Name.Content, x);
                            }

                            string storedStrTok = "";

                            foreach (var line in lines)
                            {
                                char[] special = { '.', ',', ')', '(', '[', ']', '>', '<', ':', ';', '=', '"', '!' };
                                Func <char, bool> IsSpecial = (c) => Char.IsWhiteSpace(c) || special.Contains(c);
                                List <string> split         = new List <string>();
                                string tok         = storedStrTok;
                                storedStrTok       = "";
                                bool readingString = (tok != "");
                                bool escaped       = false;
                                for (int i = 0; i < line.Length; i++)
                                {
                                    if (tok == "//")
                                    {
                                        tok += line.Substring(i);
                                        break;
                                    }
                                    if (!readingString && tok.Length > 0 && (
                                            (Char.IsWhiteSpace(line[i]) != Char.IsWhiteSpace(tok[tok.Length - 1])) ||
                                            (special.Contains(line[i]) != special.Contains(tok[tok.Length - 1])) ||
                                            (special.Contains(line[i]) && special.Contains(tok[tok.Length - 1])) ||
                                            line[i] == '"'
                                            ))
                                    {
                                        split.Add(tok);
                                        tok = "";
                                    }

                                    if (readingString && context.isGameMaker2)
                                    {
                                        if (escaped)
                                        {
                                            escaped = false;
                                            if (line[i] == '"')
                                            {
                                                tok += line[i];
                                                continue;
                                            }
                                        }
                                        else if (line[i] == '\\')
                                        {
                                            escaped = true;
                                        }
                                    }

                                    tok += line[i];
                                    if (line[i] == '"')
                                    {
                                        if (readingString)
                                        {
                                            split.Add(tok);
                                            tok = "";
                                        }
                                        readingString = !readingString;
                                    }
                                }
                                if (tok != "")
                                {
                                    if (readingString)
                                    {
                                        storedStrTok = tok + "\n";
                                    }
                                    else
                                    {
                                        split.Add(tok);
                                    }
                                }

                                Dictionary <string, object> usedObjects = new Dictionary <string, object>();
                                for (int i = 0; i < split.Count; i++)
                                {
                                    int?val      = null;
                                    string token = split[i];
                                    if (token == "if" || token == "else" || token == "return" || token == "break" || token == "continue" || token == "while" || token == "for" || token == "repeat" || token == "with" || token == "switch" || token == "case" || token == "default" || token == "exit" || token == "var" || token == "do" || token == "until")
                                    {
                                        par.Inlines.Add(new Run(token)
                                        {
                                            Foreground = keywordBrush, FontWeight = FontWeights.Bold
                                        });
                                    }
                                    else if (token == "self" || token == "global" || token == "local" || token == "other" || token == "noone" || token == "true" || token == "false" || token == "undefined" || token == "all")
                                    {
                                        par.Inlines.Add(new Run(token)
                                        {
                                            Foreground = keywordBrush
                                        });
                                    }
                                    else if (token.StartsWith("argument"))
                                    {
                                        par.Inlines.Add(new Run(token)
                                        {
                                            Foreground = argumentBrush
                                        });
                                    }
                                    else if ((val = AssetTypeResolver.FindConstValue(token)) != null)
                                    {
                                        par.Inlines.Add(new Run(token)
                                        {
                                            Foreground = constBrush, FontStyle = FontStyles.Italic, ToolTip = val.ToString()
                                        });
                                    }
                                    else if (token.StartsWith("\""))
                                    {
                                        par.Inlines.Add(new Run(token)
                                        {
                                            Foreground = stringBrush
                                        });
                                    }
                                    else if (token.StartsWith("//"))
                                    {
                                        par.Inlines.Add(new Run(token)
                                        {
                                            Foreground = commentBrush
                                        });
                                    }
                                    else if (token.StartsWith("@") && split[i - 1][0] == '"' && split[i - 1][split[i - 1].Length - 1] == '"')
                                    {
                                        par.Inlines.LastInline.Cursor     = Cursors.Hand;
                                        par.Inlines.LastInline.MouseDown += (sender, ev) =>
                                        {
                                            MainWindow mw = Application.Current.MainWindow as MainWindow;
                                            mw.ChangeSelection(mw.Data.Strings[Int32.Parse(token.Substring(1))]);
                                        };
                                    }
                                    else if (dataa.ByName(token) != null)
                                    {
                                        par.Inlines.Add(new Run(token)
                                        {
                                            Foreground = assetBrush, Cursor = Cursors.Hand
                                        });
                                        par.Inlines.LastInline.MouseDown += (sender, ev) => (Application.Current.MainWindow as MainWindow).ChangeSelection(dataa.ByName(token));
                                        if (token == "scr_gettext" && gettext != null)
                                        {
                                            if (split[i + 1] == "(" && split[i + 2].StartsWith("\"") && split[i + 3].StartsWith("@") && split[i + 4] == ")")
                                            {
                                                string id = split[i + 2].Substring(1, split[i + 2].Length - 2);
                                                if (!usedObjects.ContainsKey(id) && gettext.ContainsKey(id))
                                                {
                                                    usedObjects.Add(id, (Application.Current.MainWindow as MainWindow).Data.Strings[gettext[id]]);
                                                }
                                            }
                                        }
                                        if (token == "scr_84_get_lang_string" && gettextJSON != null)
                                        {
                                            if (split[i + 1] == "(" && split[i + 2].StartsWith("\"") && split[i + 3].StartsWith("@") && split[i + 4] == ")")
                                            {
                                                string id = split[i + 2].Substring(1, split[i + 2].Length - 2);
                                                if (!usedObjects.ContainsKey(id) && gettextJSON.ContainsKey(id))
                                                {
                                                    usedObjects.Add(id, gettextJSON[id]);
                                                }
                                            }
                                        }
                                    }
                                    else if (funcs.ContainsKey(token))
                                    {
                                        par.Inlines.Add(new Run(token)
                                        {
                                            Foreground = funcBrush, Cursor = Cursors.Hand
                                        });
                                        par.Inlines.LastInline.MouseDown += (sender, ev) => (Application.Current.MainWindow as MainWindow).ChangeSelection(funcs[token]);
                                    }
                                    else if (char.IsDigit(token[0]))
                                    {
                                        par.Inlines.Add(new Run(token)
                                        {
                                            Cursor = Cursors.Hand
                                        });
                                        par.Inlines.LastInline.MouseDown += (sender, ev) =>
                                        {
                                            if (token.Length > 2 && token[0] == '0' && token[1] == 'x')
                                            {
                                                ev.Handled = true;
                                                return; // Hex numbers aren't objects.
                                            }

                                            UndertaleData data = (Application.Current.MainWindow as MainWindow).Data;
                                            int id;
                                            if (int.TryParse(token, out id))
                                            {
                                                List <UndertaleObject> possibleObjects = new List <UndertaleObject>();
                                                if (id < data.Sprites.Count)
                                                {
                                                    possibleObjects.Add(data.Sprites[id]);
                                                }
                                                if (id < data.Rooms.Count)
                                                {
                                                    possibleObjects.Add(data.Rooms[id]);
                                                }
                                                if (id < data.GameObjects.Count)
                                                {
                                                    possibleObjects.Add(data.GameObjects[id]);
                                                }
                                                if (id < data.Backgrounds.Count)
                                                {
                                                    possibleObjects.Add(data.Backgrounds[id]);
                                                }
                                                if (id < data.Scripts.Count)
                                                {
                                                    possibleObjects.Add(data.Scripts[id]);
                                                }
                                                if (id < data.Paths.Count)
                                                {
                                                    possibleObjects.Add(data.Paths[id]);
                                                }
                                                if (id < data.Fonts.Count)
                                                {
                                                    possibleObjects.Add(data.Fonts[id]);
                                                }
                                                if (id < data.Sounds.Count)
                                                {
                                                    possibleObjects.Add(data.Sounds[id]);
                                                }
                                                if (id < data.Shaders.Count)
                                                {
                                                    possibleObjects.Add(data.Shaders[id]);
                                                }
                                                if (id < data.Timelines.Count)
                                                {
                                                    possibleObjects.Add(data.Timelines[id]);
                                                }

                                                ContextMenu contextMenu = new ContextMenu();
                                                foreach (UndertaleObject obj in possibleObjects)
                                                {
                                                    MenuItem item = new MenuItem();
                                                    item.Header   = obj.ToString().Replace("_", "__");
                                                    item.Click   += (sender2, ev2) => (Application.Current.MainWindow as MainWindow).ChangeSelection(obj);
                                                    contextMenu.Items.Add(item);
                                                }
                                                if (id > 0x00050000)
                                                {
                                                    contextMenu.Items.Add(new MenuItem()
                                                    {
                                                        Header = "#" + id.ToString("X6") + " (color)", IsEnabled = false
                                                    });
                                                }
                                                contextMenu.Items.Add(new MenuItem()
                                                {
                                                    Header = id + " (number)", IsEnabled = false
                                                });
                                                (sender as Run).ContextMenu = contextMenu;
                                                contextMenu.IsOpen          = true;
                                            }
                                            ev.Handled = true;
                                        };
                                    }
                                    else
                                    {
                                        par.Inlines.Add(token);
                                    }

                                    if (token == "." && (Char.IsLetter(split[i + 1][0]) || split[i + 1][0] == '_'))
                                    {
                                        int id;
                                        if (Int32.TryParse(split[i - 1], out id))
                                        {
                                            var gos = (Application.Current.MainWindow as MainWindow).Data.GameObjects;
                                            if (!usedObjects.ContainsKey(split[i - 1]) && id >= 0 && id < gos.Count)
                                            {
                                                usedObjects.Add(split[i - 1], gos[id]);
                                            }
                                        }
                                    }
                                }

                                // Add used object comments.
                                foreach (var gt in usedObjects)
                                {
                                    par.Inlines.Add(new Run(" // " + gt.Key + " = ")
                                    {
                                        Foreground = commentBrush
                                    });
                                    par.Inlines.Add(new Run(gt.Value is string? "\"" + (string)gt.Value + "\"" : gt.Value.ToString())
                                    {
                                        Foreground = commentBrush, Cursor = Cursors.Hand
                                    });
                                    if (gt.Value is UndertaleObject)
                                    {
                                        par.Inlines.LastInline.MouseDown += (sender, ev) => (Application.Current.MainWindow as MainWindow).ChangeSelection(gt.Value);
                                    }
                                }

                                if (par.Inlines.Count >= 250)
                                { // Splitting into different paragraphs significantly increases selection performance.
                                    document.Blocks.Add(par);
                                    par        = new Paragraph();
                                    par.Margin = new Thickness(0);
                                }
                                else if (!readingString)
                                {
                                    par.Inlines.Add(new Run("\n"));
                                }
                            }
                        }
                    }

                    document.Blocks.Add(par);
                    DecompiledView.Document = document;
                    CurrentDecompiled       = code;
                    dialog.Hide();
                });
            });

            dialog.ShowDialog();
            await t;
        }
Esempio n. 26
0
        /// Inserts short-circuit nodes into the graph, and compile list of conditions
        public static void InsertNodes(DecompileContext ctx)
        {
            foreach (var s in ctx.ShortCircuitNodes)
            {
                Node header = ctx.Blocks.AddressToBlock[s.Address];
                (header as Block).BelongingTo = s;
                if ((header as Block).Instructions.Count == 1 ||
                    header.Predecessors[0].Kind == Node.NodeType.ShortCircuit)
                {
                    // The header is actually another short circuit, need to adjust up
                    header    = header.Predecessors[0];
                    s.Address = header.Address;
                }

                // Find all the conditions
                Node curr = header;
                Node prev = header;
                bool skip = false;
                while (curr != s.Tail)
                {
                    if (curr.Kind == Node.NodeType.Block)
                    {
                        Block b = curr as Block;
                        if (b.LastInstr.Kind == Instruction.Opcode.B)
                        {
                            // This is the last condition
                            if (!skip)
                            {
                                if (b.Instructions.Count != 1)
                                {
                                    s.Conditions.Add(b);    // This has the full condition in the block
                                }
                                else
                                {
                                    s.Conditions.Add(prev); // Another short-circuit node
                                }
                            }
                            if (b.Instructions.LastOrDefault()?.Kind == Instruction.Opcode.B) // It might not be inside a loop!
                            {
                                b.Instructions.RemoveAt(b.Instructions.Count - 1);
                            }
                            b.ControlFlow = Block.ControlFlowType.None;
                            break;
                        }
                        else // (assuming either Bf or Bt)
                        {
                            // This is a new condition
                            if (!skip)
                            {
                                if (b.Instructions.Count != 1)
                                {
                                    s.Conditions.Add(b);    // This has the full condition in the block
                                }
                                else
                                {
                                    s.Conditions.Add(prev); // Another short-circuit node
                                }
                            }
                            else
                            {
                                skip = false;
                            }
                            b.Instructions.RemoveAt(b.Instructions.Count - 1);

                            // Continue onwards
                            prev = curr;
                            curr = curr.Branches[1];
                        }
                    }
                    else
                    {
                        // Continue onwards
                        prev = curr;
                        s.Conditions.Add(curr);
                        curr = curr.Branches[0];
                        skip = true;
                    }
                }

                // Change header predecessors to point to this node instead
                foreach (var node in header.Predecessors)
                {
                    for (int i = 0; i < node.Branches.Count; i++)
                    {
                        if (node.Branches[i] != node && node.Branches[i] == header)
                        {
                            node.Branches[i] = s;
                            break;
                        }
                    }
                }

                // Change tail branches to come from this node instead
                foreach (var node in s.Tail.Branches)
                {
                    node.Predecessors.Clear();
                    node.Predecessors.Add(s);
                }

                // Remove necessary branches from conditions
                foreach (var cond in s.Conditions)
                {
                    for (int i = cond.Branches.Count - 1; i >= 0; i--)
                    {
                        if (cond.Kind == Node.NodeType.ShortCircuit && cond.Branches[i].Address >= s.EndAddress)
                        {
                            cond.Branches.RemoveAt(i);
                        }
                        else if (cond.Branches[i].Address >= s.Tail.Address || s.Conditions.Contains(cond.Branches[i]))
                        {
                            cond.Branches.RemoveAt(i);
                        }
                        else
                        {
                            // Need to cut off the branch eventually
                            Stack <Node> work = new Stack <Node>();
                            work.Push(cond.Branches[i]);
                            while (work.Count != 0)
                            {
                                Node currBranch = work.Pop();
                                for (int j = currBranch.Branches.Count - 1; j >= 0; j--)
                                {
                                    if (currBranch.Branches[j].Address >= cond.EndAddress)
                                    {
                                        currBranch.Branches.RemoveAt(j);
                                    }
                                    else if (currBranch.Branches[j].Address > s.Address && currBranch.Branches[j] != s.Tail)
                                    {
                                        work.Push(currBranch.Branches[j]);
                                    }
                                }
                            }
                        }
                    }
                }

                // Transfer predecessors and branches
                s.Predecessors = header.Predecessors;
                s.Branches.AddRange(s.Tail.Branches);
                s.Tail.Branches.Clear();
            }
        }
Esempio n. 27
0
        public static ASTNode ResolveAny(DecompileContext ctx, ASTNode node, ASTNode parent, ConditionalAssetType type)
        {
            // Check if this type has a condition that needs to be satisfied
            if (type.Condition != null)
            {
                if (type.Condition.Evaluate(ctx, node, parent))
                {
                    if (type.Condition.EvaluateOnce)
                    {
                        type = new(type); // Make a new type without the condition (it has been satisfied)
                    }
                }
                else
                {
                    // Check if there's any valid alternative type
                    if (type.Alternatives != null)
                    {
                        bool evaluated = false;
                        for (int i = 0; i < type.Alternatives.Length; i++)
                        {
                            var curr = type.Alternatives[i];
                            if (curr.Condition == null || curr.Condition.Evaluate(ctx, node, parent))
                            {
                                evaluated = true;
                                if (curr.Condition != null && curr.Condition.EvaluateOnce)
                                {
                                    type = new(curr); // Make a new type without the condition (it has been satisfied)
                                }
                                else
                                {
                                    type = curr;
                                }
                                break;
                            }
                        }

                        if (!evaluated)
                        {
                            return(node);
                        }
                    }
                    else
                    {
                        return(node);
                    }
                }
            }

            switch (node.Kind)
            {
            case ASTNode.StatementKind.Int16:
            case ASTNode.StatementKind.Int32:
                return(ResolveInt(ctx, node, type));

            case ASTNode.StatementKind.IfStatement:
                if (node.Children.Count == 5)
                {
                    node.Children[3] = ResolveAny(ctx, node.Children[3], node, type);
                    node.Children[4] = ResolveAny(ctx, node.Children[4], node, type);
                }
                break;

            case ASTNode.StatementKind.Binary:
                node.Children[0] = ResolveAny(ctx, node.Children[0], node, type);
                node.Children[1] = ResolveAny(ctx, node.Children[1], node, type);
                break;

            case ASTNode.StatementKind.Function:
                if ((node as ASTFunction).Function.Name.Content == "@@NewGMLArray@@")
                {
                    for (int i = 0; i < node.Children.Count; i++)
                    {
                        node.Children[i] = ResolveAny(ctx, node.Children[i], node, type);
                    }
                }
                break;
            }

            return(node);
        }
Esempio n. 28
0
 public abstract void Create(DecompileContext ctx);
Esempio n. 29
0
        /// Inserts loop nodes into the graph, and resolves break/continue
        public static void InsertNodes(DecompileContext ctx)
        {
            foreach (var loop in ctx.LoopNodes)
            {
                // Change header predecessors to point to the loop instead
                foreach (var node in loop.Header.Predecessors)
                {
                    for (int i = 0; i < node.Branches.Count; i++)
                    {
                        if (node.Branches[i] != node && node.Branches[i] == loop.Header)
                        {
                            if (loop.LoopKind == Loop.LoopType.With || loop.LoopKind == Loop.LoopType.Repeat)
                            {
                                if (node.Kind != Node.NodeType.Loop ||
                                    (node.Branches[i].Kind == Node.NodeType.Loop &&
                                     node.Branches[i].Address != loop.Address)) // Special case when a with or repeat statement starts with a loop
                                {
                                    node.Branches[i] = loop;
                                    break;
                                }
                            }
                            else
                            {
                                node.Branches[i] = loop;
                                break;
                            }
                        }
                    }
                }

                // Initialize predecessors/branches if they're outside of the loop bounds
                foreach (var pred in loop.Header.Predecessors)
                {
                    if ((pred.Address < loop.Address && pred.EndAddress <= loop.Address) || pred.Address >= loop.EndAddress)
                    {
                        loop.Predecessors.Add(pred);
                        if (!pred.Branches.Contains(loop)) // Fix for certain empty with statements followed by another loop
                        {
                            pred.Branches.Insert(0, loop);
                        }
                    }
                }
                if (loop.LoopKind != Loop.LoopType.Repeat) // Hacky(?) fix to prevent too many loop branches
                {
                    foreach (var branch in loop.Header.Branches)
                    {
                        if ((branch.Address < loop.Address && branch.EndAddress <= loop.Address) || branch.Address >= loop.EndAddress)
                        {
                            loop.Branches.Add(branch);
                        }
                    }
                }
                if (loop.LoopKind == Loop.LoopType.With)
                {
                    // Need to make a new block at the end of the with statement so other control flow detection doesn't explode
                    Block withEndBlock = new Block(loop.Tail.Address, loop.Tail.Address);
                    foreach (var pred in loop.Tail.Predecessors)
                    {
                        for (int i = pred.Branches.Count - 1; i >= 0; i--)
                        {
                            if (pred.Branches[i] == loop.Tail)
                            {
                                pred.Branches[i] = withEndBlock;
                                withEndBlock.Predecessors.Add(pred);
                            }
                        }
                    }
                    loop.Tail.Predecessors.Clear();
                    loop.Branches.Add(loop.Tail);
                    loop.Tail.Predecessors.Add(loop);
                }
                else
                {
                    foreach (var branch in loop.Tail.Branches)
                    {
                        if ((branch.Address < loop.Address && branch.EndAddress <= loop.Address) || branch.Address >= loop.EndAddress)
                        {
                            if (!loop.Branches.Contains(branch))
                            {
                                loop.Branches.Add(branch);
                            }
                        }
                    }
                }

                // Change any nodes jumped outbound to be marked as jumped from this loop
                Stack <Node> work    = new Stack <Node>();
                List <Node>  visited = new List <Node>();
                work.Push(loop.Header);
                visited.Add(loop.Header);
                while (work.Count != 0)
                {
                    Node curr = work.Pop();
                    for (int i = 0; i < curr.Branches.Count; i++)
                    {
                        var branch = curr.Branches[i];
                        if ((branch.Address < loop.Address && branch.EndAddress <= loop.Address) || branch.Address >= loop.EndAddress)
                        {
                            // This node branches outside of the loop.
                            if (curr.Kind == Node.NodeType.Block && (curr as Block).LastInstr?.Kind == Instruction.Opcode.B &&
                                branch.Address >= loop.EndAddress && curr.EndAddress < loop.EndAddress)
                            {
                                // This is actually a break statement

                                // Remove `b` instruction, mark the block as a "break" block
                                Block currBlock = (curr as Block);
                                currBlock.Instructions.RemoveAt(currBlock.Instructions.Count - 1);
                                currBlock.ControlFlow = Block.ControlFlowType.Break;
                            }
                            else
                            {
                                // Make the branch come from the loop instead
                                if (loop.LoopKind != Loop.LoopType.With && !loop.Branches.Contains(branch))
                                {
                                    loop.Branches.Add(branch);
                                }

                                var preds = branch.Predecessors;
                                for (int j = 0; j < preds.Count; j++)
                                {
                                    if (preds[j] == curr)
                                    {
                                        preds[j] = loop;
                                        break;
                                    }
                                }
                            }
                        }
                        else if (branch == loop || branch == loop.Tail)
                        {
                            if (curr != loop.Tail &&
                                curr.Kind == Node.NodeType.Block && (curr as Block).LastInstr?.Kind == Instruction.Opcode.B)
                            {
                                if (branch == loop.Tail && branch is Block b &&
                                    b.Instructions.FirstOrDefault()?.Kind == Instruction.Opcode.Popz)
                                {
                                    // This is actually a break statement inside of a switch, inside of a loop
                                    // Don't do anything to this here, because it should be processed later? (TODO?)
                                }
                                else
                                {
                                    // This is a continue statement

                                    // Remove `b` instruction, mark the block as a "continue" block
                                    Block currBlock = (curr as Block);
                                    currBlock.Instructions.RemoveAt(currBlock.Instructions.Count - 1);
                                    currBlock.ControlFlow = Block.ControlFlowType.Continue;
                                }
                            }

                            // (otherwise just ignore the jump)
                        }

                        if (branch.Address >= loop.Address && branch.EndAddress <= loop.EndAddress && !visited.Contains(branch))
                        {
                            work.Push(branch);
                            visited.Add(branch);
                        }
                    }
                }

                // Remove unnecessary predecessors from the header (inside the loop)
                for (int i = loop.Header.Predecessors.Count - 1; i >= 0; i--)
                {
                    var pred = loop.Header.Predecessors[i];
                    if (pred.Address >= loop.Address || pred.EndAddress > loop.Address)
                    {
                        loop.Header.Predecessors.RemoveAt(i);
                    }
                }
                loop.Header.Predecessors.Add(loop);

                // Set it up so that the last branch signifies REAL header/body (not just the block)
                loop.Branches.Add(loop.Header);

                // Remove unnecessary instructions and deal with references for the loop
                switch (loop.LoopKind)
                {
                case Loop.LoopType.While:
                    // Remove `b`
                    loop.Tail.Instructions.RemoveAt(loop.Tail.Instructions.Count - 1);

                    // Find the end of the condition:
                    //  - Branches out from loop.Header (or is loop.Header)
                    //  - Ends in a `bf` instruction
                    //  - First branch goes out of loop
                    Block conditionBlock = null;
                    work.Push(loop.Header);
                    while (work.Count != 0)
                    {
                        Node curr = work.Pop();
                        if (curr.Kind == Node.NodeType.Block && (curr as Block).LastInstr?.Kind == Instruction.Opcode.Bf)
                        {
                            if (curr.Branches[0].Address >= loop.EndAddress)
                            {
                                // We found the condition!
                                conditionBlock = curr as Block;
                                break;
                            }
                        }

                        foreach (var branch in curr.Branches)
                        {
                            work.Push(branch);
                        }
                    }
                    conditionBlock.Branches.RemoveAt(0);
                    conditionBlock.Instructions.RemoveAt(conditionBlock.Instructions.Count - 1);     // Remove `bf`
                    conditionBlock.ControlFlow = Block.ControlFlowType.LoopCondition;
                    break;

                case Loop.LoopType.Repeat:
                {
                    // Remove initial condition in block before loop, and its branch
                    Block prev = loop.Predecessors[0] as Block;
                    prev.Branches.RemoveAt(0);
                    prev.Instructions.RemoveRange(prev.Instructions.Count - 4, 4);
                    prev.ControlFlow = Block.ControlFlowType.RepeatExpression;         // Mark this for later reference

                    // Handle edge cases similar to "with"
                    for (int i = prev.Branches.Count - 1; i >= 0; i--)
                    {
                        if (prev.Branches[i] != loop)
                        {
                            if (prev.Branches[i].Kind == Node.NodeType.Loop &&
                                prev.Branches[i].Address == loop.Address)
                            {
                                // Edge case when a loop begins with another loop
                                Node innerLoop = prev.Branches[i];
                                prev.Branches[i] = loop;
                                foreach (var pred2 in innerLoop.Predecessors)
                                {
                                    for (int j = pred2.Branches.Count - 1; j >= 0; j--)
                                    {
                                        if (pred2.Branches[j] == innerLoop)
                                        {
                                            pred2.Branches[j] = loop;
                                        }
                                    }
                                }
                                innerLoop.Predecessors.Clear();
                                innerLoop.Predecessors.Add(loop);
                                loop.Branches[1]            = innerLoop;
                                loop.Header.Predecessors[1] = innerLoop;
                            }
                        }
                    }

                    // Remove unnecessary branches from block previous to this loop
                    for (int i = prev.Branches.Count - 1; i >= 0; i--)
                    {
                        if (prev.Branches[i] != loop)
                        {
                            prev.Branches.RemoveAt(i);
                        }
                    }

                    // Remove decrement and branch
                    loop.Tail.Instructions.RemoveRange(loop.Tail.Instructions.Count - 5, 5);

                    // Remove popz in branch
                    (loop.Branches[0] as Block).Instructions.RemoveAt(0);
                }
                break;

                case Loop.LoopType.DoUntil:
                    // Remove `bf`
                    loop.Tail.Instructions.RemoveAt(loop.Tail.Instructions.Count - 1);
                    loop.Tail.ControlFlow = Block.ControlFlowType.LoopCondition;
                    break;

                case Loop.LoopType.With:
                {
                    // Mark block before loop as a with expression (pushenv and popenv don't need to be removed; they're unique)
                    Node prev = loop.Predecessors[0];
                    if (prev.Kind == Node.NodeType.Block)
                    {
                        (prev as Block).ControlFlow = Block.ControlFlowType.WithExpression;         // Mark this for later reference
                    }
                    // Remove unnecessary branches from the block before
                    for (int i = prev.Branches.Count - 1; i >= 0; i--)
                    {
                        if (prev.Branches[i] != loop)
                        {
                            if (prev.Branches[i].Kind == Node.NodeType.Loop &&
                                prev.Branches[i].Address == loop.Address)
                            {
                                // Edge case when a loop begins a with statement
                                Node innerLoop = prev.Branches[i];
                                prev.Branches[i] = loop;
                                foreach (var pred2 in innerLoop.Predecessors)
                                {
                                    for (int j = pred2.Branches.Count - 1; j >= 0; j--)
                                    {
                                        if (pred2.Branches[j] == innerLoop)
                                        {
                                            pred2.Branches[j] = loop;
                                        }
                                    }
                                }
                                innerLoop.Predecessors.Clear();
                                innerLoop.Predecessors.Add(loop);
                                loop.Branches[1]            = innerLoop;
                                loop.Header.Predecessors[1] = innerLoop;
                            }
                            else
                            {
                                prev.Branches[i].Predecessors.Remove(prev.Branches[i]);
                                prev.Branches.RemoveAt(i);
                            }
                        }
                    }

                    // Check for a "break"/popenv drop block at the end, and remove the `b` instruction
                    if (loop.Tail.Instructions.Count == 2 &&
                        loop.Tail.Instructions[1].Kind == Instruction.Opcode.B &&
                        loop.Tail.Index + 1 < ctx.Blocks.List.Count)
                    {
                        Block nextBlock = ctx.Blocks.List[loop.Tail.Index + 1];
                        if (loop.Tail.Branches[0].Address == nextBlock.EndAddress &&
                            nextBlock.Instructions.Count == 1 &&
                            nextBlock.Instructions[0].Kind == Instruction.Opcode.PopEnv &&
                            nextBlock.Instructions[0].PopenvExitMagic)
                        {
                            loop.Tail.Instructions.RemoveAt(1);
                        }
                    }
                }
                break;
                }
            }
Esempio n. 30
0
        public void BlockProcess(DecompileContext context, Block block,
                                 Dictionary <int, Expression> exps)
        {
            if (block.Statements != null)
            {
                return;
            }

            if (block.From.Count > 1)
            {
                //get from.Output && from.Def
                var commonInput = block.From.Select(b => b.Output).Union(block.From.Select(b => b.Def)).GetIntersection();
                commonInput.IntersectWith(block.Input);
                //flag can be phi
                if (commonInput.Count > 0)
                {
                    foreach (var inSlot in commonInput)
                    {
                        //Generate Phi
                        var phi = new PhiExpression(inSlot);
                        //From must be sorted since we need first condition
                        if (block.From[0].Statements?.Last() is ConditionExpression condition)
                        {
                            phi.Condition = condition;
                            //var thenBlock = context.BlockTable[condition.JumpTo];
                            var elseBlock = context.BlockTable[condition.ElseTo];
                            //phi.ThenBranch = context.BlockFinalStates[trueBlock][inSlot];
                            phi.ThenBranch =
                                context.BlockFinalStates[block.From[0]]
                                [inSlot];     //if jump, use the state from the jump-from block
                            phi.ElseBranch = context.BlockFinalStates[elseBlock][inSlot];
                            //Next: Merge condition: if (v1) then v1 else v2 => v1 || v2 (infer v1 is bool)
                            if (phi.ThenBranch != phi.ElseBranch)
                            {
                                exps[inSlot] = phi;
                            }
                        }
                    }
                }
            }

            Expression retExp  = null;
            var        ex      = new Dictionary <int, Expression>(exps);
            var        flag    = ex.ContainsKey(Const.FlagReg) ? ex[Const.FlagReg] : null;
            var        expList = new List <IAstNode>();

            block.Statements = expList;
            InstructionData insData = null;

            for (var i = 0; i < block.Instructions.Count; i++)
            {
                ex[0] = Void;
                var ins = block.Instructions[i];
                insData = block.InstructionDatas[i];

                switch (ins.OpCode)
                {
                case OpCode.NOP:
                    break;

                case OpCode.CONST:
                {
                    var data     = (OperandData)ins.Data;
                    var constExp = new ConstantExpression(data.Variant);
                    ex[ins.GetRegisterSlot(0)] = constExp;
                }
                break;

                case OpCode.CL:
                {
                    ex[ins.GetRegisterSlot(0)] = null;
                }
                break;

                case OpCode.CCL:
                    break;

                case OpCode.CEQ:
                case OpCode.CDEQ:
                case OpCode.CLT:
                case OpCode.CGT:
                {
                    var      left  = ex[ins.GetRegisterSlot(0)];
                    var      right = ex[ins.GetRegisterSlot(1)];
                    BinaryOp op    = BinaryOp.Unknown;
                    switch (ins.OpCode)
                    {
                    case OpCode.CEQ:
                        op = BinaryOp.Equal;
                        break;

                    case OpCode.CDEQ:
                        op = BinaryOp.Congruent;
                        break;

                    case OpCode.CLT:
                        op = BinaryOp.LessThan;
                        break;

                    case OpCode.CGT:
                        op = BinaryOp.GreaterThan;
                        break;
                    }

                    var b = new BinaryExpression(left, right, op);
                    flag = b;
                }
                break;

                case OpCode.SETF:
                case OpCode.SETNF:
                {
                    var dst = ins.GetRegisterSlot(0);
                    switch (ins.OpCode)
                    {
                    case OpCode.SETF:
                        ex[dst] = flag;
                        break;

                    case OpCode.SETNF:
                        ex[dst] = flag.Invert();
                        break;
                    }
                }
                break;

                case OpCode.TT:
                {
                    flag = ex[ins.GetRegisterSlot(0)];
                }
                break;

                case OpCode.TF:
                {
                    flag = ex[ins.GetRegisterSlot(0)].Invert();
                }
                break;

                case OpCode.NF:
                {
                    flag = flag.Invert();
                }
                break;

                case OpCode.JF:
                case OpCode.JNF:
                {
                    bool jmpFlag = ins.OpCode == OpCode.JF;
                    expList.Add(new ConditionExpression(flag, jmpFlag)
                        {
                            JumpTo = ((JumpData)ins.Data).Goto.Line, ElseTo = ins.Line + 1
                        });
                }
                break;

                case OpCode.JMP:
                {
                    expList.Add(new GotoExpression {
                            JumpTo = ((JumpData)ins.Data).Goto.Line
                        });
                }
                break;

                case OpCode.CHS:
                case OpCode.INT:
                case OpCode.REAL:
                case OpCode.STR:
                case OpCode.NUM:
                case OpCode.OCTET:
                case OpCode.LNOT:
                case OpCode.INC:
                case OpCode.DEC:
                case OpCode.BNOT:
                case OpCode.TYPEOF:
                case OpCode.INV:
                {
                    var dstSlot = ins.GetRegisterSlot(0);
                    var dst     = ex[dstSlot];
                    var op      = UnaryOp.Unknown;
                    switch (ins.OpCode)
                    {
                    case OpCode.INC:
                        op = UnaryOp.Inc;
                        break;

                    case OpCode.DEC:
                        op = UnaryOp.Dec;
                        break;

                    case OpCode.CHS:
                        op = UnaryOp.InvertSign;
                        break;

                    case OpCode.INT:
                        op = UnaryOp.ToInt;
                        break;

                    case OpCode.REAL:
                        op = UnaryOp.ToReal;
                        break;

                    case OpCode.STR:
                        op = UnaryOp.ToString;
                        break;

                    case OpCode.NUM:
                        op = UnaryOp.ToNumber;
                        break;

                    case OpCode.BNOT:
                        op = UnaryOp.BitNot;
                        break;

                    case OpCode.OCTET:
                        op = UnaryOp.ToByteArray;
                        break;

                    case OpCode.LNOT:
                        op = UnaryOp.Not;
                        break;

                    case OpCode.TYPEOF:
                        op = UnaryOp.TypeOf;
                        break;

                    case OpCode.INV:
                        op = UnaryOp.Invalidate;
                        break;
                    }

                    var u = new UnaryExpression(dst, op);
                    //ex[dstSlot] = u;
                    expList.Add(u);
                }
                break;

                case OpCode.INCPD:
                case OpCode.DECPD:
                case OpCode.TYPEOFD:
                {
                    var res  = ins.GetRegisterSlot(0);
                    var obj  = ins.GetRegisterSlot(1);
                    var name = ins.Data.AsString();
                    var op   = UnaryOp.Unknown;
                    switch (ins.OpCode)
                    {
                    case OpCode.INCPI:
                        op = UnaryOp.Inc;
                        break;

                    case OpCode.DECPI:
                        op = UnaryOp.Dec;
                        break;

                    case OpCode.TYPEOFD:
                        op = UnaryOp.TypeOf;
                        break;
                    }

                    //var u = new UnaryExpression(new IdentifierExpression(name), op) {Instance = ex[obj]};
                    var u = new UnaryExpression(new IdentifierExpression(name)
                        {
                            Instance = ex[obj]
                        }, op);
                    if (res != 0)     //copy to %res
                    {
                        ex[res] = u;
                    }

                    expList.Add(u);
                }
                break;

                case OpCode.INCPI:
                case OpCode.DECPI:
                case OpCode.TYPEOFI:
                {
                    var res  = ins.GetRegisterSlot(0);
                    var obj  = ins.GetRegisterSlot(1);
                    var name = ins.GetRegisterSlot(2);
                    var op   = UnaryOp.Unknown;
                    switch (ins.OpCode)
                    {
                    case OpCode.INCPI:
                        op = UnaryOp.Inc;
                        break;

                    case OpCode.DECPI:
                        op = UnaryOp.Dec;
                        break;

                    case OpCode.TYPEOFI:
                        op = UnaryOp.TypeOf;
                        break;
                    }

                    var u = new UnaryExpression(new PropertyAccessExpression(ex[name], ex[obj]), op);
                    if (res != 0)     //copy to %res
                    {
                        ex[res] = u;
                    }

                    expList.Add(u);
                }
                break;

                case OpCode.INCP:
                case OpCode.DECP:
                    break;

                case OpCode.LORP:
                    break;

                case OpCode.LANDP:
                    break;

                case OpCode.BORP:
                    break;

                case OpCode.BXORP:
                    break;

                case OpCode.BANDP:
                    break;

                case OpCode.SARP:
                    break;

                case OpCode.SALP:
                    break;

                case OpCode.SRP:
                    break;

                case OpCode.CP:
                {
                    var dstSlot = ins.GetRegisterSlot(0);
                    var srcSlot = ins.GetRegisterSlot(1);

                    Expression src;
                    if (ex.ContainsKey(srcSlot))
                    {
                        src = ex[srcSlot];
                    }
                    else
                    {
                        src = new LocalExpression(context.Object, srcSlot);
                    }

                    Expression dst = null;
                    if (ex.ContainsKey(dstSlot))
                    {
                        //dst = ex[dstSlot];
                        ex[dstSlot] = src;
                    }
                    else if (dstSlot < -2)
                    {
                        var l = new LocalExpression(context.Object, dstSlot);
                        //if (!l.IsParameter)
                        //{
                        //    expList.Add(l);
                        //}
                        dst         = l;
                        ex[dstSlot] = l;     //assignment -> statements, local -> expressions

                        BinaryExpression b = new BinaryExpression(dst, src, BinaryOp.Assign)
                        {
                            IsDeclaration = true
                        };
                        //ex[dstSlot] = b;
                        expList.Add(b);
                    }
                    else if (dstSlot != 0)
                    {
                        ex[dstSlot] = src;
                    }
                }
                break;

                //Binary Operation
                case OpCode.ADD:
                case OpCode.SUB:
                case OpCode.MOD:
                case OpCode.DIV:
                case OpCode.IDIV:
                case OpCode.MUL:
                case OpCode.BAND:
                case OpCode.BOR:
                case OpCode.BXOR:
                case OpCode.LAND:
                case OpCode.LOR:
                case OpCode.SAR:
                case OpCode.SAL:
                case OpCode.SR:
                case OpCode.CHKINS:
                {
                    var dstSlot = ins.GetRegisterSlot(0);
                    var srcSlot = ins.GetRegisterSlot(1);
                    var store   = false;   //Set to Expression
                    var declare = false;   //Is declaration

                    Expression dst = null;
                    if (ex.ContainsKey(dstSlot))
                    {
                        dst = ex[dstSlot];
                    }
                    else if (dstSlot < -2)
                    {
                        var l = new LocalExpression(context.Object, dstSlot);
                        //if (!l.IsParameter)
                        //{
                        //    expList.Add(l);
                        //}
                        dst         = l;
                        ex[dstSlot] = l;
                        store       = false;
                        declare     = true;
                    }

                    Expression src;
                    if (ex.ContainsKey(srcSlot))
                    {
                        src = ex[srcSlot];
                    }
                    else
                    {
                        src = new LocalExpression(context.Object, srcSlot);
                    }

                    var op = BinaryOp.Unknown;
                    switch (ins.OpCode)
                    {
                    case OpCode.ADD:
                        op = BinaryOp.Add;
                        break;

                    case OpCode.SUB:
                        op = BinaryOp.Sub;
                        break;

                    case OpCode.MOD:
                        op = BinaryOp.Mod;
                        break;

                    case OpCode.DIV:
                        op = BinaryOp.Div;
                        break;

                    case OpCode.IDIV:
                        op = BinaryOp.Idiv;
                        break;

                    case OpCode.MUL:
                        op = BinaryOp.Mul;
                        break;

                    case OpCode.BAND:
                        op = BinaryOp.BitAnd;
                        break;

                    case OpCode.BOR:
                        op = BinaryOp.BitOr;
                        break;

                    case OpCode.BXOR:
                        op = BinaryOp.BitXor;
                        break;

                    case OpCode.LAND:
                        op = BinaryOp.LogicAnd;
                        break;

                    case OpCode.LOR:
                        op = BinaryOp.LogicOr;
                        break;

                    case OpCode.SAR:
                        op = BinaryOp.NumberShiftRight;
                        break;

                    case OpCode.SAL:
                        op = BinaryOp.NumberShiftLeft;
                        break;

                    case OpCode.SR:
                        op = BinaryOp.BitShiftRight;
                        break;

                    //case OpCode.CP: //moved!
                    //    op = BinaryOp.Assign;
                    //    push = true;
                    //break;
                    case OpCode.CHKINS:
                        op = BinaryOp.InstanceOf;
                        break;
                    }

                    BinaryExpression b = new BinaryExpression(dst, src, op)
                    {
                        IsDeclaration = declare
                    };

                    if (store)
                    {
                        ex[dstSlot] = b;
                    }

                    expList.Add(b);
                }
                break;

                case OpCode.ADDPD:
                case OpCode.SUBPD:
                case OpCode.MODPD:
                case OpCode.DIVPD:
                case OpCode.IDIVPD:
                case OpCode.MULPD:
                case OpCode.BANDPD:
                case OpCode.BORPD:
                case OpCode.BXORPD:
                case OpCode.LANDPD:
                case OpCode.LORPD:
                case OpCode.SARPD:
                case OpCode.SALPD:
                case OpCode.SRPD:
                {
                    var res  = ins.GetRegisterSlot(0);
                    var obj  = ins.GetRegisterSlot(1);
                    var name = ins.Data.AsString();
                    var op   = BinaryOp.Unknown;

                    var src = ex[ins.GetRegisterSlot(3)];
                    switch (ins.OpCode)
                    {
                    case OpCode.ADDPD:
                        op = BinaryOp.Add;
                        break;

                    case OpCode.SUBPD:
                        op = BinaryOp.Sub;
                        break;

                    case OpCode.MODPD:
                        op = BinaryOp.Mod;
                        break;

                    case OpCode.DIVPD:
                        op = BinaryOp.Div;
                        break;

                    case OpCode.IDIVPD:
                        op = BinaryOp.Idiv;
                        break;

                    case OpCode.MULPD:
                        op = BinaryOp.Mul;
                        break;

                    case OpCode.BANDPD:
                        op = BinaryOp.BitAnd;
                        break;

                    case OpCode.BORPD:
                        op = BinaryOp.BitOr;
                        break;

                    case OpCode.BXORPD:
                        op = BinaryOp.BitXor;
                        break;

                    case OpCode.LANDPD:
                        op = BinaryOp.LogicAnd;
                        break;

                    case OpCode.LORPD:
                        op = BinaryOp.LogicOr;
                        break;

                    case OpCode.SARPD:
                        op = BinaryOp.NumberShiftRight;
                        break;

                    case OpCode.SALPD:
                        op = BinaryOp.NumberShiftLeft;
                        break;

                    case OpCode.SRPD:
                        op = BinaryOp.BitShiftRight;
                        break;
                    }

                    BinaryExpression b = new BinaryExpression(new IdentifierExpression(name)
                        {
                            Instance = ex[obj]
                        },
                                                              src, op);

                    if (res != 0)
                    {
                        ex[res] = b;
                    }

                    expList.Add(b);
                }
                break;

                case OpCode.ADDPI:
                case OpCode.SUBPI:
                case OpCode.MODPI:
                case OpCode.DIVPI:
                case OpCode.IDIVPI:
                case OpCode.MULPI:
                case OpCode.BANDPI:
                case OpCode.BORPI:
                case OpCode.BXORPI:
                case OpCode.LANDPI:
                case OpCode.LORPI:
                case OpCode.SARPI:
                case OpCode.SALPI:
                case OpCode.SRPI:
                {
                    var res  = ins.GetRegisterSlot(0);
                    var obj  = ins.GetRegisterSlot(1);
                    var name = ins.GetRegisterSlot(2);
                    var op   = BinaryOp.Unknown;

                    var src = ex[ins.GetRegisterSlot(3)];
                    switch (ins.OpCode)
                    {
                    case OpCode.ADDPI:
                        op = BinaryOp.Add;
                        break;

                    case OpCode.SUBPI:
                        op = BinaryOp.Sub;
                        break;

                    case OpCode.MODPI:
                        op = BinaryOp.Mod;
                        break;

                    case OpCode.DIVPI:
                        op = BinaryOp.Div;
                        break;

                    case OpCode.IDIVPI:
                        op = BinaryOp.Idiv;
                        break;

                    case OpCode.MULPI:
                        op = BinaryOp.Mul;
                        break;

                    case OpCode.BANDPI:
                        op = BinaryOp.BitAnd;
                        break;

                    case OpCode.BORPI:
                        op = BinaryOp.BitOr;
                        break;

                    case OpCode.BXORPI:
                        op = BinaryOp.BitXor;
                        break;

                    case OpCode.LANDPI:
                        op = BinaryOp.LogicAnd;
                        break;

                    case OpCode.LORPI:
                        op = BinaryOp.LogicOr;
                        break;

                    case OpCode.SARPI:
                        op = BinaryOp.NumberShiftRight;
                        break;

                    case OpCode.SALPI:
                        op = BinaryOp.NumberShiftLeft;
                        break;

                    case OpCode.SRPI:
                        op = BinaryOp.BitShiftRight;
                        break;
                    }

                    BinaryExpression b =
                        new BinaryExpression(new PropertyAccessExpression(ex[name], ex[obj]), src, op);

                    if (res != 0)
                    {
                        ex[res] = b;
                    }

                    expList.Add(b);
                }
                break;

                case OpCode.ADDP:
                    break;

                case OpCode.SUBP:
                    break;

                case OpCode.MODP:
                    break;

                case OpCode.DIVP:
                    break;

                case OpCode.IDIVP:
                    break;

                case OpCode.MULP:
                    break;

                case OpCode.EVAL:
                    break;

                case OpCode.EEXP:
                    break;

                case OpCode.ASC:
                    break;

                case OpCode.CHR:
                    break;

                case OpCode.CHKINV:
                    break;

                //Invoke
                case OpCode.CALL:
                {
                    var call = new InvokeExpression(((OperandData)ins.Data).Variant as TjsCodeObject);
                    var dst  = ins.GetRegisterSlot(0);
                    call.Instance = null;
                    var paramCount = ins.GetRegisterSlot(2);
                    if (paramCount == -1)
                    {
                        //...
                        //do nothing
                    }
                    else
                    {
                        for (int j = 0; j < paramCount; j++)
                        {
                            var pSlot = ins.GetRegisterSlot(3 + j);
                            call.Parameters.Add(ex[pSlot]);
                        }
                    }

                    ex[dst] = call;
                    //if (dst == 0) //just execute and discard result
                    //{
                    //    expList.Add(call);
                    //}
                    expList.Add(call);
                }
                break;

                case OpCode.CALLD:
                {
                    var callMethodName = ins.Data.AsString();
                    var call           = new InvokeExpression(callMethodName);
                    var dst            = ins.GetRegisterSlot(0);
                    var callerSlot     = ins.GetRegisterSlot(1);
                    call.Instance = ex[callerSlot];
                    var paramCount = ins.GetRegisterSlot(3);
                    if (paramCount == -1)
                    {
                        //...
                        //do nothing
                    }
                    else
                    {
                        for (int j = 0; j < paramCount; j++)
                        {
                            var pSlot = ins.GetRegisterSlot(4 + j);
                            ex[pSlot].Parent = call;
                            call.Parameters.Add(ex[pSlot]);
                        }
                    }

                    ex[dst] = call;
                    if (dst == 0)     //just execute and discard result
                    {
                        //Handle RegExp()._compile("//g/[^A-Za-z]")
                        if (callMethodName == Const.RegExpCompile)
                        {
                            if (call.Instance is InvokeExpression invoke && invoke.Method == Const.RegExp)
                            {
                                call.InvokeType = InvokeType.RegExpCompile;
                                ex[callerSlot]  = call;
                                break;
                            }
                        }

                        expList.Add(call);
                    }
                }
                break;

                case OpCode.CALLI:
                {
                    //InvokeExpression call = null;
                    //var operand = ((OperandData) ins.Data).Variant;
                    //if (operand is TjsString str)
                    //{
                    //    call = new InvokeExpression(str.StringValue);
                    //}
                    //else
                    //{
                    //    call = new InvokeExpression(operand as TjsCodeObject);
                    //}
                    InvokeExpression call = new InvokeExpression(ex[ins.GetRegisterSlot(2)]);
                    var dst        = ins.GetRegisterSlot(0);
                    var callerSlot = ins.GetRegisterSlot(1);
                    call.Instance = ex[callerSlot];
                    var paramCount = ins.GetRegisterSlot(3);
                    if (paramCount == -1)
                    {
                        //...
                        //do nothing
                    }
                    else
                    {
                        for (int j = 0; j < paramCount; j++)
                        {
                            var pSlot = ins.GetRegisterSlot(4 + j);
                            ex[pSlot].Parent = call;
                            call.Parameters.Add(ex[pSlot]);
                        }
                    }

                    ex[dst] = call;
                    //if (dst == 0) //just execute and discard result
                    //{
                    //    expList.Add(call);
                    //}
                    expList.Add(call);
                }
                break;

                case OpCode.NEW:
                {
                    InvokeExpression call = new InvokeExpression(ex[ins.GetRegisterSlot(1)])
                    {
                        InvokeType = InvokeType.Ctor
                    };
                    var dst = ins.GetRegisterSlot(0);
                    call.Instance = null;
                    var paramCount = ins.GetRegisterSlot(2);
                    if (paramCount == -1)
                    {
                        //...
                        //do nothing
                    }
                    else
                    {
                        for (int j = 0; j < paramCount; j++)
                        {
                            var pSlot = ins.GetRegisterSlot(3 + j);
                            ex[pSlot].Parent = call;
                            call.Parameters.Add(ex[pSlot]);
                        }
                    }

                    ex[dst] = call;
                    //if (dst == 0) //just execute and discard result
                    //{
                    //    expList.Add(call);
                    //}
                    expList.Add(call);
                }
                break;

                case OpCode.GPD:
                case OpCode.GPDS:
                {
                    var dst      = ins.GetRegisterSlot(0);
                    var slot     = ins.GetRegisterSlot(1);
                    var instance = ex[slot];
                    var name     = ins.Data.AsString();
                    var newId    = new IdentifierExpression(name)
                    {
                        Instance = instance
                    };
                    ex[dst] = newId;
                }
                break;

                case OpCode.GPI:
                case OpCode.GPIS:
                {
                    var dst  = ins.GetRegisterSlot(0);
                    var obj  = ins.GetRegisterSlot(1);
                    var name = ins.GetRegisterSlot(2);

                    PropertyAccessExpression p = new PropertyAccessExpression(ex[name], ex[obj]);
                    ex[dst] = p;
                }
                break;

                case OpCode.SPI:
                case OpCode.SPIE:
                case OpCode.SPIS:
                {
                    var obj  = ins.GetRegisterSlot(0);
                    var name = ins.GetRegisterSlot(1);
                    var src  = ins.GetRegisterSlot(2);

                    BinaryExpression b = new BinaryExpression(new PropertyAccessExpression(ex[name], ex[obj]),
                                                              ex[src], BinaryOp.Assign);
                    expList.Add(b);     //there is no other way to find this expression
                }
                break;

                //Set
                case OpCode.SPD:
                case OpCode.SPDE:
                case OpCode.SPDEH:
                case OpCode.SPDS:
                {
                    var left = new IdentifierExpression(ins.Data.AsString())
                    {
                        Instance = ex[ins.GetRegisterSlot(0)]
                    };
                    var right          = ex[ins.GetRegisterSlot(2)];
                    BinaryExpression b = new BinaryExpression(left, right, BinaryOp.Assign);
                    //check declare
                    if (context.Object.ContextType == TjsContextType.TopLevel)
                    {
                        if (!context.RegisteredMembers.ContainsKey(left.Name))
                        {
                            b.IsDeclaration = true;
                            var stub = new TjsStub();
                            if (right is ConstantExpression con)     //TODO: better type check
                            {
                                stub.Type = con.DataType;
                            }

                            context.RegisteredMembers[left.Name] = stub;
                        }
                    }

                    expList.Add(b);
                }
                break;

                case OpCode.SETP:
                {
                }
                break;

                case OpCode.GETP:
                {
                }
                break;

                //Delete
                case OpCode.DELD:
                    DeleteExpression d = new DeleteExpression(ins.Data.AsString());
                    d.Instance = ex[ins.GetRegisterSlot(1)];
                    expList.Add(d);
                    break;

                case OpCode.DELI:
                    DeleteExpression d2 = new DeleteExpression(ex[ins.GetRegisterSlot(2)]);
                    d2.Instance = ex[ins.GetRegisterSlot(1)];
                    //Check declare
                    if (d2.Instance is IdentifierExpression toDel)
                    {
                        if (context.RegisteredMembers.ContainsKey(toDel.Name))
                        {
                            context.RegisteredMembers.Remove(toDel.Name);
                        }
                    }

                    expList.Add(d2);
                    break;

                case OpCode.SRV:
                {
                    var srv = ins.GetRegisterSlot(0);
                    retExp = srv == 0 ? null : ex[srv];
                }
                break;

                case OpCode.RET:
                {
                    expList.Add(new ReturnExpression(retExp));
                }
                break;

                case OpCode.ENTRY:
                    break;

                case OpCode.EXTRY:
                    break;

                case OpCode.THROW:
                {
                    var th = new ThrowExpression(ex[ins.GetRegisterSlot(0)]);
                    expList.Add(th);
                }
                break;

                case OpCode.CHGTHIS:
                    break;

                case OpCode.GLOBAL:
                {
                    ex[ins.GetRegisterSlot(0)] = Global;
                }
                break;

                case OpCode.ADDCI:
                    break;

                case OpCode.REGMEMBER:
                    break;

                case OpCode.DEBUGGER:
                    break;

                case OpCode.LAST:
                    break;

                case OpCode.PreDec:
                    break;

                case OpCode.PostInc:
                    break;

                case OpCode.PostDec:
                    break;

                case OpCode.Delete:
                    break;

                case OpCode.FuncCall:
                    break;

                case OpCode.IgnorePropGet:
                    break;

                case OpCode.IgnorePropSet:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            expList.RemoveAll(node => node is Expression exp && exp.Parent != null);

            //Save states
            ex[Const.FlagReg] = flag;
            context.BlockFinalStates[block] = ex;

            //Process next
            foreach (var succ in block.To)
            {
                BlockProcess(context, succ, ex); //TODO: deep copy flag?
            }
        }
Esempio n. 31
0
 DecompileContext CreateDecompileContext()
 {
     var decompileContext = new DecompileContext();
     var decompilationContext = new DecompilationContext();
     decompilationContext.GetDisableAssemblyLoad = () => decompileFileTabContentFactory.FileManager.DisableAssemblyLoad();
     decompilationContext.IsBodyModified = m => decompileFileTabContentFactory.MethodAnnotations.IsBodyModified(m);
     var output = new AvalonEditTextOutput();
     var dispatcher = Dispatcher.CurrentDispatcher;
     decompileContext.DecompileNodeContext = new DecompileNodeContext(decompilationContext, language, output, dispatcher);
     return decompileContext;
 }
Esempio n. 32
0
		DecompileContext CreateDecompileContext(string filename) {
			var decompileContext = new DecompileContext();
			try {
				var decompilationContext = new DecompilationContext();
				decompileContext.Writer = new StreamWriter(filename);
				var output = new TextWriterDecompilerOutput(decompileContext.Writer);
				var dispatcher = Dispatcher.CurrentDispatcher;
				decompileContext.DecompileNodeContext = new DecompileNodeContext(decompilationContext, decompiler, output, NullDocumentWriterService.Instance, dispatcher);
				return decompileContext;
			}
			catch {
				decompileContext.Dispose();
				throw;
			}
		}
Esempio n. 33
0
		DecompileContext CreateDecompileContext(string filename) {
			var decompileContext = new DecompileContext();
			try {
				decompileContext.Writer = new StreamWriter(filename);
				decompileContext.Output = new PlainTextOutput(decompileContext.Writer);
				return decompileContext;
			}
			catch {
				decompileContext.Dispose();
				throw;
			}
		}
Esempio n. 34
0
 DecompileContext CreateDecompileContext(string filename)
 {
     var decompileContext = new DecompileContext();
     try {
         var decompilationContext = new DecompilationContext();
         decompileContext.Writer = new StreamWriter(filename);
         var output = new PlainTextOutput(decompileContext.Writer);
         var dispatcher = Dispatcher.CurrentDispatcher;
         decompileContext.DecompileNodeContext = new DecompileNodeContext(decompilationContext, language, output, dispatcher);
         return decompileContext;
     }
     catch {
         decompileContext.Dispose();
         throw;
     }
 }
Esempio n. 35
0
        //TODO: more robust RegMember detect

        public BlockStatement Process(DecompileContext context, BlockStatement statement)
        {
            context.RegisteredMembers.Clear();

            var entry = context.EntryBlock;
            var codes = entry.Instructions;
            int i     = 0;

            if (codes.Count < i + 3)
            {
                return(statement);
            }

            while (codes.Count >= i + 3)
            {
                if (codes[i].ToString() == "cl %1")
                {
                    codes.RemoveAt(i);
                    break;
                }

                if (codes[i].ToString().StartsWith("const %1,") &&
                    codes[i + 1].ToString() == "chgthis %1, %-1" &&
                    codes[i + 2].ToString().StartsWith("spds %-1.") && codes[i + 2].Registers[2].GetSlot() == 1)
                {
                    var data = codes[i].Data as OperandData;
                    if (data == null)
                    {
                        i += 3;
                        continue;
                    }

                    var func = data.Variant as TjsCodeObject;
                    if (func == null)
                    {
                        i += 3;
                        continue;
                    }

                    var memberData = codes[i + 2].Data as OperandData;
                    if (memberData == null)
                    {
                        i += 3;
                        continue;
                    }

                    var memberName = memberData.Variant as TjsString;
                    if (memberName == null)
                    {
                        i += 3;
                        continue;
                    }

                    context.RegisteredMembers[memberName] = func;
                    i += 3;
                }
                else
                {
                    break;
                }
            }

            codes.RemoveRange(0, i);

            return(statement);
        }
Esempio n. 36
0
        public static ASTNode ResolveInt(DecompileContext ctx, ASTNode intNode, ConditionalAssetType type)
        {
            int value = (intNode.Kind == ASTNode.StatementKind.Int16) ? (intNode as ASTInt16).Value : (intNode as ASTInt32).Value;

            switch (type.Kind)
            {
            case AssetType.Boolean:
                if (value == 0)
                {
                    return(new ASTBoolean(false));
                }
                else if (value == 1)
                {
                    return(new ASTBoolean(true));
                }
                break;

            case AssetType.Object:
                if (intNode.Kind == ASTNode.StatementKind.Int16)
                {
                    return(ResolveObject(ctx, intNode as ASTInt16));
                }
                break;

            case AssetType.Sprite:
                if (value >= 0 && value < ctx.Project.Sprites.Count)
                {
                    return(new ASTAsset(ctx.Project.Sprites[value].Name));
                }
                else if (value == -4)
                {
                    return(new ASTAsset("noone"));
                }
                break;

            case AssetType.Room:
                if (value >= 0 && value < ctx.Project.Rooms.Count)
                {
                    return(new ASTAsset(ctx.Project.Rooms[value].Name));
                }
                else if (value == -4)
                {
                    return(new ASTAsset("noone"));
                }
                break;

            case AssetType.Font:
                if (value >= 0 && value < ctx.Project.Fonts.Count)
                {
                    return(new ASTAsset(ctx.Project.Fonts[value].Name));
                }
                else if (value == -4)
                {
                    return(new ASTAsset("noone"));
                }
                break;

            case AssetType.Sound:
                if (value >= 0 && value < ctx.Project.Sounds.Count)
                {
                    return(new ASTAsset(ctx.Project.Sounds[value].Name));
                }
                else if (value == -4)
                {
                    return(new ASTAsset("noone"));
                }
                break;

            case AssetType.Path:
                if (value >= 0 && value < ctx.Project.Paths.Count)
                {
                    return(new ASTAsset(ctx.Project.Paths[value].Name));
                }
                else if (value == -4)
                {
                    return(new ASTAsset("noone"));
                }
                break;

            case AssetType.Color:
                if (value >= 0)
                {
                    if (ctx.Cache.Types.ColorMacros.TryGetValue(value, out string color))
                    {
                        return(new ASTAsset(color));
                    }
                    return(new ASTAsset((ctx.Data.VersionInfo.IsNumberAtLeast(2) ? "0x" : "$") + value.ToString("X6", CultureInfo.InvariantCulture)));
                }
                break;

            case AssetType.Keyboard:
                if (value >= 0)
                {
                    if (ctx.Cache.Types.KeyboardMacros.TryGetValue(value, out string keyboard))
                    {
                        return(new ASTAsset(keyboard));
                    }
                    if (value >= '0' && value <= 'Z')
                    {
                        return(new ASTAsset("ord(\"" + (char)value + "\")"));
                    }
                }
                break;

            case AssetType.Macro_PathEndAction:
            {
                if (ctx.Cache.Types.PathEndActionMacros.TryGetValue(value, out string macro))
                {
                    return(new ASTAsset(macro));
                }
            }
            break;
            }
            return(intNode);
        }
		DecompileContext CreateDecompileContext(IShowContext ctx) {
			var decompileContext = new DecompileContext();
			var decompilationContext = new DecompilationContext();
			decompilationContext.CalculateBinSpans = true;
			decompilationContext.GetDisableAssemblyLoad = () => decompileDocumentTabContentFactory.DocumentService.DisableAssemblyLoad();
			decompilationContext.IsBodyModified = m => decompileDocumentTabContentFactory.MethodAnnotations.IsBodyModified(m);
			var dispatcher = Dispatcher.CurrentDispatcher;
			decompileContext.DocumentViewerContentFactory = decompileDocumentTabContentFactory.DocumentViewerContentFactoryProvider.Create();
			decompileContext.DecompileNodeContext = new DecompileNodeContext(decompilationContext, Decompiler, decompileContext.DocumentViewerContentFactory.Output, decompileDocumentTabContentFactory.DocumentWriterService, dispatcher);
			if (ctx.IsRefresh) {
				decompileContext.SavedRefPos = ((IDocumentViewer)ctx.UIContext).SaveReferencePosition();
				if (decompileContext.SavedRefPos != null) {
					ctx.OnShown = e => {
						if (e.Success && !e.HasMovedCaret) {
							e.HasMovedCaret = ((IDocumentViewer)ctx.UIContext).RestoreReferencePosition(decompileContext.SavedRefPos);
							if (!e.HasMovedCaret) {
								((IDocumentViewer)ctx.UIContext).MoveCaretToPosition(0);
								e.HasMovedCaret = true;
							}
						}
					};
				}
			}
			return decompileContext;
		}