internal static string GetClassAndPackageName(IAnnotatableClass item, out string[] packageNameItems) { if (null == item) { throw new ArgumentNullException(); } if (-1 != item.Name.IndexOf('$')) { throw new REException(); } string result = item.Name; List<string> namespaces = new List<string>(); for (INamespace scannedNamespace = item.Namespace; !scannedNamespace.IsRoot; scannedNamespace = scannedNamespace.Parent) { namespaces.Insert(0, scannedNamespace.Name); } packageNameItems = (0 == namespaces.Count) ? null : namespaces.ToArray(); return result; }
internal FileInfo GetClassFileName(IAnnotatableClass item, bool doNotCreate = false) { string[] packageNameItems; string simpleClassName = Helpers.GetClassAndPackageName(item, out packageNameItems); DirectoryInfo currentDirectory = _baseDirectory; if (null != packageNameItems) { for (int index = 0; index < packageNameItems.Length; index++) { DirectoryInfo nextDirectory = new DirectoryInfo(Path.Combine(currentDirectory.FullName, packageNameItems[index])); if (!nextDirectory.Exists && !doNotCreate) { nextDirectory.Create(); nextDirectory.Refresh(); } currentDirectory = nextDirectory; } } // Looks like the FileInfo instance Create call will from time to time trigger an // exception when we later attempt to open the file. So we stopped creating the file // here. return new FileInfo(Path.Combine(currentDirectory.FullName, simpleClassName + ".java")); }
/// <summary>Reverse a single class and output result in a file named from /// the class name and located in the appropriate directory reflecting the /// class package name.</summary> /// <param name="item">The class to be reversed.</param> /// <param name="reversedMethodsCount">On return this parameter is updated /// with the count of methods reversed within this class.</param> private void ReverseClass(IAnnotatableClass item, out int reversedMethodsCount) { FileInfo targetFile = _treeHandler.GetClassFileName(item); List<string> headerSourceCode = new List<string>(); List<string> methodsSourceCode = new List<string>(); StringBuilder methodsSourceCodeBuilder = new StringBuilder(); StringBuilder fieldsSourceCodeBuilder = new StringBuilder(); // TODO : Get rid of this dictionary. Dictionary<string, string> namespaceByImportedType = new Dictionary<string,string>(); List<IJavaType> importedTypes = new List<IJavaType>(); reversedMethodsCount = 0; if (!item.IsAbstract) { foreach (IField field in item.EnumerateFields()) { IJavaType fieldType = field.FieldType; if (!importedTypes.Contains(fieldType)) { importedTypes.Add(fieldType); } fieldsSourceCodeBuilder.AppendLine( BuildFieldDefinition(field, namespaceByImportedType)); } #if DBGCFG bool debugClassCfg = item.IsAnnotatedWith(CfgDebugAnnotation.Id); #endif foreach (IAnnotatableMethod method in item.EnumerateMethods()) { #if DBGCFG bool debugMethodCfg = debugClassCfg || method.IsAnnotatedWith(CfgDebugAnnotation.Id); #endif reversedMethodsCount++; // Extract all instructions from the method byte code. DalvikInstruction[] sparseInstructions = BuildInstructionList(method, _objectResolver); // Construct a first version of the CFG graph. CfgNode methodRootCfgNode = CfgBuilder.BuildBasicTree(method, sparseInstructions #if DBGCFG , debugMethodCfg #endif ); // Ensure each catch block from each try block starts on a block boundary. // Eventually create additional block to enforce the constraint. foreach (ITryBlock scannedBlock in method.EnumerateTryBlocks()) { foreach (IGuardHandler scannedHandler in scannedBlock.EnumerateHandlers()) { CfgBuilder.EnsureBlockBoundary(methodRootCfgNode, scannedHandler.HandlerMethodOffset); } } // Detect cycles in CFG graph. List<CircuitDefinition> circuits = new DirectedGraphCycleFinder(methodRootCfgNode).Resolve(); if (0 < circuits.Count) { int circuitId = 1; foreach (CircuitDefinition circuit in circuits) { Console.WriteLine("CIRCUIT #{0} ------------------", circuitId++); circuit.Print(); } int i = 1; } // Go on now with the AST tree. This is where we perform the real job. // AstNode methodRootAstNode = // AstBuilder.BuildTree(method, sparseInstructions, methodRootCfgNode, _objectResolver); //// Here we are we a basic CFG graph and an AST tree that is composed only //// of disassembled instruction. Time to augment the AST. //AstBuilder.CreateTryCatch(method, methodRootAstNode, methodRootCfgNode); //methodsSourceCodeBuilder.Append( // BuildSourceCode(method, methodRootAstNode, namespaceByImportedType)); //methodsSourceCodeBuilder.AppendLine(); } } FileStream stream = null; Console.WriteLine("Generating source code in {0} -------------------------", targetFile.FullName); try { stream = File.Open(targetFile.FullName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); using (StreamWriter writer = new StreamWriter(stream)) { writer.Write(BuildClassHeaderSourceCode(item, importedTypes).ToString()); writer.WriteLine("// FIELDS -----------------"); writer.Write(fieldsSourceCodeBuilder.ToString()); writer.WriteLine("// METHODS -----------------"); writer.Write(methodsSourceCodeBuilder.ToString()); // Class closing curly braces. writer.WriteLine("}"); } } finally { if (null != stream) { stream.Close(); } } }