1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2013 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.util; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.Attribute; 25import proguard.classfile.attribute.visitor.AttributeVisitor; 26import proguard.classfile.constant.*; 27import proguard.classfile.constant.visitor.ConstantVisitor; 28import proguard.classfile.visitor.ClassVisitor; 29 30/** 31 * This ClassVisitor shares strings in the class files that it visits. 32 * 33 * @author Eric Lafortune 34 */ 35public class StringSharer 36extends SimplifiedVisitor 37implements ClassVisitor, 38 ConstantVisitor, 39 AttributeVisitor 40{ 41 // A fields acting as an argument for the visitor methods. 42 private String name; 43 private String type; 44 45 46 // Implementations for ClassVisitor. 47 48 public void visitProgramClass(ProgramClass programClass) 49 { 50 // Replace name strings in the constant pool by shared strings. 51 programClass.constantPoolEntriesAccept(this); 52 53 // Replace attribute name strings in the constant pool by internalized 54 // strings. 55 programClass.attributesAccept(this); 56 } 57 58 59 public void visitLibraryClass(LibraryClass libraryClass) 60 { 61 // Replace the super class name string by the shared name string. 62 Clazz superClass = libraryClass.superClass; 63 if (superClass != null) 64 { 65 libraryClass.superClassName = superClass.getName(); 66 } 67 68 // Replace the interface name strings by the shared name strings. 69 if (libraryClass.interfaceNames != null) 70 { 71 String[] interfaceNames = libraryClass.interfaceNames; 72 Clazz[] interfaceClasses = new Clazz[interfaceNames.length]; 73 74 for (int index = 0; index < interfaceNames.length; index++) 75 { 76 // Keep a reference to the interface class. 77 Clazz interfaceClass = interfaceClasses[index]; 78 if (interfaceClass != null) 79 { 80 interfaceNames[index] = interfaceClass.getName(); 81 } 82 } 83 } 84 } 85 86 87 // Implementations for ConstantVisitor. 88 89 90 public void visitAnyConstant(Clazz clazz, Constant constant) {} 91 92 93 public void visitStringConstant(Clazz clazz, StringConstant stringConstant) 94 { 95 Member referencedMember = stringConstant.referencedMember; 96 if (referencedMember != null) 97 { 98 Clazz referencedClass = stringConstant.referencedClass; 99 100 // Put the actual class member's name in the class pool. 101 name = referencedMember.getName(referencedClass); 102 clazz.constantPoolEntryAccept(stringConstant.u2stringIndex, this); 103 } 104 } 105 106 107 public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) 108 { 109 Member referencedMember = refConstant.referencedMember; 110 if (referencedMember != null) 111 { 112 Clazz referencedClass = refConstant.referencedClass; 113 114 // Put the actual class member's name and type strings in the class 115 // pool. 116 name = referencedMember.getName(referencedClass); 117 type = referencedMember.getDescriptor(referencedClass); 118 clazz.constantPoolEntryAccept(refConstant.u2nameAndTypeIndex, this); 119 } 120 } 121 122 123 public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) 124 { 125 if (name != null) 126 { 127 // Put the actual class member's name and type strings in the class 128 // pool. 129 clazz.constantPoolEntryAccept(nameAndTypeConstant.u2nameIndex, this); 130 name = type; 131 clazz.constantPoolEntryAccept(nameAndTypeConstant.u2descriptorIndex, this); 132 } 133 } 134 135 136 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 137 { 138 Clazz referencedClass = classConstant.referencedClass; 139 if (referencedClass != null) 140 { 141 // Put the actual class's name string in the class pool. 142 name = referencedClass.getName(); 143 clazz.constantPoolEntryAccept(classConstant.u2nameIndex, this); 144 } 145 } 146 147 148 public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) 149 { 150 // Do we have a new string to put into this constant? 151 if (name != null) 152 { 153 // Replace the string, if it's actually the same. 154 if (name.equals(utf8Constant.getString())) 155 { 156 utf8Constant.setString(name); 157 } 158 159 name = null; 160 } 161 } 162 163 164 // Implementations for AttributeVisitor. 165 166 public void visitAnyAttribute(Clazz clazz, Attribute attribute) 167 { 168 // Put the internalized attribute's name string in the class pool. 169 name = attribute.getAttributeName(clazz).intern(); 170 clazz.constantPoolEntryAccept(attribute.u2attributeNameIndex, this); 171 } 172} 173