1 21 package proguard.obfuscate; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.*; 26 import proguard.classfile.constant.*; 27 import proguard.classfile.constant.visitor.ConstantVisitor; 28 import proguard.classfile.util.*; 29 import proguard.classfile.visitor.*; 30 31 import java.util.*; 32 33 42 public class ClassObfuscator 43 extends SimplifiedVisitor 44 implements ClassVisitor, 45 AttributeVisitor, 46 InnerClassesInfoVisitor, 47 ConstantVisitor 48 { 49 private boolean useMixedCaseClassNames; 50 private String flattenPackageHierarchy; 51 private String repackageClasses; 52 private boolean allowAccessModification; 53 54 private final Set classNamesToAvoid = new HashSet(); 55 56 private final Map packagePrefixMap = new HashMap(); 58 59 private final Map packagePrefixPackageNameFactoryMap = new HashMap(); 61 62 private final Map packagePrefixClassNameFactoryMap = new HashMap(); 64 65 private String newClassName; 68 69 70 83 public ClassObfuscator(ClassPool programClassPool, 84 boolean useMixedCaseClassNames, 85 String flattenPackageHierarchy, 86 String repackageClasses, 87 boolean allowAccessModification) 88 { 89 if (flattenPackageHierarchy != null && 91 flattenPackageHierarchy.length() > 0) 92 { 93 flattenPackageHierarchy += ClassConstants.INTERNAL_PACKAGE_SEPARATOR; 94 } 95 96 if (repackageClasses != null && 98 repackageClasses.length() > 0) 99 { 100 repackageClasses += ClassConstants.INTERNAL_PACKAGE_SEPARATOR; 101 } 102 103 this.useMixedCaseClassNames = useMixedCaseClassNames; 104 this.flattenPackageHierarchy = flattenPackageHierarchy; 105 this.repackageClasses = repackageClasses; 106 this.allowAccessModification = allowAccessModification; 107 108 packagePrefixMap.put("", ""); 110 111 programClassPool.classesAccept(new MyKeepCollector()); 113 } 114 115 116 118 public void visitProgramClass(ProgramClass programClass) 119 { 120 newClassName = newClassName(programClass); 122 if (newClassName == null) 123 { 124 programClass.attributesAccept(this); 128 129 String newPackagePrefix = newClassName != null ? 133 newClassName + ClassConstants.INNER_CLASS_SEPARATOR : 134 newPackagePrefix(ClassUtil.internalPackagePrefix(programClass.getName())); 135 136 newClassName = generateUniqueClassName(newPackagePrefix); 138 139 setNewClassName(programClass, newClassName); 140 } 141 } 142 143 144 146 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 147 148 149 public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) 150 { 151 innerClassesAttribute.innerClassEntriesAccept(clazz, this); 153 } 154 155 156 public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) 157 { 158 enclosingMethodAttribute.referencedClassAccept(this); 160 } 161 162 163 165 public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) 166 { 167 int innerClassIndex = innerClassesInfo.u2innerClassIndex; 169 int outerClassIndex = innerClassesInfo.u2outerClassIndex; 170 if (innerClassIndex != 0 && 171 outerClassIndex != 0 && 172 clazz.getClassName(innerClassIndex).equals(clazz.getName())) 173 { 174 clazz.constantPoolEntryAccept(outerClassIndex, this); 175 } 176 } 177 178 179 181 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 182 { 183 classConstant.referencedClassAccept(this); 185 } 186 187 188 192 private class MyKeepCollector implements ClassVisitor 193 { 194 public void visitProgramClass(ProgramClass programClass) 195 { 196 String newClassName = newClassName(programClass); 198 if (newClassName != null) 199 { 200 classNamesToAvoid.add(newClassName); 202 203 if (repackageClasses == null || 205 !allowAccessModification) 206 { 207 String className = programClass.getName(); 208 209 mapPackageName(className, 213 newClassName, 214 repackageClasses == null && 215 flattenPackageHierarchy == null); 216 } 217 } 218 } 219 220 221 public void visitLibraryClass(LibraryClass libraryClass) 222 { 223 } 224 225 226 230 private void mapPackageName(String className, 231 String newClassName, 232 boolean recursively) 233 { 234 String packagePrefix = ClassUtil.internalPackagePrefix(className); 235 String newPackagePrefix = ClassUtil.internalPackagePrefix(newClassName); 236 237 do 240 { 241 packagePrefixMap.put(packagePrefix, newPackagePrefix); 242 243 if (!recursively) 244 { 245 break; 246 } 247 248 packagePrefix = ClassUtil.internalPackagePrefix(packagePrefix); 249 newPackagePrefix = ClassUtil.internalPackagePrefix(newPackagePrefix); 250 } 251 while (packagePrefix.length() > 0 && 252 newPackagePrefix.length() > 0); 253 } 254 } 255 256 257 259 262 private String newPackagePrefix(String packagePrefix) 263 { 264 String newPackagePrefix = (String )packagePrefixMap.get(packagePrefix); 266 if (newPackagePrefix == null) 267 { 268 if (repackageClasses != null) 270 { 271 return repackageClasses; 272 } 273 274 String newSuperPackagePrefix = flattenPackageHierarchy != null ? 277 flattenPackageHierarchy : 278 newPackagePrefix(ClassUtil.internalPackagePrefix(packagePrefix)); 279 280 newPackagePrefix = generateUniquePackagePrefix(newSuperPackagePrefix); 282 283 packagePrefixMap.put(packagePrefix, newPackagePrefix); 285 } 286 287 return newPackagePrefix; 288 } 289 290 291 294 private String generateUniquePackagePrefix(String newSuperPackagePrefix) 295 { 296 NameFactory packageNameFactory = 298 (NameFactory)packagePrefixPackageNameFactoryMap.get(newSuperPackagePrefix); 299 if (packageNameFactory == null) 300 { 301 packageNameFactory = new SimpleNameFactory(useMixedCaseClassNames); 304 packagePrefixPackageNameFactoryMap.put(newSuperPackagePrefix, 305 packageNameFactory); 306 } 307 308 String newPackagePrefix; 310 do 311 { 312 newPackagePrefix = newSuperPackagePrefix + 314 packageNameFactory.nextName() + 315 ClassConstants.INTERNAL_PACKAGE_SEPARATOR; 316 } 317 while (packagePrefixMap.containsValue(newPackagePrefix)); 318 319 return newPackagePrefix; 320 } 321 322 323 326 private String generateUniqueClassName(String newPackagePrefix) 327 { 328 NameFactory classNameFactory = 330 (NameFactory)packagePrefixClassNameFactoryMap.get(newPackagePrefix); 331 if (classNameFactory == null) 332 { 333 classNameFactory = new SimpleNameFactory(useMixedCaseClassNames); 336 packagePrefixClassNameFactoryMap.put(newPackagePrefix, 337 classNameFactory); 338 } 339 340 String newClassName; 342 do 343 { 344 newClassName = newPackagePrefix + 346 classNameFactory.nextName(); 347 } 348 while (classNamesToAvoid.contains(newClassName)); 349 350 return newClassName; 351 } 352 353 354 359 static void setNewClassName(Clazz clazz, String name) 360 { 361 clazz.setVisitorInfo(name); 362 } 363 364 365 371 static String newClassName(Clazz clazz) 372 { 373 Object visitorInfo = clazz.getVisitorInfo(); 374 375 return visitorInfo instanceof String ? 376 (String )visitorInfo : 377 null; 378 } 379 } 380 | Popular Tags |