/** * Finds the original field name(s), appending the first one to the out line, and any additional * alternatives to the extra lines. */ private void originalFieldName( String className, String obfuscatedFieldName, String type, StringBuffer outLine, List extraOutLines) { int extraIndent = -1; // Class name -> obfuscated field names. Map fieldMap = (Map) classFieldMap.get(className); if (fieldMap != null) { // Obfuscated field names -> fields. Set fieldSet = (Set) fieldMap.get(obfuscatedFieldName); if (fieldSet != null) { // Find all matching fields. Iterator fieldInfoIterator = fieldSet.iterator(); while (fieldInfoIterator.hasNext()) { FieldInfo fieldInfo = (FieldInfo) fieldInfoIterator.next(); if (fieldInfo.matches(type)) { // Is this the first matching field? if (extraIndent < 0) { extraIndent = outLine.length(); // Append the first original name. if (verbose) { outLine.append(fieldInfo.type).append(' '); } outLine.append(fieldInfo.originalName); } else { // Create an additional line with the proper // indentation. StringBuffer extraBuffer = new StringBuffer(); for (int counter = 0; counter < extraIndent; counter++) { extraBuffer.append(' '); } // Append the alternative name. if (verbose) { extraBuffer.append(fieldInfo.type).append(' '); } extraBuffer.append(fieldInfo.originalName); // Store the additional line. extraOutLines.add(extraBuffer); } } } } } // Just append the obfuscated name if we haven't found any matching // fields. if (extraIndent < 0) { outLine.append(obfuscatedFieldName); } }
/** Returns the original argument types. */ private String originalArguments(String obfuscatedArguments) { StringBuffer originalArguments = new StringBuffer(); int startIndex = 0; while (true) { int endIndex = obfuscatedArguments.indexOf(',', startIndex); if (endIndex < 0) { break; } originalArguments .append(originalType(obfuscatedArguments.substring(startIndex, endIndex).trim())) .append(','); startIndex = endIndex + 1; } originalArguments.append(originalType(obfuscatedArguments.substring(startIndex).trim())); return originalArguments.toString(); }
/** Performs the subsequent ReTrace operations. */ public void execute() throws IOException { // Read the mapping file. MappingReader mappingReader = new MappingReader(mappingFile); mappingReader.pump(this); StringBuffer expressionBuffer = new StringBuffer(regularExpression.length() + 32); char[] expressionTypes = new char[32]; int expressionTypeCount = 0; int index = 0; while (true) { int nextIndex = regularExpression.indexOf('%', index); if (nextIndex < 0 || nextIndex == regularExpression.length() - 1 || expressionTypeCount == expressionTypes.length) { break; } expressionBuffer.append(regularExpression.substring(index, nextIndex)); expressionBuffer.append('('); char expressionType = regularExpression.charAt(nextIndex + 1); switch (expressionType) { case 'c': expressionBuffer.append(REGEX_CLASS); break; case 'C': expressionBuffer.append(REGEX_CLASS_SLASH); break; case 'l': expressionBuffer.append(REGEX_LINE_NUMBER); break; case 't': expressionBuffer.append(REGEX_TYPE); break; case 'f': expressionBuffer.append(REGEX_MEMBER); break; case 'm': expressionBuffer.append(REGEX_MEMBER); break; case 'a': expressionBuffer.append(REGEX_ARGUMENTS); break; } expressionBuffer.append(')'); expressionTypes[expressionTypeCount++] = expressionType; index = nextIndex + 2; } expressionBuffer.append(regularExpression.substring(index)); Pattern pattern = Pattern.compile(expressionBuffer.toString()); // Read the stack trace file. LineNumberReader reader = new LineNumberReader( stackTraceFile == null ? (Reader) new InputStreamReader(System.in) : (Reader) new BufferedReader(new FileReader(stackTraceFile))); try { StringBuffer outLine = new StringBuffer(256); List extraOutLines = new ArrayList(); String className = null; // Read the line in the stack trace. while (true) { String line = reader.readLine(); if (line == null) { break; } Matcher matcher = pattern.matcher(line); if (matcher.matches()) { int lineNumber = 0; String type = null; String arguments = null; // Figure out a class name, line number, type, and // arguments beforehand. for (int expressionTypeIndex = 0; expressionTypeIndex < expressionTypeCount; expressionTypeIndex++) { int startIndex = matcher.start(expressionTypeIndex + 1); if (startIndex >= 0) { String match = matcher.group(expressionTypeIndex + 1); char expressionType = expressionTypes[expressionTypeIndex]; switch (expressionType) { case 'c': className = originalClassName(match); break; case 'C': className = originalClassName(ClassUtil.externalClassName(match)); break; case 'l': lineNumber = Integer.parseInt(match); break; case 't': type = originalType(match); break; case 'a': arguments = originalArguments(match); break; } } } // Actually construct the output line. int lineIndex = 0; outLine.setLength(0); extraOutLines.clear(); for (int expressionTypeIndex = 0; expressionTypeIndex < expressionTypeCount; expressionTypeIndex++) { int startIndex = matcher.start(expressionTypeIndex + 1); if (startIndex >= 0) { int endIndex = matcher.end(expressionTypeIndex + 1); String match = matcher.group(expressionTypeIndex + 1); // Copy a literal piece of input line. outLine.append(line.substring(lineIndex, startIndex)); char expressionType = expressionTypes[expressionTypeIndex]; switch (expressionType) { case 'c': className = originalClassName(match); outLine.append(className); break; case 'C': className = originalClassName(ClassUtil.externalClassName(match)); outLine.append(ClassUtil.internalClassName(className)); break; case 'l': lineNumber = Integer.parseInt(match); outLine.append(match); break; case 't': type = originalType(match); outLine.append(type); break; case 'f': originalFieldName(className, match, type, outLine, extraOutLines); break; case 'm': originalMethodName( className, match, lineNumber, type, arguments, outLine, extraOutLines); break; case 'a': arguments = originalArguments(match); outLine.append(arguments); break; } // Skip the original element whose processed version // has just been appended. lineIndex = endIndex; } } // Copy the last literal piece of input line. outLine.append(line.substring(lineIndex)); // Print out the main line. System.out.println(outLine); // Print out any additional lines. for (int extraLineIndex = 0; extraLineIndex < extraOutLines.size(); extraLineIndex++) { System.out.println(extraOutLines.get(extraLineIndex)); } } else { // Print out the original line. System.out.println(line); } } } catch (IOException ex) { throw new IOException("Can't read stack trace (" + ex.getMessage() + ")"); } finally { if (stackTraceFile != null) { try { reader.close(); } catch (IOException ex) { // This shouldn't happen. } } } }
/** * Finds the original method name(s), appending the first one to the out line, and any additional * alternatives to the extra lines. */ private void originalMethodName( String className, String obfuscatedMethodName, int lineNumber, String type, String arguments, StringBuffer outLine, List extraOutLines) { int extraIndent = -1; // Class name -> obfuscated method names. Map methodMap = (Map) classMethodMap.get(className); if (methodMap != null) { // Obfuscated method names -> methods. Set methodSet = (Set) methodMap.get(obfuscatedMethodName); if (methodSet != null) { // Find all matching methods. Iterator methodInfoIterator = methodSet.iterator(); while (methodInfoIterator.hasNext()) { MethodInfo methodInfo = (MethodInfo) methodInfoIterator.next(); if (methodInfo.matches(lineNumber, type, arguments)) { // Is this the first matching method? if (extraIndent < 0) { extraIndent = outLine.length(); // Append the first original name. if (verbose) { outLine.append(methodInfo.type).append(' '); } outLine.append(methodInfo.originalName); if (verbose) { outLine.append('(').append(methodInfo.arguments).append(')'); } } else { // Create an additional line with the proper // indentation. StringBuffer extraBuffer = new StringBuffer(); for (int counter = 0; counter < extraIndent; counter++) { extraBuffer.append(' '); } // Append the alternative name. if (verbose) { extraBuffer.append(methodInfo.type).append(' '); } extraBuffer.append(methodInfo.originalName); if (verbose) { extraBuffer.append('(').append(methodInfo.arguments).append(')'); } // Store the additional line. extraOutLines.add(extraBuffer); } } } } } // Just append the obfuscated name if we haven't found any matching // methods. if (extraIndent < 0) { outLine.append(obfuscatedMethodName); } }