Home | History | Annotate | Download | only in io
      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