1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 Eric Lafortune (eric (at) graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard.io; 22 23 import proguard.classfile.*; 24 import proguard.classfile.util.ClassUtil; 25 26 import java.io.IOException; 27 import java.util.Map; 28 29 /** 30 * This DataEntryReader delegates to another DataEntryReader, renaming the 31 * data entries based on the renamed classes in the given ClassPool. 32 * 33 * @author Eric Lafortune 34 */ 35 public class DataEntryObfuscator implements DataEntryReader 36 { 37 private final ClassPool classPool; 38 private final Map packagePrefixMap; 39 private final DataEntryReader dataEntryReader; 40 41 42 /** 43 * Creates a new DataEntryObfuscator. 44 * @param classPool the class pool that maps from old names to new 45 * names. 46 * @param packagePrefixMap the map from old package prefixes to new package 47 * prefixes. 48 * @param dataEntryReader the DataEntryReader to which calls will be 49 * delegated. 50 */ 51 public DataEntryObfuscator(ClassPool classPool, 52 Map packagePrefixMap, 53 DataEntryReader dataEntryReader) 54 { 55 this.classPool = classPool; 56 this.packagePrefixMap = packagePrefixMap; 57 this.dataEntryReader = dataEntryReader; 58 } 59 60 61 // Implementations for DataEntryReader. 62 63 public void read(DataEntry dataEntry) throws IOException 64 { 65 // Delegate to the actual data entry reader. 66 dataEntryReader.read(renamedDataEntry(dataEntry)); 67 } 68 69 70 /** 71 * Create a renamed data entry, if possible. 72 */ 73 private DataEntry renamedDataEntry(DataEntry dataEntry) 74 { 75 String dataEntryName = dataEntry.getName(); 76 77 // Try to find a corresponding class name by removing increasingly 78 // long suffixes, 79 for (int suffixIndex = dataEntryName.length() - 1; 80 suffixIndex > 0; 81 suffixIndex--) 82 { 83 char c = dataEntryName.charAt(suffixIndex); 84 if (!Character.isLetterOrDigit(c)) 85 { 86 // Chop off the suffix. 87 String className = dataEntryName.substring(0, suffixIndex); 88 89 // Did we get to the package separator? 90 if (c == ClassConstants.INTERNAL_PACKAGE_SEPARATOR) 91 { 92 break; 93 } 94 95 // Is there a class corresponding to the data entry? 96 Clazz clazz = classPool.getClass(className); 97 if (clazz != null) 98 { 99 // Did the class get a new name? 100 String newClassName = clazz.getName(); 101 if (!className.equals(newClassName)) 102 { 103 // Return a renamed data entry. 104 String newDataEntryName = 105 newClassName + dataEntryName.substring(suffixIndex); 106 107 return new RenamedDataEntry(dataEntry, newDataEntryName); 108 } 109 110 // Otherwise stop looking. 111 break; 112 } 113 } 114 } 115 116 // Did the package get a new name? 117 String packagePrefix = ClassUtil.internalPackagePrefix(dataEntryName); 118 String newPackagePrefix = (String)packagePrefixMap.get(packagePrefix); 119 if (newPackagePrefix != null && 120 !packagePrefix.equals(newPackagePrefix)) 121 { 122 // Return a renamed data entry. 123 String newDataEntryName = 124 newPackagePrefix + dataEntryName.substring(packagePrefix.length()); 125 126 return new RenamedDataEntry(dataEntry, newDataEntryName); 127 } 128 129 return dataEntry; 130 } 131 } 132