1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/* 2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification 3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * of Java bytecode. 4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59f606f95f03a75961498803e24bee6799a7c0885Ying Wang * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) 6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it 8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free 9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option) 10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version. 11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT 13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details. 16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along 18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc., 19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard.obfuscate; 22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.*; 24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.*; 25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.visitor.*; 26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.constant.visitor.AllConstantVisitor; 27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.editor.*; 28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.util.*; 29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.visitor.*; 30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.util.*; 31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.io.*; 33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.util.*; 34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/** 36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This class can perform obfuscation of class pools according to a given 37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * specification. 38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune 40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class Obfuscator 42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{ 43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private final Configuration configuration; 44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Creates a new Obfuscator. 48b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public Obfuscator(Configuration configuration) 50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato this.configuration = configuration; 52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Performs obfuscation of the given program class pool. 57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void execute(ClassPool programClassPool, 59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ClassPool libraryClassPool) throws IOException 60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Check if we have at least some keep commands. 62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (configuration.keep == null && 63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.applyMapping == null && 64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.printMapping == null) 65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato throw new IOException("You have to specify '-keep' options for the obfuscation step."); 67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Clean up any old visitor info. 70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept(new ClassCleaner()); 71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato libraryClassPool.classesAccept(new ClassCleaner()); 72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // If the class member names have to correspond globally, 74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // link all class members in all classes, otherwise 75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // link all non-private methods in all class hierarchies. 76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ClassVisitor memberInfoLinker = 77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.useUniqueClassMemberNames ? 78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato (ClassVisitor)new AllMemberVisitor(new MethodLinker()) : 79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato (ClassVisitor)new BottomClassFilter(new MethodLinker()); 80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept(memberInfoLinker); 82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato libraryClassPool.classesAccept(memberInfoLinker); 83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Create a visitor for marking the seeds. 85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato NameMarker nameMarker = new NameMarker(); 86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ClassPoolVisitor classPoolvisitor = 87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, 88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nameMarker, 89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nameMarker, 90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato false, 91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato false, 92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato true); 93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Mark the seeds. 94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.accept(classPoolvisitor); 95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato libraryClassPool.accept(classPoolvisitor); 96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // All library classes and library class members keep their names. 98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato libraryClassPool.classesAccept(nameMarker); 99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato libraryClassPool.classesAccept(new AllMemberVisitor(nameMarker)); 100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Mark attributes that have to be kept. 1029f606f95f03a75961498803e24bee6799a7c0885Ying Wang AttributeUsageMarker requiredAttributeUsageMarker = 1039f606f95f03a75961498803e24bee6799a7c0885Ying Wang new AttributeUsageMarker(); 104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato AttributeVisitor optionalAttributeUsageMarker = 106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.keepAttributes == null ? null : 107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AttributeNameFilter(new ListParser(new NameParser()).parse(configuration.keepAttributes), 1089f606f95f03a75961498803e24bee6799a7c0885Ying Wang requiredAttributeUsageMarker); 109b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllAttributeVisitor(true, 1129f606f95f03a75961498803e24bee6799a7c0885Ying Wang new RequiredAttributeFilter(requiredAttributeUsageMarker, 113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato optionalAttributeUsageMarker))); 114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Remove the attributes that can be discarded. Note that the attributes 116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // may only be discarded after the seeds have been marked, since the 117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // configuration may rely on annotations. 118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept(new AttributeShrinker()); 119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Apply the mapping, if one has been specified. The mapping can 121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // override the names of library classes and of library class members. 122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (configuration.applyMapping != null) 123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); 125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato MappingReader reader = new MappingReader(configuration.applyMapping); 127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato MappingProcessor keeper = 129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MultiMappingProcessor(new MappingProcessor[] 130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MappingKeeper(programClassPool, warningPrinter), 132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MappingKeeper(libraryClassPool, null), 133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato }); 134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato reader.pump(keeper); 136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Print out a summary of the warnings if necessary. 138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int mappingWarningCount = warningPrinter.getWarningCount(); 139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (mappingWarningCount > 0) 140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println("Warning: there were " + mappingWarningCount + 142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato " kept classes and class members that were remapped anyway."); 143b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" You should adapt your configuration or edit the mapping file."); 144b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 145b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (!configuration.ignoreWarnings) 146b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" If you are sure this remapping won't hurt,"); 148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" you could try your luck using the '-ignorewarnings' option."); 149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato throw new IOException("Please correct the above warnings first."); 150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Come up with new names for all classes. 155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato DictionaryNameFactory classNameFactory = configuration.classObfuscationDictionary != null ? 156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new DictionaryNameFactory(configuration.classObfuscationDictionary, null) : 157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato null; 158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato DictionaryNameFactory packageNameFactory = configuration.packageObfuscationDictionary != null ? 160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new DictionaryNameFactory(configuration.packageObfuscationDictionary, null) : 161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato null; 162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ClassObfuscator(programClassPool, 165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato classNameFactory, 166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato packageNameFactory, 167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.useMixedCaseClassNames, 168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.keepPackageNames, 169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.flattenPackageHierarchy, 170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.repackageClasses, 171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.allowAccessModification)); 172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Come up with new names for all class members. 174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato NameFactory nameFactory = new SimpleNameFactory(); 175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (configuration.obfuscationDictionary != null) 177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nameFactory = new DictionaryNameFactory(configuration.obfuscationDictionary, 179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nameFactory); 180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); 183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Maintain a map of names to avoid [descriptor - new name - old name]. 185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Map descriptorMap = new HashMap(); 186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Do the class member names have to be globally unique? 188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (configuration.useUniqueClassMemberNames) 189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect all member names in all classes. 191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap))); 195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Assign new names to all members in all classes. 197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberObfuscator(configuration.overloadAggressively, 200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nameFactory, 201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap))); 202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Come up with new names for all non-private class members. 206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MultiClassVisitor(new ClassVisitor[] 208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect all private member names in this class and down 210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // the hierarchy. 211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ClassHierarchyTraveler(true, false, false, true, 212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, 214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap)))), 216b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 217b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect all non-private member names anywhere in the hierarchy. 218b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ClassHierarchyTraveler(true, true, true, true, 219b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 220b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, 221b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 222b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap)))), 223b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 224b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Assign new names to all non-private members in this class. 225b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 226b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, 227b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberObfuscator(configuration.overloadAggressively, 228b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nameFactory, 229b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap))), 230b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 231b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Clear the collected names. 232b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MapCleaner(descriptorMap) 233b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato })); 234b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 235b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Come up with new names for all private class members. 236b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 237b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MultiClassVisitor(new ClassVisitor[] 238b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 239b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect all member names in this class. 240b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 241b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 242b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap)), 243b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 244b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect all non-private member names higher up the hierarchy. 245b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ClassHierarchyTraveler(false, true, true, false, 246b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 247b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, 248b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 249b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap)))), 250b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 251b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Assign new names to all private members in this class. 252b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 253b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, 254b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberObfuscator(configuration.overloadAggressively, 255b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nameFactory, 256b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap))), 257b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 258b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Clear the collected names. 259b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MapCleaner(descriptorMap) 260b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato })); 261b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 262b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 263b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Some class members may have ended up with conflicting names. 264b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Come up with new, globally unique names for them. 265b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato NameFactory specialNameFactory = 266b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new SpecialNameFactory(new SimpleNameFactory()); 267b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 268b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect a map of special names to avoid 269b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // [descriptor - new name - old name]. 270b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Map specialDescriptorMap = new HashMap(); 271b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 272b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 273b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 274b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberSpecialNameFilter( 275b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 276b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato specialDescriptorMap)))); 277b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 278b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato libraryClassPool.classesAccept( 279b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 280b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberSpecialNameFilter( 281b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 282b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato specialDescriptorMap)))); 283b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 284b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Replace conflicting non-private member names with special names. 285b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 286b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MultiClassVisitor(new ClassVisitor[] 287b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 288b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect all private member names in this class and down 289b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // the hierarchy. 290b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ClassHierarchyTraveler(true, false, false, true, 291b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 292b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, 293b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 294b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap)))), 295b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 296b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect all non-private member names in this class and 297b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // higher up the hierarchy. 298b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ClassHierarchyTraveler(true, true, true, false, 299b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 300b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, 301b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 302b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap)))), 303b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 304b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Assign new names to all conflicting non-private members 305b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // in this class and higher up the hierarchy. 306b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ClassHierarchyTraveler(true, true, true, false, 307b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 308b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, 309b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameConflictFixer(configuration.overloadAggressively, 310b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap, 311b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato warningPrinter, 312b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberObfuscator(configuration.overloadAggressively, 313b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato specialNameFactory, 314b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato specialDescriptorMap))))), 315b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 316b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Clear the collected names. 317b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MapCleaner(descriptorMap) 318b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato })); 319b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 320b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Replace conflicting private member names with special names. 321b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // This is only possible if those names were kept or mapped. 322b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 323b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MultiClassVisitor(new ClassVisitor[] 324b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 325b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect all member names in this class. 326b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 327b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 328b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap)), 329b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 330b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Collect all non-private member names higher up the hierarchy. 331b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ClassHierarchyTraveler(false, true, true, false, 332b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 333b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, 334b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameCollector(configuration.overloadAggressively, 335b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap)))), 336b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 337b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Assign new names to all conflicting private members in this 338b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // class. 339b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllMemberVisitor( 340b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, 341b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberNameConflictFixer(configuration.overloadAggressively, 342b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptorMap, 343b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato warningPrinter, 344b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MemberObfuscator(configuration.overloadAggressively, 345b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato specialNameFactory, 346b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato specialDescriptorMap)))), 347b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 348b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Clear the collected names. 349b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new MapCleaner(descriptorMap) 350b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato })); 351b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 352b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Print out any warnings about member name conflicts. 353b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int warningCount = warningPrinter.getWarningCount(); 354b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (warningCount > 0) 355b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 356b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println("Warning: there were " + warningCount + 357b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato " conflicting class member name mappings."); 358b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" Your configuration may be inconsistent."); 359b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 360b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (!configuration.ignoreWarnings) 361b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 362b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" If you are sure the conflicts are harmless,"); 363b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" you could try your luck using the '-ignorewarnings' option."); 364b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato throw new IOException("Please correct the above warnings first."); 365b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 366b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 367b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 368b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Print out the mapping, if requested. 369b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (configuration.printMapping != null) 370b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 371b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato PrintStream ps = isFile(configuration.printMapping) ? 372b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printMapping))) : 373b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out; 374b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 375b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Print out items that will be removed. 376b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAcceptAlphabetically(new MappingPrinter(ps)); 377b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 378b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (ps != System.out) 379b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 380b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ps.close(); 381b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 382b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 383b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 384b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Actually apply the new names. 385b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept(new ClassRenamer()); 386b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato libraryClassPool.classesAccept(new ClassRenamer()); 387b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 388b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Update all references to these new names. 389b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept(new ClassReferenceFixer(false)); 390b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato libraryClassPool.classesAccept(new ClassReferenceFixer(false)); 391b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept(new MemberReferenceFixer()); 392b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 393b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Make package visible elements public or protected, if obfuscated 394b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // classes are being repackaged aggressively. 395b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (configuration.repackageClasses != null && 396b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato configuration.allowAccessModification) 397b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 398b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept( 399b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AllConstantVisitor( 400b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new AccessFixer())); 401b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 402b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 403b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Rename the source file attributes, if requested. 404b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (configuration.newSourceFileAttribute != null) 405b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 406b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato programClassPool.classesAccept(new SourceFileRenamer(configuration.newSourceFileAttribute)); 407b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 408b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 4099f606f95f03a75961498803e24bee6799a7c0885Ying Wang // Mark NameAndType constant pool entries that have to be kept 4109f606f95f03a75961498803e24bee6799a7c0885Ying Wang // and remove the other ones. 4119f606f95f03a75961498803e24bee6799a7c0885Ying Wang programClassPool.classesAccept(new NameAndTypeUsageMarker()); 4129f606f95f03a75961498803e24bee6799a7c0885Ying Wang programClassPool.classesAccept(new NameAndTypeShrinker()); 4139f606f95f03a75961498803e24bee6799a7c0885Ying Wang 4149f606f95f03a75961498803e24bee6799a7c0885Ying Wang // Mark Utf8 constant pool entries that have to be kept 4159f606f95f03a75961498803e24bee6799a7c0885Ying Wang // and remove the other ones. 4169f606f95f03a75961498803e24bee6799a7c0885Ying Wang programClassPool.classesAccept(new Utf8UsageMarker()); 4179f606f95f03a75961498803e24bee6799a7c0885Ying Wang programClassPool.classesAccept(new Utf8Shrinker()); 418b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 419b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 420b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 421b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 422b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns whether the given file is actually a file, or just a placeholder 423b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * for the standard output. 424b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 425b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private boolean isFile(File file) 426b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 427b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return file.getPath().length() > 0; 428b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 429b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato} 430