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);
            }
        }
Exemple #3
0
        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);
            //        }
            //    }
            //}
        }