1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric@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 */ 21package proguard.classfile.editor; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.*; 25import proguard.classfile.attribute.visitor.AttributeVisitor; 26import proguard.classfile.constant.Utf8Constant; 27import proguard.classfile.util.*; 28import proguard.classfile.visitor.ClassVisitor; 29 30import 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 */ 38public class InterfaceDeleter 39extends SimplifiedVisitor 40implements 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