Home | History | Annotate | Download | only in editor
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 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.classfile.editor;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.*;
     25 import proguard.classfile.attribute.visitor.AttributeVisitor;
     26 import proguard.classfile.constant.Utf8Constant;
     27 import proguard.classfile.util.*;
     28 import proguard.classfile.visitor.ClassVisitor;
     29 
     30 import java.util.Arrays;
     31 
     32 /**
     33  * This ClassVisitor removes specified interfaces from the classes and class
     34  * signatures that it visits.
     35  *
     36  * @author Eric Lafortune
     37  */
     38 public class InterfaceDeleter
     39 extends      SimplifiedVisitor
     40 implements   ClassVisitor,
     41              AttributeVisitor
     42 {
     43     private static final boolean DEBUG = false;
     44 
     45 
     46     private final boolean[] delete;
     47 
     48 
     49     /**
     50      * Creates a new InterfaceDeleter to remove the specified interfaces.
     51      * @param delete an array that corresponds to the interfaces of a class
     52      *               and that specifies the ones to be removed.
     53      */
     54     public InterfaceDeleter(boolean[] delete)
     55     {
     56         this.delete = delete;
     57     }
     58 
     59 
     60     // Implementations for ClassVisitor.
     61 
     62     public void visitProgramClass(ProgramClass programClass)
     63     {
     64         int[] interfaces      = programClass.u2interfaces;
     65         int   interfacesCount = programClass.u2interfacesCount;
     66 
     67         if (DEBUG)
     68         {
     69             System.out.println("InterfaceDeleter: "+programClass.getName()+" ("+interfacesCount+" interfaces)");
     70         }
     71 
     72         // Copy the interfaces that aren't deleted.
     73         int newInterfacesCount = 0;
     74         for (int index = 0; index < interfacesCount; index++)
     75         {
     76             if (DEBUG)
     77             {
     78                 System.out.println("InterfaceDeleter:   "+(delete[index]?"- ":"+ ")+programClass.getInterfaceName(index));
     79             }
     80 
     81             if (!delete[index])
     82             {
     83                 interfaces[newInterfacesCount++] = interfaces[index];
     84             }
     85         }
     86 
     87         // Update the signature.
     88         if (newInterfacesCount < interfacesCount)
     89         {
     90             programClass.u2interfacesCount = newInterfacesCount;
     91 
     92             programClass.attributesAccept(this);
     93         }
     94     }
     95 
     96 
     97     // Implementations for AttributeVisitor.
     98 
     99     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
    100 
    101 
    102     public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
    103     {
    104         Clazz[] referencedClasses = signatureAttribute.referencedClasses;
    105         if (referencedClasses != null)
    106         {
    107             // Process the generic definitions, superclass, and implemented
    108             // interfaces.
    109             InternalTypeEnumeration internalTypeEnumeration =
    110                 new InternalTypeEnumeration(signatureAttribute.getSignature(clazz));
    111 
    112             // Recompose the signature types in a string buffer.
    113             StringBuffer newSignatureBuffer = new StringBuffer();
    114 
    115             // Also update the array with referenced classes.
    116             int referencedClassIndex    = 0;
    117             int newReferencedClassIndex = 0;
    118 
    119             // Copy the variable type declarations and the super class type.
    120             while (internalTypeEnumeration.hasMoreTypes())
    121             {
    122                 String internalType = internalTypeEnumeration.nextType();
    123 
    124                 // Append the type.
    125                 newSignatureBuffer.append(internalType);
    126 
    127                 // Copy any referenced classes.
    128                 int classCount =
    129                     new DescriptorClassEnumeration(internalType).classCount();
    130 
    131                 for (int counter = 0; counter < classCount; counter++)
    132                 {
    133                     referencedClasses[newReferencedClassIndex++] =
    134                         referencedClasses[referencedClassIndex++];
    135                 }
    136 
    137                 if (DEBUG)
    138                 {
    139                     System.out.println("InterfaceDeleter:   type = " + internalType + " (" + classCount + " referenced classes)");
    140                 }
    141 
    142                 if (ClassUtil.isInternalClassType(internalType))
    143                 {
    144                     break;
    145                 }
    146             }
    147 
    148             // Copy the interface types.
    149             int index = 0;
    150             while (internalTypeEnumeration.hasMoreTypes())
    151             {
    152                 String internalType = internalTypeEnumeration.nextType();
    153 
    154                 int classCount =
    155                     new DescriptorClassEnumeration(internalType).classCount();
    156 
    157                 if (DEBUG)
    158                 {
    159                     System.out.println("InterfaceDeleter:   type " + (delete[index] ? "- " : "+ ") + internalType + " (" + classCount + " referenced classes)");
    160                 }
    161 
    162                 if (!delete[index++])
    163                 {
    164                     // Append the type.
    165                     newSignatureBuffer.append(internalType);
    166 
    167                     // Copy any referenced classes.
    168                     for (int counter = 0; counter < classCount; counter++)
    169                     {
    170                         referencedClasses[newReferencedClassIndex++] =
    171                             referencedClasses[referencedClassIndex++];
    172                     }
    173                 }
    174                 else
    175                 {
    176                     referencedClassIndex += classCount;
    177                 }
    178             }
    179 
    180             // Update the signature.
    181             ((Utf8Constant)((ProgramClass)clazz).constantPool[signatureAttribute.u2signatureIndex]).setString(newSignatureBuffer.toString());
    182 
    183             // Clear the remaining referenced classes.
    184             Arrays.fill(referencedClasses,
    185                         newReferencedClassIndex,
    186                         referencedClassIndex,
    187                         null);
    188         }
    189     }
    190 }
    191