1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 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.constant.*; 25import proguard.classfile.constant.visitor.ConstantVisitor; 26import proguard.classfile.util.SimplifiedVisitor; 27 28 29/** 30 * This class is a <code>Comparable</code> wrapper of <code>Constant</code> 31 * objects. It can store an index, in order to identify the constant pool 32 * entry after it has been sorted. The comparison is primarily based on the 33 * types of the constant pool entries, and secondarily on the contents of 34 * the constant pool entries. 35 * 36 * @author Eric Lafortune 37 */ 38class ComparableConstant 39extends SimplifiedVisitor 40implements Comparable, ConstantVisitor 41{ 42 private static final int[] PRIORITIES = new int[13]; 43 static 44 { 45 PRIORITIES[ClassConstants.CONSTANT_Integer] = 0; // Possibly byte index (ldc). 46 PRIORITIES[ClassConstants.CONSTANT_Float] = 1; 47 PRIORITIES[ClassConstants.CONSTANT_String] = 2; 48 PRIORITIES[ClassConstants.CONSTANT_Class] = 3; 49 PRIORITIES[ClassConstants.CONSTANT_Long] = 4; // Always wide index (ldc2_w). 50 PRIORITIES[ClassConstants.CONSTANT_Double] = 5; 51 PRIORITIES[ClassConstants.CONSTANT_Fieldref] = 6; // Always wide index. 52 PRIORITIES[ClassConstants.CONSTANT_Methodref] = 7; 53 PRIORITIES[ClassConstants.CONSTANT_InterfaceMethodref] = 8; 54 PRIORITIES[ClassConstants.CONSTANT_NameAndType] = 9; 55 PRIORITIES[ClassConstants.CONSTANT_Utf8] = 10; 56 } 57 58 private final Clazz clazz; 59 private final int thisIndex; 60 private final Constant thisConstant; 61 62 private Constant otherConstant; 63 private int result; 64 65 66 public ComparableConstant(Clazz clazz, int index, Constant constant) 67 { 68 this.clazz = clazz; 69 this.thisIndex = index; 70 this.thisConstant = constant; 71 } 72 73 74 public int getIndex() 75 { 76 return thisIndex; 77 } 78 79 80 public Constant getConstant() 81 { 82 return thisConstant; 83 } 84 85 86 // Implementations for Comparable. 87 88 public int compareTo(Object other) 89 { 90 ComparableConstant otherComparableConstant = (ComparableConstant)other; 91 92 otherConstant = otherComparableConstant.thisConstant; 93 94 // Compare based on the original indices, if the actual constant pool 95 // entries are the same. 96 if (thisConstant == otherConstant) 97 { 98 int otherIndex = otherComparableConstant.thisIndex; 99 100 return thisIndex < otherIndex ? -1 : 101 thisIndex == otherIndex ? 0 : 102 1; 103 } 104 105 // Compare based on the tags, if they are different. 106 int thisTag = thisConstant.getTag(); 107 int otherTag = otherConstant.getTag(); 108 109 if (thisTag != otherTag) 110 { 111 return PRIORITIES[thisTag] < PRIORITIES[otherTag] ? -1 : 1; 112 } 113 114 // Otherwise compare based on the contents of the Constant objects. 115 thisConstant.accept(clazz, this); 116 117 return result; 118 } 119 120 121 // Implementations for ConstantVisitor. 122 123 public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) 124 { 125 // In JDK 1.4, we can use Integer.compare(a,b). 126 result = new Integer(integerConstant.getValue()).compareTo(new Integer(((IntegerConstant)otherConstant).getValue())); 127 } 128 129 public void visitLongConstant(Clazz clazz, LongConstant longConstant) 130 { 131 // In JDK 1.4, we can use Long.compare(a,b). 132 result = new Long(longConstant.getValue()).compareTo(new Long(((LongConstant)otherConstant).getValue())); 133 } 134 135 public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) 136 { 137 // In JDK 1.4, we can use Float.compare(a,b). 138 result = new Float(floatConstant.getValue()).compareTo(new Float(((FloatConstant)otherConstant).getValue())); 139 } 140 141 public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) 142 { 143 // In JDK 1.4, we can use Double.compare(a,b). 144 result = new Double(doubleConstant.getValue()).compareTo(new Double(((DoubleConstant)otherConstant).getValue())); 145 } 146 147 public void visitStringConstant(Clazz clazz, StringConstant stringConstant) 148 { 149 result = stringConstant.getString(clazz).compareTo(((StringConstant)otherConstant).getString(clazz)); 150 } 151 152 public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) 153 { 154 result = utf8Constant.getString().compareTo(((Utf8Constant)otherConstant).getString()); 155 } 156 157 public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) 158 { 159 RefConstant otherRefConstant = (RefConstant)otherConstant; 160 result = (refConstant.getClassName(clazz) + ' ' + 161 refConstant.getName(clazz) + ' ' + 162 refConstant.getType(clazz)) 163 .compareTo 164 (otherRefConstant.getClassName(clazz) + ' ' + 165 otherRefConstant.getName(clazz) + ' ' + 166 otherRefConstant.getType(clazz)); 167 } 168 169 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 170 { 171 result = classConstant.getName(clazz).compareTo(((ClassConstant)otherConstant).getName(clazz)); 172 } 173 174 public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) 175 { 176 NameAndTypeConstant otherNameAndTypeConstant = (NameAndTypeConstant)otherConstant; 177 result = (nameAndTypeConstant.getName(clazz) + ' ' + 178 nameAndTypeConstant.getType(clazz)) 179 .compareTo 180 (otherNameAndTypeConstant.getName(clazz) + ' ' + 181 otherNameAndTypeConstant.getType(clazz)); 182 } 183 184 185 // Implementations for Object. 186 187 public boolean equals(Object other) 188 { 189 return other != null && 190 this.getClass().equals(other.getClass()) && 191 this.getConstant().getClass().equals(((ComparableConstant)other).getConstant().getClass()) && 192 this.compareTo(other) == 0; 193 } 194 195 196 public int hashCode() 197 { 198 return this.getClass().hashCode(); 199 } 200} 201