/// <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); } }