public void SaveTextToMultipleFiles(string outputFileName, Encoding encoding) { this.IncludeMessages = true; this.IncludeStrings = false; string baseDirectoryName = Path.GetDirectoryName(outputFileName); string textDirectory = Path.Combine(baseDirectoryName, "text"); string rootFileName = Path.Combine(textDirectory, "root.txt"); Directory.CreateDirectory(textDirectory); using (var rootFileStream = new FileStream(rootFileName, FileMode.Create, FileAccess.Write)) { var rootTextWriter = new StreamWriter(rootFileStream, encoding); var enumerator = new FunctionEnumerator(ainFile); var results = enumerator.GetFilesAndFunctions(); foreach (var result1 in results) { string jafFileName = result1.name; foreach (var functionNode in result1.children) { var function = ainFile.GetFunction(functionNode.name); var text = GetTextFromFunction(function); if (text.Count > 2) { string functionName = AssemblerProjectWriter.SanitizeVariableName(function.Name); if (functionName.StartsWith("\"")) { } else { string includeFileName = Path.Combine(jafFileName, functionName + ".txt"); string fileName = Path.Combine(textDirectory, includeFileName); string outputDirectory = Path.GetDirectoryName(fileName); Directory.CreateDirectory(outputDirectory); File.WriteAllLines(fileName, text.ToArray(), encoding); rootTextWriter.WriteLine("#include \"" + includeFileName + "\""); } } } } rootTextWriter.Flush(); rootFileStream.Flush(); rootTextWriter.Close(); rootFileStream.Close(); } using (var textWriter2 = new StreamWriter(outputFileName, false, encoding)) { textWriter2.WriteLine("#include \"text/root.txt\""); textWriter2.Flush(); textWriter2.Close(); } }
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); } }
public void GetExclusionList() { this.exclusionFlags = (this.ExcludeFunctionNames ? (int)StringExclusionReason.IsFunctionName : 0) | (this.ExcludeSystemFunctions ? (int)StringExclusionReason.IsInsideSystemFunction : 0) | (this.ExcludeTestFunctions ? (int)StringExclusionReason.IsInsideTestFunction : 0) | (this.ExcludeUnusedStrings ? (int)StringExclusionReason.IsUnused : 0) | (this.ExcludeAsserts ? (int)StringExclusionReason.IsAssert : 0) | (this.ExcludeEventFlags ? (int)StringExclusionReason.IsEvent : 0); if (alreadyBuilt) { return; } alreadyBuilt = true; //if (currentExclusionFlags == newExclusionFlags) //{ // return; //} //currentExclusionFlags = newExclusionFlags; stringsToExclude.Clear(); //build list of "System" functions var functionEnumerator = new FunctionEnumerator(ainFile); var filesAndFunctions = functionEnumerator.GetFilesAndFunctions(); var systemFiles = filesAndFunctions.Where(f => f.name.StartsWith("System\\", StringComparison.OrdinalIgnoreCase)); var systemFunctions = new HashSet <int>(systemFiles.SelectMany(f => f.children).Select(res => res.id)); Dictionary <int, HashSet <int> > assertStringNumberToFunctionIndex = GetStringsUsedInAsserts(); HashSet <Function> functionsThatCallEv = new HashSet <Function>(); //get functions that call "EV()" var evFunction = ainFile.GetFunction("EV"); if (evFunction != null) { functionsThatCallEv = ainFile.CodeSearchCache.FunctionsCache.GetUsedBy(evFunction); } //Is it used as part of a function call to EV? foreach (var function in functionsThatCallEv) { int address = function.Address; int codeLength = ainFile.Code.Length; int evFunctionIndex = evFunction.Index; int evFunctionArgs = evFunction.ParameterCount; int evFunctionOffset = evFunctionArgs * 6; while (address < codeLength) { var instructionInfo = Decompiler.Peek(ainFile.Code, address); if (instructionInfo.instruction == Instruction.CALLFUNC && instructionInfo.word1 == evFunctionIndex) { var ins1 = Decompiler.Peek(ainFile.Code, instructionInfo.CurrentAddress - evFunctionOffset); if (ins1.instruction == Instruction.S_PUSH) { stringsToExclude.SetBit(ins1.word1, StringExclusionReason.IsEvent); } } else if (instructionInfo.instruction == Instruction.FUNC || instructionInfo.instruction == Instruction.ENDFUNC) { break; } address = instructionInfo.nextAddress; } //var expression = ainFile.DecompiledCodeCache.GetDecompiledCode(function); //var childExpressions = expression.GetChildExpressions(); //var evCalls = childExpressions.Where(e => e.ExpressionType == Instruction.CALLFUNC && e.Variable == evFunction); //var stringNumbers = evCalls.SelectMany(evCall => evCall.GetChildExpressions()) // .Where(e => e.ExpressionType == Instruction.S_PUSH) // .Select(e => e.Value); //foreach (var stringNumber in stringNumbers) //{ // stringsToExclude.SetBit(stringNumber, ExclusionReason.IsEvent); //} } for (int i = 0; i < ainFile.Strings.Count; i++) { string str = ainFile.Strings[i]; if (String.IsNullOrEmpty(str)) { continue; } //Is it a function name? if (ainFile.FunctionNameToIndex.ContainsKey(str)) { stringsToExclude.SetBit(i, StringExclusionReason.IsFunctionName); } var usedBy = ainFile.CodeSearchCache.StringsCache.GetUsedBy(str); //Is it used only by a function containing TEST or DEBUG in its name? if (usedBy.All(f => f.Name.Contains("テスト") || f.Name.Contains("デバッグ"))) //TEST or DEBUG { stringsToExclude.SetBit(i, StringExclusionReason.IsInsideTestFunction); } //Is it used only by a system function? if (usedBy.All(f => systemFunctions.Contains(f.Index))) { stringsToExclude.SetBit(i, StringExclusionReason.IsInsideSystemFunction); } //Is it never used? if (usedBy.Count == 0) { stringsToExclude.SetBit(i, StringExclusionReason.IsUnused); } //Is it used only in an assert? if (assertStringNumberToFunctionIndex.ContainsKey(i)) { var assertFunctionIndexes = assertStringNumberToFunctionIndex[i]; var usedByFunctionIndexes = usedBy.Select(f => f.Index); if (assertFunctionIndexes.SetEquals(usedByFunctionIndexes)) { stringsToExclude.SetBit(i, StringExclusionReason.IsAssert); } } } if (stringsToExclude.ContainsKey(0)) { stringsToExclude.Remove(0); } ////part 1: function names //if (ExcludeFunctionNames) //{ // for (int i = 0; i < ainFile.Strings.Count; i++) // { // string str = ainFile.Strings[i]; // if (ainFile.FunctionNameToIndex.ContainsKey(str)) // { // stringsToExclude.SetBit(i, ExclusionReason.IsFunctionName); // } // } //} ////part 2: Test functions //if (ExcludeTestFunctions) //{ // for (int i = 0; i < ainFile.Strings.Count; i++) // { // string str = ainFile.Strings[i]; // var usedBy = ainFile.CodeSearchCache.StringsCache.GetUsedBy(str); // if (usedBy.All(f => f.Name.Contains("テスト") || f.Name.Contains("デバッグ"))) //TEST or DEBUG // { // stringsToExclude.SetBit(i, ExclusionReason.IsInsideTestFunction); // } // } //} ////part 3: System functions //if (ExcludeSystemFunctions) //{ // for (int i = 0; i < ainFile.Strings.Count; i++) // { // string str = ainFile.Strings[i]; // var usedBy = ainFile.CodeSearchCache.StringsCache.GetUsedBy(str); // if (usedBy.All(f => systemFunctions.Contains(f.Index))) // { // stringsToExclude.SetBit(i, ExclusionReason.IsInsideSystemFunction); // } // } //} ////part 4: Unused strings //if (ExcludeUnusedStrings) //{ // for (int i = 0; i < ainFile.Strings.Count; i++) // { // string str = ainFile.Strings[i]; // var usedBy = ainFile.CodeSearchCache.StringsCache.GetUsedBy(str); // if (usedBy.Count == 0) // { // stringsToExclude.SetBit(i, ExclusionReason.IsUnused); // } // } //} }