예제 #1
0
        /// <summary>
        /// Returns the disassembly of code starting at startAddress, until and excluding endAddress.
        /// </summary>
        /// <param name="startAddress">The address to start at</param>
        /// <param name="endAddress">The address to end at (output will exclude code at this address)</param>
        /// <returns>The disassembly of code between startAddress and endAddress (excluding endAddress)</returns>
        public string DisassembleListFileRange(int startAddress, int endAddress)
        {
            if (ainFile.Version == 0)
            {
                var function = Decompiler.FindFunctionByAddress(startAddress, ainFile);
                startAddress = function.Address;
                if (function != null)
                {
                    displayer.currentFuncNumber = function.Index;
                }
            }

            var sw = new StringWriter(CultureInfo.InvariantCulture);

            tw = new MyIndentedTextWriter(sw);
            int address = startAddress;

            while (address < endAddress)
            {
                address = DisassembleOneInstructionForListFile(address);
            }
            return(sw.GetStringBuilder().ToString());
        }
        internal void ExportFiles(string destinationPath)
        {
            ainFile.FindFunctionTypes();
            stopwatch.Start();

            var encoding   = Extensions.BinaryEncoding;
            var enumerator = new FunctionEnumerator(this.ainFile);
            var results    = enumerator.GetFilesAndFunctions();
            HashSet <Struct> UnvisitedStructs = new HashSet <Struct>(ainFile.Structs);
            HashSet <int>    VisitedFunctions = new HashSet <int>();
            int functionsVisited = 0;
            int totalFunctions   = ainFile.Functions.Count;

            codeDisplayOptions.DisplayDefaultValuesForMethods = false;
            var displayer = new ExpressionDisplayer(ainFile, codeDisplayOptions);

            StringBuilder mainIncludeFile = new StringBuilder();

            mainIncludeFile.AppendLine("Source = {");
            mainIncludeFile.AppendLine("\t\"constants.jaf\",");
            mainIncludeFile.AppendLine("\t\"classes.jaf\",");
            mainIncludeFile.AppendLine("\t\"globals.jaf\",");

            this.SeenFilenames.Add("classes.jaf");
            this.SeenFilenames.Add("globals.jaf");
            this.SeenFilenames.Add("constants.jaf");
            this.SeenFilenames.Add("HLL\\hll.inc");

            if (ainFile.Libraries.Count > 0)
            {
                mainIncludeFile.AppendLine("\t\"HLL\\hll.inc\",");
            }

            foreach (var fileNode in results)
            {
                string fileName = fileNode.name.Replace("\r", "\\r").Replace("\n", "\\n");  //fix filenames that went through bad tools
                if (fileNode.children.Count > 0)
                {
                    using (FileStream fs = CreateFileUnique(ref fileName, destinationPath))
                    {
                        mainIncludeFile.AppendLine("\t\"" + fileName + "\",");

                        using (var streamWriter = new StreamWriter(fs, encoding))
                        {
                            foreach (var functionNode in fileNode.children)
                            {
                                if (backgroundWorker != null)
                                {
                                    if (backgroundWorker.CancellationPending == true)
                                    {
                                        //abort
                                        return;
                                    }
                                }

                                int functionNumber = functionNode.id;
                                var function       = ainFile.GetFunction(functionNumber);

                                if (function.ToString().Contains("SP_SET_CG_REAL"))
                                {
                                    Console.WriteLine("SP_SET_CG_REAL");
                                }

                                if (!VisitedFunctions.Contains(functionNumber))
                                {
                                    VisitedFunctions.Add(functionNumber);
                                    if (this.backgroundWorker != null && stopwatch.ElapsedTime >= 250)
                                    {
                                        stopwatch.Start();
                                        backgroundWorker.ReportProgress(100 * functionsVisited / totalFunctions,
                                                                        "Function " + functionNumber.ToString() + " of " + totalFunctions.ToString() +
                                                                        ", currently decompiling" + Environment.NewLine + function.Name);
                                    }

                                    if (function.Name == "0" || function.Name.EndsWith("@2"))
                                    {
                                        //exclude global array initializer and struct array initializer functions
                                    }
                                    else
                                    {
                                        //var structInfo = function.GetClass();
                                        //if (structInfo != null)
                                        //{
                                        //    if (UnvisitedStructs.Contains(structInfo))
                                        //    {
                                        //        UnvisitedStructs.Remove(structInfo);
                                        //        string classDeclaration = displayer.GetClassDeclaration(structInfo);
                                        //        streamWriter.Write(classDeclaration);
                                        //    }
                                        //}
                                        if (Debugger.IsAttached)
                                        {
                                            //no exception handling when debugging - we want to see the exceptions
                                            try
                                            {
                                                var    expression = decompiler.DecompileFunction(function);
                                                string text       = displayer.PrintExpression2(expression, true);
                                                streamWriter.WriteLine(text);
                                            }
                                            finally
                                            {
                                            }
                                        }
                                        else
                                        {
                                            try
                                            {
                                                var    expression = decompiler.DecompileFunction(function);
                                                string text       = displayer.PrintExpression2(expression, true);
                                                streamWriter.WriteLine(text);
                                            }
                                            catch (Exception ex)
                                            {
                                                string errorMessage = "Function " + functionNode.name + " failed to decompile.";
                                                RaiseError(errorMessage, ex);
                                            }
                                            finally
                                            {
                                            }
                                        }
                                    }
                                    functionsVisited++;
                                }
                            }
                            streamWriter.Flush();
                            streamWriter.Close();
                        }
                    }
                }
            }
            mainIncludeFile.AppendLine("}");

            if (UnvisitedStructs.Count > 0)
            {
                var remainingStructs = UnvisitedStructs.OrderByIndex().ToArray();

                if (this.backgroundWorker != null)
                {
                    backgroundWorker.ReportProgress(100, "Generating class declarations...");
                }
                using (var fs = CreateFile("classes.jaf", destinationPath))
                {
                    using (var sw = new StreamWriter(fs, encoding))
                    {
                        foreach (var structInfo in remainingStructs)
                        {
                            string classDeclaration = displayer.GetClassDeclaration(structInfo);
                            sw.Write(classDeclaration);
                            sw.WriteLine();
                        }

                        foreach (var funcType in ainFile.FunctionTypes)
                        {
                            string funcTypeDeclaration = displayer.GetFunctypeDeclaration(funcType);
                            sw.WriteLine(funcTypeDeclaration);
                        }

                        foreach (var delg in ainFile.Delegates)
                        {
                            string delegateDeclaration = displayer.GetDelegateDeclaration(delg);
                            sw.WriteLine(delegateDeclaration);
                        }
                        sw.Flush();
                        sw.Close();
                    }
                }
            }

            Dictionary <Global, Expression> globalInitializers = GetGlobalInitializers();

            if (this.backgroundWorker != null)
            {
                backgroundWorker.ReportProgress(100, "Listing global variables...");
            }

            using (var fs = CreateFile("globals.jaf", destinationPath))
            {
                string lastGlobalGroupName = null;
                using (var sw = new MyIndentedTextWriter(new StreamWriter(fs, encoding)))
                {
                    Dictionary <int, GlobalInitialValue> initialValues = new Dictionary <int, GlobalInitialValue>();
                    foreach (var globalInitialValue in ainFile.GlobalInitialValues)
                    {
                        initialValues[globalInitialValue.GlobalIndex] = globalInitialValue;
                    }


                    foreach (var global in ainFile.Globals)
                    {
                        if (global.DataType != DataType.Void)
                        {
                            string globalGroupName = global.GroupName;
                            if (globalGroupName != lastGlobalGroupName)
                            {
                                if (lastGlobalGroupName != null)
                                {
                                    sw.Indent--;
                                    sw.WriteLine("}");
                                }
                                if (globalGroupName != null)
                                {
                                    sw.WriteLine("globalgroup " + globalGroupName);
                                    sw.WriteLine("{");
                                    sw.Indent++;
                                }
                            }
                            lastGlobalGroupName = globalGroupName;

                            sw.Write(global.GetDataTypeName());
                            sw.Write(" ");
                            sw.Write(global.Name);

                            if (global.DataType.IsArray())
                            {
                                if (globalInitializers.ContainsKey(global))
                                {
                                    var expr = globalInitializers[global];

                                    foreach (var e in expr.Args)
                                    {
                                        if (e.ExpressionType == Instruction.PUSH)
                                        {
                                            sw.Write("[" + e.Value.ToString() + "]");
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if (initialValues.ContainsKey(global.Index))
                                {
                                    sw.Write(" = ");
                                    var initialValue = initialValues[global.Index];
                                    sw.Write(initialValue.GetValueQuoted());
                                }
                            }
                            sw.WriteLine(";");
                        }
                    }
                    if (lastGlobalGroupName != null)
                    {
                        sw.Indent--;
                        sw.WriteLine("}");
                    }
                    sw.Flush();
                    sw.Close();
                }
            }

            using (var fs = CreateFile("constants.jaf", destinationPath))
            {
                using (StreamWriter sw = new StreamWriter(fs, encoding))
                {
                    sw.WriteLine("const int true = 1;");
                    sw.WriteLine("const int false = 0;");
                    sw.WriteLine();
                    if (ainFile.MetadataFile != null)
                    {
                        foreach (var pair in ainFile.MetadataFile.EnumerationTypes)
                        {
                            var enumerationType = pair.Value;
                            sw.WriteLine("//" + enumerationType.Name);
                            foreach (var pair2 in enumerationType)
                            {
                                sw.WriteLine("const int " + pair2.Value + " = " + pair2.Key.ToString() + ";");
                            }
                            sw.WriteLine();
                        }
                    }

                    sw.Flush();
                    fs.Flush();
                    sw.Close();
                    fs.Close();
                }
            }

            if (this.backgroundWorker != null)
            {
                backgroundWorker.ReportProgress(100, "Creating project file...");
            }

            if (ainFile.Libraries.Count > 0)
            {
                StringBuilder libraryIncludeFile = new StringBuilder();
                libraryIncludeFile.AppendLine("SystemSource = {");

                string hllDirectory = Path.Combine(destinationPath, "HLL");
                foreach (var library in ainFile.Libraries)
                {
                    string hllFileName = library.LibraryName + ".hll";

                    using (var fs = CreateFileUnique(ref hllFileName, hllDirectory))
                    {
                        libraryIncludeFile.AppendLine("\t\"" + hllFileName + "\",\t\"" + library.LibraryName + "\",");
                        using (var sw = new StreamWriter(fs, encoding))
                        {
                            foreach (var func in library.Functions)
                            {
                                string declaration = func.GetDeclaration() + ";";
                                sw.WriteLine(declaration);
                            }
                            sw.Flush();
                            sw.Close();
                        }
                    }
                }
                libraryIncludeFile.AppendLine("}");
                string includeFileContents = libraryIncludeFile.ToString();

                using (var fs = CreateFile("hll.inc", hllDirectory))
                {
                    using (var sw = new StreamWriter(fs, encoding))
                    {
                        sw.Write(includeFileContents);
                    }
                }
            }

            File.WriteAllText(Path.Combine(destinationPath, "main.inc"), mainIncludeFile.ToString(), encoding);

            //build a PJE file
            {
                StringBuilder pje = new StringBuilder();
                pje.AppendLine("// Project Environment File");
                pje.AppendLine("ProjectName = \"" + Path.GetFileNameWithoutExtension(this.ainFile.OriginalFilename) + "\"");
                pje.AppendLine();
                pje.AppendLine("CodeName = \"" + Path.GetFileNameWithoutExtension(this.ainFile.OriginalFilename) + ".ain\"");
                pje.AppendLine();
                pje.AppendLine("#define _AINVERSION " + ainFile.Version.ToString());
                pje.AppendLine("#define _KEYCODE 0x" + ainFile.KeyCode.ToString("X8"));
                pje.AppendLine("#define _ISAI2FILE " + (ainFile.IsAi2File ? "true" : "false"));
                if (ainFile.Version >= 6)
                {
                    pje.AppendLine("#define _USESMSG1 " + (ainFile.UsesMsg1 ? "true" : "false"));
                }
                pje.AppendLine("#define _TARGETVM " + ainFile.TargetVMVersion.ToString());
                pje.AppendLine();
                pje.AppendLine("GameVersion = " + ainFile.GameVersion.ToString());
                pje.AppendLine();
                pje.AppendLine("// Settings for each directory");
                pje.AppendLine("SourceDir = \".\"");
                pje.AppendLine("HLLDir = \"HLL\"");
                pje.AppendLine("ObjDir = \"OBJ\"");
                pje.AppendLine("OutputDir = \"Run\"");
                pje.AppendLine();
                pje.AppendLine("Source = {");
                pje.AppendLine("    \"main.inc\",");
                pje.AppendLine("}");

                string pjeFileName = Path.Combine(destinationPath, Path.GetFileNameWithoutExtension(this.ainFile.OriginalFilename) + ".pje");

                File.WriteAllText(pjeFileName, pje.ToString(), encoding);
            }
        }