summaryrefslogtreecommitdiffstats
path: root/src/proguard/obfuscate/MappingReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/obfuscate/MappingReader.java')
-rw-r--r--src/proguard/obfuscate/MappingReader.java199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/proguard/obfuscate/MappingReader.java b/src/proguard/obfuscate/MappingReader.java
new file mode 100644
index 0000000..24fd26c
--- /dev/null
+++ b/src/proguard/obfuscate/MappingReader.java
@@ -0,0 +1,199 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import java.io.*;
+
+
+/**
+ * This class can parse mapping files and invoke a processor for each of the
+ * mapping entries.
+ *
+ * @author Eric Lafortune
+ */
+public class MappingReader
+{
+ private final File mappingFile;
+
+
+ public MappingReader(File mappingFile)
+ {
+ this.mappingFile = mappingFile;
+ }
+
+
+ /**
+ * Reads the mapping file, presenting all of the encountered mapping entries
+ * to the given processor.
+ */
+ public void pump(MappingProcessor mappingProcessor) throws IOException
+ {
+ LineNumberReader reader = new LineNumberReader(
+ new BufferedReader(
+ new FileReader(mappingFile)));
+ try
+ {
+ String className = null;
+
+ // Read the subsequent class mappings and class member mappings.
+ while (true)
+ {
+ String line = reader.readLine();
+
+ if (line == null)
+ {
+ break;
+ }
+
+ line = line.trim();
+
+ // The distinction between a class mapping and a class
+ // member mapping is the initial whitespace.
+ if (line.endsWith(":"))
+ {
+ // Process the class mapping and remember the class's
+ // old name.
+ className = processClassMapping(line, mappingProcessor);
+ }
+ else if (className != null)
+ {
+ // Process the class member mapping, in the context of the
+ // current old class name.
+ processClassMemberMapping(className, line, mappingProcessor);
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new IOException("Can't process mapping file (" + ex.getMessage() + ")");
+ }
+ finally
+ {
+ try
+ {
+ reader.close();
+ }
+ catch (IOException ex)
+ {
+ // This shouldn't happen.
+ }
+ }
+ }
+
+
+ /**
+ * Parses the given line with a class mapping and processes the
+ * results with the given mapping processor. Returns the old class name,
+ * or null if any subsequent class member lines can be ignored.
+ */
+ private String processClassMapping(String line,
+ MappingProcessor mappingProcessor)
+ {
+ // See if we can parse "___ -> ___:", containing the original
+ // class name and the new class name.
+
+ int arrowIndex = line.indexOf("->");
+ if (arrowIndex < 0)
+ {
+ return null;
+ }
+
+ int colonIndex = line.indexOf(':', arrowIndex + 2);
+ if (colonIndex < 0)
+ {
+ return null;
+ }
+
+ // Extract the elements.
+ String className = line.substring(0, arrowIndex).trim();
+ String newClassName = line.substring(arrowIndex + 2, colonIndex).trim();
+
+ // Process this class name mapping.
+ boolean interested = mappingProcessor.processClassMapping(className, newClassName);
+
+ return interested ? className : null;
+ }
+
+
+ /**
+ * Parses the given line with a class member mapping and processes the
+ * results with the given mapping processor.
+ */
+ private void processClassMemberMapping(String className,
+ String line,
+ MappingProcessor mappingProcessor)
+ {
+ // See if we can parse "___:___:___ ___(___) -> ___",
+ // containing the optional line numbers, the return type, the original
+ // field/method name, optional arguments, and the new field/method name.
+
+ int colonIndex1 = line.indexOf(':');
+ int colonIndex2 = colonIndex1 < 0 ? -1 : line.indexOf(':', colonIndex1 + 1);
+ int spaceIndex = line.indexOf(' ', colonIndex2 + 2);
+ int argumentIndex1 = line.indexOf('(', spaceIndex + 1);
+ int argumentIndex2 = argumentIndex1 < 0 ? -1 : line.indexOf(')', argumentIndex1 + 1);
+ int arrowIndex = line.indexOf("->", Math.max(spaceIndex, argumentIndex2) + 1);
+
+ if (spaceIndex < 0 ||
+ arrowIndex < 0)
+ {
+ return;
+ }
+
+ // Extract the elements.
+ String type = line.substring(colonIndex2 + 1, spaceIndex).trim();
+ String name = line.substring(spaceIndex + 1, argumentIndex1 >= 0 ? argumentIndex1 : arrowIndex).trim();
+ String newName = line.substring(arrowIndex + 2).trim();
+
+ // Process this class member mapping.
+ if (type.length() > 0 &&
+ name.length() > 0 &&
+ newName.length() > 0)
+ {
+ // Is it a field or a method?
+ if (argumentIndex2 < 0)
+ {
+ mappingProcessor.processFieldMapping(className, type, name, newName);
+ }
+ else
+ {
+ int firstLineNumber = 0;
+ int lastLineNumber = 0;
+
+ if (colonIndex2 > 0)
+ {
+ firstLineNumber = Integer.parseInt(line.substring(0, colonIndex1).trim());
+ lastLineNumber = Integer.parseInt(line.substring(colonIndex1 + 1, colonIndex2).trim());
+ }
+
+ String arguments = line.substring(argumentIndex1 + 1, argumentIndex2).trim();
+
+ mappingProcessor.processMethodMapping(className,
+ firstLineNumber,
+ lastLineNumber,
+ type,
+ name,
+ arguments,
+ newName);
+ }
+ }
+ }
+}