[proguard] 01/02: Imported Upstream version 3.2
Emmanuel Bourg
ebourg-guest at moszumanska.debian.org
Thu Apr 10 09:00:30 UTC 2014
This is an automated email from the git hooks/post-receive script.
ebourg-guest pushed a commit to annotated tag debian/3.2-1
in repository proguard.
commit 7851c476e9fca2d97f1b0a8d85c45a92687efc8f
Author: Sam Clegg <samo at debian.org>
Date: Thu Apr 10 10:41:50 2014 +0200
Imported Upstream version 3.2
---
README | 54 +
docs/FAQ.html | 191 ++
docs/GPL.html | 406 ++++
docs/GPL_exception.html | 44 +
docs/acknowledgements.html | 58 +
docs/alternatives.html | 433 +++++
docs/checkmark.gif | Bin 0 -> 63 bytes
docs/downloads.html | 221 +++
docs/drop1.gif | Bin 0 -> 803 bytes
docs/drop2.gif | Bin 0 -> 620 bytes
docs/drop3.gif | Bin 0 -> 175 bytes
docs/feedback.html | 106 +
docs/index.html | 54 +
docs/license.html | 46 +
docs/luciadlogo.png | Bin 0 -> 2356 bytes
docs/main.html | 79 +
docs/manual/ant.html | 417 ++++
docs/manual/examples.html | 684 +++++++
docs/manual/gui.html | 418 ++++
docs/manual/index.html | 39 +
docs/manual/introduction.html | 116 ++
docs/manual/limitations.html | 95 +
docs/manual/refcard.html | 305 +++
docs/manual/retrace/examples.html | 336 ++++
docs/manual/retrace/index.html | 25 +
docs/manual/retrace/introduction.html | 66 +
docs/manual/retrace/usage.html | 81 +
docs/manual/sections.html | 136 ++
docs/manual/style.css | 81 +
docs/manual/troubleshooting.html | 269 +++
docs/manual/usage.html | 849 +++++++++
docs/manual/wtk.html | 58 +
docs/quality.html | 37 +
docs/results.html | 134 ++
docs/screenshot_console.gif | Bin 0 -> 13199 bytes
docs/screenshot_console_small.gif | Bin 0 -> 87201 bytes
docs/screenshot_gui1.gif | Bin 0 -> 38674 bytes
docs/screenshot_gui2.gif | Bin 0 -> 30691 bytes
docs/screenshot_gui3.gif | Bin 0 -> 29364 bytes
docs/screenshot_gui4.gif | Bin 0 -> 30409 bytes
docs/screenshot_gui5.gif | Bin 0 -> 28754 bytes
docs/screenshot_gui6.gif | Bin 0 -> 23939 bytes
docs/screenshot_gui7.gif | Bin 0 -> 29404 bytes
docs/screenshot_gui8.gif | Bin 0 -> 26259 bytes
docs/screenshots.html | 56 +
docs/screenshots_gui_small.gif | Bin 0 -> 90544 bytes
docs/sections.html | 121 ++
docs/sflogo.png | Bin 0 -> 1299 bytes
docs/steel.gif | Bin 0 -> 2759 bytes
docs/style.css | 128 ++
docs/testimonials.html | 98 +
docs/title.gif | Bin 0 -> 2613 bytes
docs/title.html | 19 +
docs/vtitle.gif | Bin 0 -> 22053 bytes
examples/ant/applets.xml | 74 +
examples/ant/applications1.xml | 15 +
examples/ant/applications2.xml | 66 +
examples/ant/applications3.xml | 85 +
examples/ant/library.xml | 95 +
examples/ant/midlets.xml | 44 +
examples/ant/proguard.xml | 62 +
examples/ant/servlets.xml | 74 +
examples/applets.pro | 57 +
examples/applications.pro | 63 +
examples/dictionaries/compact.txt | 19 +
examples/dictionaries/keywords.txt | 58 +
examples/dictionaries/shakespeare.txt | 23 +
examples/library.pro | 74 +
examples/midlets.pro | 53 +
examples/proguard.pro | 55 +
examples/proguardall.pro | 67 +
examples/proguardgui.pro | 48 +
examples/retrace.pro | 41 +
examples/servlets.pro | 58 +
src/proguard/ArgumentWordReader.java | 83 +
src/proguard/ClassMemberSpecification.java | 103 +
src/proguard/ClassPath.java | 94 +
src/proguard/ClassPathEntry.java | 157 ++
src/proguard/ClassSpecification.java | 224 +++
src/proguard/ClassSpecificationVisitorFactory.java | 358 ++++
src/proguard/Configuration.java | 202 ++
src/proguard/ConfigurationConstants.java | 94 +
src/proguard/ConfigurationParser.java | 919 +++++++++
src/proguard/ConfigurationWriter.java | 418 ++++
src/proguard/DataEntryReaderFactory.java | 138 ++
src/proguard/DataEntryWriterFactory.java | 152 ++
src/proguard/FileWordReader.java | 87 +
src/proguard/ParseException.java | 51 +
src/proguard/ProGuard.java | 936 +++++++++
src/proguard/SubclassedClassFileFilter.java | 63 +
src/proguard/WordReader.java | 271 +++
.../ant/ClassMemberSpecificationElement.java | 201 ++
src/proguard/ant/ClassPathElement.java | 173 ++
src/proguard/ant/ClassSpecificationElement.java | 230 +++
src/proguard/ant/ConfigurationElement.java | 59 +
src/proguard/ant/ConfigurationTask.java | 290 +++
src/proguard/ant/KeepAttributeElement.java | 70 +
src/proguard/ant/ProGuardTask.java | 216 +++
src/proguard/ant/package.html | 3 +
src/proguard/ant/task.properties | 2 +
src/proguard/classfile/ClassConstants.java | 203 ++
src/proguard/classfile/ClassCpInfo.java | 123 ++
src/proguard/classfile/ClassFile.java | 188 ++
src/proguard/classfile/ClassPool.java | 151 ++
src/proguard/classfile/CpInfo.java | 166 ++
src/proguard/classfile/DoubleCpInfo.java | 97 +
src/proguard/classfile/FieldInfo.java | 33 +
src/proguard/classfile/FieldrefCpInfo.java | 69 +
src/proguard/classfile/FloatCpInfo.java | 92 +
src/proguard/classfile/IntegerCpInfo.java | 92 +
.../classfile/InterfaceMethodrefCpInfo.java | 69 +
src/proguard/classfile/LibraryClassFile.java | 586 ++++++
src/proguard/classfile/LibraryFieldInfo.java | 60 +
src/proguard/classfile/LibraryMemberInfo.java | 129 ++
src/proguard/classfile/LibraryMethodInfo.java | 60 +
src/proguard/classfile/LongCpInfo.java | 96 +
src/proguard/classfile/MemberInfo.java | 53 +
src/proguard/classfile/MethodInfo.java | 33 +
src/proguard/classfile/MethodrefCpInfo.java | 69 +
src/proguard/classfile/NameAndTypeCpInfo.java | 162 ++
src/proguard/classfile/ProgramClassFile.java | 537 ++++++
src/proguard/classfile/ProgramFieldInfo.java | 70 +
src/proguard/classfile/ProgramMemberInfo.java | 208 ++
src/proguard/classfile/ProgramMethodInfo.java | 70 +
src/proguard/classfile/RefCpInfo.java | 146 ++
src/proguard/classfile/StringCpInfo.java | 108 ++
src/proguard/classfile/Utf8CpInfo.java | 215 +++
src/proguard/classfile/VisitorAccepter.java | 48 +
.../classfile/attribute/AllAttrInfoVisitor.java | 68 +
src/proguard/classfile/attribute/AttrInfo.java | 184 ++
.../classfile/attribute/AttrInfoVisitor.java | 59 +
src/proguard/classfile/attribute/CodeAttrInfo.java | 190 ++
.../classfile/attribute/ConstantValueAttrInfo.java | 70 +
.../classfile/attribute/DeprecatedAttrInfo.java | 65 +
.../attribute/EnclosingMethodAttrInfo.java | 135 ++
.../classfile/attribute/ExceptionInfo.java | 91 +
.../classfile/attribute/ExceptionInfoVisitor.java | 36 +
.../classfile/attribute/ExceptionsAttrInfo.java | 99 +
.../classfile/attribute/InnerClassesAttrInfo.java | 104 +
.../classfile/attribute/InnerClassesInfo.java | 112 ++
.../attribute/InnerClassesInfoVisitor.java | 38 +
.../classfile/attribute/LibraryAttrInfo.java | 45 +
.../classfile/attribute/LineNumberInfo.java | 64 +
.../attribute/LineNumberTableAttrInfo.java | 116 ++
.../classfile/attribute/LocalVariableInfo.java | 112 ++
.../attribute/LocalVariableInfoVisitor.java | 38 +
.../attribute/LocalVariableTableAttrInfo.java | 102 +
.../classfile/attribute/LocalVariableTypeInfo.java | 113 ++
.../attribute/LocalVariableTypeInfoVisitor.java | 38 +
.../attribute/LocalVariableTypeTableAttrInfo.java | 102 +
.../classfile/attribute/MultiAttrInfoVisitor.java | 234 +++
.../classfile/attribute/SignatureAttrInfo.java | 75 +
.../classfile/attribute/SourceDirAttrInfo.java | 69 +
.../classfile/attribute/SourceFileAttrInfo.java | 70 +
.../classfile/attribute/SyntheticAttrInfo.java | 65 +
.../classfile/attribute/UnknownAttrInfo.java | 70 +
.../classfile/attribute/annotation/Annotation.java | 134 ++
.../annotation/AnnotationDefaultAttrInfo.java | 77 +
.../annotation/AnnotationElementValue.java | 76 +
.../attribute/annotation/AnnotationVisitor.java | 40 +
.../attribute/annotation/ArrayElementValue.java | 95 +
.../attribute/annotation/ClassElementValue.java | 75 +
.../attribute/annotation/ConstantElementValue.java | 67 +
.../attribute/annotation/ElementValue.java | 147 ++
.../attribute/annotation/ElementValueVisitor.java | 40 +
.../annotation/EnumConstantElementValue.java | 78 +
.../annotation/RuntimeAnnotationsAttrInfo.java | 92 +
.../RuntimeInvisibleAnnotationsAttrInfo.java | 44 +
...ntimeInvisibleParameterAnnotationsAttrInfo.java | 44 +
.../RuntimeParameterAnnotationsAttrInfo.java | 120 ++
.../RuntimeVisibleAnnotationsAttrInfo.java | 44 +
...RuntimeVisibleParameterAnnotationsAttrInfo.java | 44 +
.../classfile/attribute/annotation/package.html | 4 +
src/proguard/classfile/attribute/package.html | 3 +
.../classfile/editor/CodeAttrInfoEditor.java | 667 +++++++
.../editor/CodeAttrInfoEditorResetter.java | 76 +
.../classfile/editor/ComparableCpInfo.java | 177 ++
.../classfile/editor/ConstantPoolEditor.java | 531 ++++++
.../classfile/editor/ConstantPoolRemapper.java | 592 ++++++
.../classfile/editor/ConstantPoolSorter.java | 128 ++
.../classfile/editor/StackSizeUpdater.java | 357 ++++
src/proguard/classfile/editor/package.html | 3 +
.../instruction/AllInstructionVisitor.java | 71 +
.../classfile/instruction/BranchInstruction.java | 133 ++
.../classfile/instruction/CpInstruction.java | 267 +++
.../classfile/instruction/Instruction.java | 866 +++++++++
.../instruction/InstructionConstants.java | 449 +++++
.../classfile/instruction/InstructionFactory.java | 310 +++
.../classfile/instruction/InstructionVisitor.java | 41 +
.../instruction/LookUpSwitchInstruction.java | 142 ++
.../instruction/MultiInstructionVisitor.java | 138 ++
.../classfile/instruction/SimpleInstruction.java | 182 ++
.../instruction/TableSwitchInstruction.java | 145 ++
.../classfile/instruction/VariableInstruction.java | 224 +++
src/proguard/classfile/instruction/package.html | 9 +
src/proguard/classfile/package.html | 15 +
src/proguard/classfile/util/AccessUtil.java | 99 +
.../ClassFileClassForNameReferenceInitializer.java | 260 +++
.../util/ClassFileHierarchyInitializer.java | 282 +++
.../util/ClassFileReferenceInitializer.java | 523 +++++
.../classfile/util/ClassForNameChecker.java | 225 +++
.../classfile/util/ClassNewInstanceChecker.java | 97 +
src/proguard/classfile/util/ClassUtil.java | 935 +++++++++
.../classfile/util/DescriptorClassEnumeration.java | 165 ++
.../classfile/util/ExternalTypeEnumeration.java | 106 +
.../classfile/util/InternalTypeEnumeration.java | 108 ++
src/proguard/classfile/util/MemberFinder.java | 236 +++
src/proguard/classfile/util/package.html | 3 +
.../classfile/visitor/AllClassFileVisitor.java | 47 +
.../classfile/visitor/AllCpInfoVisitor.java | 52 +
.../classfile/visitor/AllFieldVisitor.java | 55 +
.../classfile/visitor/AllMemberInfoVisitor.java | 57 +
.../classfile/visitor/AllMethodVisitor.java | 55 +
.../classfile/visitor/BottomClassFileFilter.java | 69 +
.../classfile/visitor/ClassFileAccessFilter.java | 88 +
.../classfile/visitor/ClassFileCleaner.java | 368 ++++
.../visitor/ClassFileHierarchyTraveler.java | 91 +
.../visitor/ClassFileMemberInfoVisitor.java | 88 +
.../classfile/visitor/ClassFileNameFilter.java | 81 +
.../classfile/visitor/ClassFilePrinter.java | 677 +++++++
.../classfile/visitor/ClassFileVisitor.java | 36 +
.../classfile/visitor/ClassPoolFiller.java | 69 +
.../classfile/visitor/ClassPoolVisitor.java | 37 +
.../visitor/ConcreteClassFileDownTraveler.java | 100 +
src/proguard/classfile/visitor/CpInfoVisitor.java | 45 +
.../classfile/visitor/LibraryClassFileFilter.java | 60 +
.../classfile/visitor/LibraryMemberInfoFilter.java | 73 +
.../classfile/visitor/LineNumberInfoVisitor.java | 38 +
.../classfile/visitor/MemberInfoAccessFilter.java | 122 ++
.../visitor/MemberInfoDescriptorFilter.java | 99 +
.../classfile/visitor/MemberInfoNameFilter.java | 99 +
.../classfile/visitor/MemberInfoVisitor.java | 40 +
.../classfile/visitor/MultiClassFileVisitor.java | 97 +
.../classfile/visitor/MultiClassPoolVisitor.java | 88 +
.../classfile/visitor/MultiMemberInfoVisitor.java | 113 ++
.../classfile/visitor/NamedClassFileVisitor.java | 55 +
.../classfile/visitor/NamedFieldVisitor.java | 59 +
.../classfile/visitor/NamedMethodVisitor.java | 59 +
.../classfile/visitor/ProgramClassFileFilter.java | 60 +
.../classfile/visitor/ProgramMemberInfoFilter.java | 73 +
.../visitor/ReferencedClassFileVisitor.java | 110 ++
.../classfile/visitor/SimpleClassFilePrinter.java | 169 ++
.../visitor/VariableClassFileVisitor.java | 78 +
.../visitor/VariableMemberInfoVisitor.java | 96 +
src/proguard/classfile/visitor/package.html | 40 +
.../gui/ClassMemberSpecificationDialog.java | 416 ++++
.../gui/ClassMemberSpecificationsPanel.java | 268 +++
src/proguard/gui/ClassPathPanel.java | 415 ++++
src/proguard/gui/ClassSpecificationDialog.java | 414 ++++
src/proguard/gui/ClassSpecificationsPanel.java | 191 ++
src/proguard/gui/ExtensionFileFilter.java | 78 +
src/proguard/gui/FilterDialog.java | 296 +++
src/proguard/gui/GUIResources.java | 56 +
src/proguard/gui/GUIResources.properties | 255 +++
src/proguard/gui/ListPanel.java | 317 +++
src/proguard/gui/MessageDialogRunnable.java | 83 +
src/proguard/gui/ProGuardGUI.java | 1420 ++++++++++++++
src/proguard/gui/ProGuardRunnable.java | 148 ++
src/proguard/gui/ReTraceRunnable.java | 149 ++
src/proguard/gui/SwingUtil.java | 80 +
src/proguard/gui/TabbedPane.java | 229 +++
src/proguard/gui/TextAreaOutputStream.java | 74 +
src/proguard/gui/arrow.gif | Bin 0 -> 112 bytes
src/proguard/gui/boilerplate.pro | 277 +++
src/proguard/gui/default.pro | 193 ++
src/proguard/gui/package.html | 3 +
src/proguard/gui/splash/BufferedSprite.java | 85 +
src/proguard/gui/splash/CircleSprite.java | 80 +
src/proguard/gui/splash/ClipSprite.java | 85 +
src/proguard/gui/splash/CompositeSprite.java | 56 +
src/proguard/gui/splash/ConstantColor.java | 51 +
src/proguard/gui/splash/ConstantDouble.java | 49 +
src/proguard/gui/splash/ConstantFont.java | 46 +
src/proguard/gui/splash/ConstantInt.java | 49 +
src/proguard/gui/splash/ConstantString.java | 49 +
src/proguard/gui/splash/ConstantTiming.java | 58 +
src/proguard/gui/splash/ImageSprite.java | 76 +
src/proguard/gui/splash/LinearColor.java | 72 +
src/proguard/gui/splash/LinearDouble.java | 55 +
src/proguard/gui/splash/LinearInt.java | 55 +
src/proguard/gui/splash/LinearTiming.java | 55 +
src/proguard/gui/splash/OverrideGraphics2D.java | 597 ++++++
src/proguard/gui/splash/RectangleSprite.java | 114 ++
src/proguard/gui/splash/SawToothTiming.java | 53 +
src/proguard/gui/splash/ShadowedSprite.java | 102 +
src/proguard/gui/splash/SineTiming.java | 53 +
src/proguard/gui/splash/SmoothTiming.java | 66 +
src/proguard/gui/splash/SplashPanel.java | 217 +++
src/proguard/gui/splash/Sprite.java | 41 +
src/proguard/gui/splash/TextSprite.java | 102 +
src/proguard/gui/splash/TimeSwitchSprite.java | 75 +
src/proguard/gui/splash/Timing.java | 34 +
src/proguard/gui/splash/TypeWriterString.java | 71 +
src/proguard/gui/splash/VariableColor.java | 36 +
src/proguard/gui/splash/VariableDouble.java | 34 +
src/proguard/gui/splash/VariableFont.java | 36 +
src/proguard/gui/splash/VariableInt.java | 34 +
src/proguard/gui/splash/VariableSizeFont.java | 65 +
src/proguard/gui/splash/VariableString.java | 34 +
src/proguard/gui/splash/package.html | 4 +
src/proguard/gui/vtitle.gif | Bin 0 -> 26541 bytes
src/proguard/io/CascadingDataEntryWriter.java | 86 +
src/proguard/io/ClassFileFilter.java | 72 +
src/proguard/io/ClassFileReader.java | 94 +
src/proguard/io/ClassFileRewriter.java | 77 +
src/proguard/io/DataEntry.java | 55 +
src/proguard/io/DataEntryCopier.java | 243 +++
src/proguard/io/DataEntryFilter.java | 38 +
src/proguard/io/DataEntryNameFilter.java | 54 +
src/proguard/io/DataEntryParentFilter.java | 51 +
src/proguard/io/DataEntryPump.java | 43 +
src/proguard/io/DataEntryReader.java | 39 +
src/proguard/io/DataEntryWriter.java | 65 +
src/proguard/io/DirectoryPump.java | 74 +
src/proguard/io/DirectoryWriter.java | 145 ++
src/proguard/io/FileDataEntry.java | 92 +
src/proguard/io/FilteredDataEntryReader.java | 96 +
src/proguard/io/FilteredDataEntryWriter.java | 112 ++
src/proguard/io/Finisher.java | 37 +
src/proguard/io/JarReader.java | 78 +
src/proguard/io/JarWriter.java | 183 ++
src/proguard/io/ParentDataEntryWriter.java | 67 +
src/proguard/io/RenamedDataEntry.java | 77 +
src/proguard/io/ZipDataEntry.java | 85 +
src/proguard/io/package.html | 4 +
src/proguard/obfuscate/AttributeShrinker.java | 160 ++
src/proguard/obfuscate/AttributeUsageMarker.java | 401 ++++
src/proguard/obfuscate/ClassFileObfuscator.java | 179 ++
src/proguard/obfuscate/ClassFileRenamer.java | 716 +++++++
src/proguard/obfuscate/MappingKeeper.java | 119 ++
src/proguard/obfuscate/MappingPrinter.java | 170 ++
src/proguard/obfuscate/MappingProcessor.java | 78 +
src/proguard/obfuscate/MappingReader.java | 195 ++
src/proguard/obfuscate/MemberInfoLinker.java | 185 ++
src/proguard/obfuscate/MemberInfoObfuscator.java | 404 ++++
src/proguard/obfuscate/MultiMappingProcessor.java | 98 +
src/proguard/obfuscate/NameAndTypeShrinker.java | 124 ++
src/proguard/obfuscate/NameAndTypeUsageMarker.java | 160 ++
src/proguard/obfuscate/NameFactory.java | 36 +
src/proguard/obfuscate/NameMarker.java | 78 +
src/proguard/obfuscate/ReadNameFactory.java | 171 ++
src/proguard/obfuscate/SimpleNameFactory.java | 156 ++
src/proguard/obfuscate/Utf8Shrinker.java | 121 ++
src/proguard/obfuscate/Utf8UsageMarker.java | 419 ++++
src/proguard/obfuscate/package.html | 3 +
src/proguard/optimize/ChangedCodePrinter.java | 203 ++
src/proguard/optimize/KeepMarker.java | 92 +
.../optimize/NoSideEffectMethodMarker.java | 74 +
.../optimize/SideEffectInstructionChecker.java | 246 +++
src/proguard/optimize/SideEffectMethodMarker.java | 172 ++
src/proguard/optimize/WriteOnlyFieldMarker.java | 158 ++
src/proguard/optimize/evaluation/BranchUnit.java | 64 +
.../optimize/evaluation/PartialEvaluator.java | 2016 ++++++++++++++++++++
src/proguard/optimize/evaluation/Processor.java | 997 ++++++++++
src/proguard/optimize/evaluation/Stack.java | 515 +++++
.../optimize/evaluation/TracedBranchUnit.java | 146 ++
src/proguard/optimize/evaluation/TracedStack.java | 336 ++++
.../optimize/evaluation/TracedVariables.java | 191 ++
src/proguard/optimize/evaluation/Variables.java | 312 +++
src/proguard/optimize/evaluation/package.html | 4 +
.../optimize/evaluation/value/Category1Value.java | 41 +
.../optimize/evaluation/value/Category2Value.java | 41 +
.../optimize/evaluation/value/DoubleValue.java | 312 +++
.../evaluation/value/DoubleValueFactory.java | 53 +
.../optimize/evaluation/value/FloatValue.java | 312 +++
.../evaluation/value/FloatValueFactory.java | 55 +
.../evaluation/value/InstructionOffsetValue.java | 237 +++
.../value/InstructionOffsetValueFactory.java | 59 +
.../optimize/evaluation/value/IntegerValue.java | 622 ++++++
.../evaluation/value/IntegerValueFactory.java | 66 +
.../optimize/evaluation/value/LongValue.java | 390 ++++
.../evaluation/value/LongValueFactory.java | 53 +
.../optimize/evaluation/value/ReferenceValue.java | 190 ++
.../evaluation/value/ReferenceValueFactory.java | 80 +
.../value/SpecificArrayReferenceValue.java | 160 ++
.../evaluation/value/SpecificDoubleValue.java | 213 +++
.../evaluation/value/SpecificFloatValue.java | 213 +++
.../evaluation/value/SpecificIntegerValue.java | 388 ++++
.../evaluation/value/SpecificLongValue.java | 258 +++
.../evaluation/value/SpecificReferenceValue.java | 158 ++
src/proguard/optimize/evaluation/value/Value.java | 143 ++
.../optimize/evaluation/value/ValueFactory.java | 63 +
.../optimize/evaluation/value/package.html | 3 +
src/proguard/optimize/package.html | 4 +
.../optimize/peephole/BranchTargetFinder.java | 178 ++
.../optimize/peephole/ClassFileFinalizer.java | 96 +
.../optimize/peephole/GetterSetterInliner.java | 387 ++++
.../optimize/peephole/GotoReturnReplacer.java | 92 +
.../optimize/peephole/LoadStoreRemover.java | 99 +
src/proguard/optimize/peephole/NopRemover.java | 68 +
src/proguard/optimize/peephole/PushPopRemover.java | 139 ++
.../peephole/SingleImplementationInliner.java | 534 ++++++
.../peephole/SingleImplementationMarker.java | 160 ++
.../optimize/peephole/StoreLoadReplacer.java | 116 ++
src/proguard/optimize/peephole/package.html | 3 +
src/proguard/package.html | 5 +
src/proguard/retrace/ReTrace.java | 155 ++
src/proguard/retrace/StackTrace.java | 177 ++
src/proguard/retrace/StackTraceItem.java | 294 +++
src/proguard/retrace/package.html | 4 +
src/proguard/shrink/ClassFileShrinker.java | 341 ++++
src/proguard/shrink/InnerUsageMarker.java | 224 +++
src/proguard/shrink/InterfaceUsageMarker.java | 158 ++
src/proguard/shrink/UsageMarker.java | 824 ++++++++
src/proguard/shrink/UsagePrinter.java | 174 ++
src/proguard/shrink/UsedClassFileFilter.java | 65 +
src/proguard/shrink/package.html | 3 +
src/proguard/util/BasicListMatcher.java | 148 ++
src/proguard/util/BasicMatcher.java | 360 ++++
src/proguard/util/ClassNameListMatcher.java | 88 +
src/proguard/util/ClassNameMatcher.java | 93 +
src/proguard/util/ExtensionMatcher.java | 52 +
src/proguard/util/FileNameListMatcher.java | 88 +
src/proguard/util/FileNameMatcher.java | 89 +
src/proguard/util/ListUtil.java | 87 +
src/proguard/util/StringMatcher.java | 38 +
src/proguard/util/package.html | 3 +
src/proguard/wtk/ProGuardObfuscator.java | 138 ++
src/proguard/wtk/default.pro | 112 ++
src/proguard/wtk/package.html | 3 +
420 files changed, 62137 insertions(+)
diff --git a/README b/README
new file mode 100644
index 0000000..e1cde65
--- /dev/null
+++ b/README
@@ -0,0 +1,54 @@
+ProGuard, Java class file shrinker and obfuscator
+=================================================
+
+This distribution contains the following directories:
+
+- lib : the main jars, compiled and ready to use with "java -jar ...."
+- docs : the complete documentation, licenses, etc. in html format
+- examples : some example configuration files
+- src : the source code
+
+
+The best place to start is docs/index.html
+
+
+Example
+=======
+
+If you want to give ProGuard a spin right away, try processing the jar itself:
+
+ cd lib
+ java -jar proguard.jar @../examples/proguard.pro
+
+The resulting proguard_out.jar contains the same application, but it's much
+smaller!
+
+
+Development
+===========
+
+If you're interested in changing and extending ProGuard, you can start by
+compiling the source code yourself:
+
+ mkdir classes
+ javac -sourcepath src -d classes src/proguard/ProGuard.java
+ javac -sourcepath src -d classes src/proguard/retrace/ReTrace.java
+ javac -sourcepath src -d classes src/proguard/gui/ProGuardGUI.java
+
+If you want to compile the ProGuard Ant task as well:
+
+ javac -sourcepath src -d classes -classpath lib/ant.jar \
+ src/proguard/ant/ProGuardTask.java
+
+If you want to compile the J2ME WTK obfuscator plug-in:
+
+ javac -sourcepath src -d classes -classpath wtklib/kenv.zip \
+ src/proguard/wtk/ProGuardObfuscator.java
+
+Note that you'll have to install Ant and the J2ME WTK yourself.
+
+Enjoy!
+
+http://proguard.sourceforge.net/
+
+Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
diff --git a/docs/FAQ.html b/docs/FAQ.html
new file mode 100644
index 0000000..16660b8
--- /dev/null
+++ b/docs/FAQ.html
@@ -0,0 +1,191 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard FAQ</title>
+</head>
+<body>
+
+<h2>Frequently Asked Questions</h2>
+
+<h3>Contents</h3>
+
+<ol>
+<li><a href="#shrinking">What is shrinking?</a>
+<li><a href="#obfuscation">What is obfuscation?</a>
+<li><a href="#optimization">What kind of optimizations does <b>ProGuard</b>
+ support?</a>
+<li><a href="#jdk1.4">Does <b>ProGuard</b> work with JDK1.4? JDK5.0?</a>
+<li><a href="#j2me">Does <b>ProGuard</b> work with J2ME?</a>
+<li><a href="#ant">Does <b>ProGuard</b> have support for Ant?</a>
+<li><a href="#gui">Does <b>ProGuard</b> come with a GUI?</a>
+<li><a href="#forname">Does <b>ProGuard</b> handle <code>Class.forName</code>
+ calls?</a>
+<li><a href="#resource">Does <b>ProGuard</b> handle resource files?</a>
+<li><a href="#encrypt">Does <b>ProGuard</b> encrypt strings constants?</a>
+<li><a href="#flow">Does <b>ProGuard</b> perform control flow obfuscation?</a>
+<li><a href="#incremental">Does <b>ProGuard</b> support incremental
+ obfuscation?</a>
+<li><a href="#keywords">Can <b>ProGuard</b> obfuscate using reserved
+ keywords?</a>
+<li><a href="#stacktrace">Can <b>ProGuard</b> reconstruct obfuscated stack
+ traces?</a>
+</ol>
+
+<a name="shrinking"> </a>
+<h3>What is shrinking?</h3>
+Java source code (.java files) is typically compiled to bytecode (.class
+files). Complete programs or program libraries are usually zipped up and
+distributed as Java archives (.jar files). Bytecode is more compact than Java
+source code, but it may still contain a lot of unused code, especially if it
+uses program libraries. Shrinking programs such as <b>ProGuard</b> can analyze
+bytecode and remove unused classes, fields, and methods. The program remains
+functionally equivalent, including the information given in exception stack
+traces.
+
+<a name="obfuscation"> </a>
+<h3>What is obfuscation?</h3>
+By default, compiled bytecode still contains a lot of debugging information:
+source file names, line numbers, field names, method names, argument names,
+variable names, etc. This information makes it straightforward to decompile
+the bytecode and reverse-engineer entire programs. Sometimes, this is not
+desirable. Obfuscators such as <b>ProGuard</b> can remove the debugging
+information and replace all names by meaningless character sequences, making
+it much harder to reverse-engineer the code. It further compacts the code as a
+bonus. The program remains functionally equivalent, except for the class
+names, method names, and line numbers given in exception stack traces.
+
+<a name="optimization"> </a>
+<h3>What kind of optimizations does <b>ProGuard</b> support?</h3>
+Apart from removing unused classes, fields, and methods in the shrinking step,
+<b>ProGuard</b> can also perform optimizations at the bytecode level, inside
+methods:
+<ul>
+<li>Evaluating constant expressions.
+<li>Removing unnecessary computations.
+<li>Removing unnecessary field accesses.
+<li>Removing unnecessary method calls.
+<li>Removing unnecessary branches.
+<li>Removing unnecessary comparisons and instanceof tests.
+<li>Removing write-only fields.
+<li>Various peephole optimizations like push/pop simplification.
+<li>Making classes and methods final when possible.
+<li>Inlining simple getters and setters when possible.
+<li>Replacing interfaces that have single implementations.
+<li>Optionally removing logging code.
+</ul>
+The positive effects of these optimizations will depend on your code and on
+the virtual machine on which the code is executed. Simple virtual machines may
+benefit more than advanced virtual machines with sophisticated JIT compilers.
+At the very least, your bytecode may become a bit smaller.
+<p>
+A notable optimization that isn't supported yet is the inlining of constant
+fields that are not marked as final.
+
+<a name="jdk1.4"> </a>
+<h3>Does <b>ProGuard</b> work with JDK1.4? JDK5.0?</h3>
+Yes. Class files compiled with JDK1.4 are targeted at JRE1.2 by default. Class
+files compiled with JDK5.0 may have additional attributes for supporting
+generics and annotations. The compiled class files have slightly different
+structures from older class files. <b>ProGuard</b> handles all versions
+correctly.
+
+<a name="j2me"> </a>
+<h3>Does <b>ProGuard</b> work with J2ME?</h3>
+Yes. <b>ProGuard</b> itself runs in J2SE, but you can freely specify the
+run-time environment at which your programs are targeted, including J2ME. For
+instance, you can specify <code>midpapi20.jar</code> and
+<code>cldcapi11.jar</code> as the run-time libraries, instead of J2SE's
+traditional <code>rt.jar</code>. All of <b>ProGuard</b>'s powerful
+configuration options remain available. The <a
+href="manual/examples.html">example section</a> of the <a
+href="manual/index.html">ProGuard User Manual</a> illustrates how to process
+<a href="manual/examples.html#midlet">a single midlet</a> or <a
+href="manual/examples.html#midlets">all midlets</a> in your input jar, for
+instance.
+<p>
+In addition, <b>ProGuard</b> provides an obfuscator plug-in for the J2ME
+Wireless Toolkit.
+
+<a name="ant"> </a>
+<h3>Does <b>ProGuard</b> have support for Ant?</h3>
+Yes. <b>ProGuard</b> provides an Ant task, so that it integrates seamlessly
+into your Ant build processes. You can still use configurations in
+<b>ProGuard</b>'s own readable format. Alternatively, if you prefer XML, you
+can specify the equivalent XML configuration.
+
+<a name="gui"> </a>
+<h3>Does <b>ProGuard</b> come with a GUI?</h3>
+Yes. First of all, <b>ProGuard</b> is perfectly usable as a command-line tool
+that can easily be integrated into any automatic build process. For casual
+users, there's also a graphical user interface that makes creating, loading,
+editing, executing, and saving ProGuard configurations a breeze.
+
+<a name="forname"> </a>
+<h3>Does <b>ProGuard</b> handle <code>Class.forName</code> calls?</h3>
+Yes. <b>ProGuard</b> automatically handles
+<code>Class.forName("SomeClass")</code> and <code>SomeClass.class</code>
+constructs. The referenced classes are preserved in the shrinking phase, and
+the string arguments are properly replaced in the obfuscation phase.
+<p>
+With variable string arguments, it's generally not possible to determine their
+possible values. They might be read from a configuration file, for instance.
+However, <b>ProGuard</b> will note constructs like
+"<code>(SomeClass)Class.forName(variable).newInstance()</code>". These might
+be an indication that the class or interface <code>SomeClass</code> and/or its
+implementations may need to be preserved. The user can adapt his configuration
+accordingly.
+
+<a name="resource"> </a>
+<h3>Does <b>ProGuard</b> handle resource files?</h3>
+Yes, in the sense that <b>ProGuard</b> copies all non-class resource files
+from the given input jars to the output jars. Their names and contents remain
+unchanged.
+
+<a name="encrypt"> </a>
+<h3>Does <b>ProGuard</b> encrypt strings constants?</h3>
+No. Storing encrypted string constants in program code is fairly futile, since
+the encryption has to be perfectly reversible by definition. Moreover, the
+decryption costs additional memory and computation at run-time. If this feature
+is ever incorporated, I'll provide a tool to decrypt the strings as well.
+
+<a name="flow"> </a>
+<h3>Does <b>ProGuard</b> perform flow obfuscation?</h3>
+No. Control obfuscation injects additional branches into the bytecode, in an
+attempt to fool decompilers. This operation may confuse JIT compilers as well,
+adversely affecting performance. It may be added as an option in the future,
+but it doesn't have the highest priority.
+
+<a name="incremental"> </a>
+<h3>Does <b>ProGuard</b> support incremental obfuscation?</h3>
+Yes. This feature allows you to specify a previous obfuscation mapping file in
+a new obfuscation step, in order to produce add-ons or patches for obfuscated
+code.
+
+<a name="keywords"> </a>
+<h3>Can <b>ProGuard</b> obfuscate using reserved keywords?</h3>
+Yes. You can specify your own obfuscation dictionary, such as a list of
+reserved key words, identifiers with foreign characters, random source files,
+or a text by Shakespeare. Note that this hardly improves the obfuscation.
+Decent decompilers can automatically replace reserved keywords, and the effect
+can fairly simply be undone by obfuscating again with simpler names.
+
+<a name="stacktrace"> </a>
+<h3>Can <b>ProGuard</b> reconstruct obfuscated stack traces?</h3>
+Yes. <b>ProGuard</b> comes with a companion tool, <b>ReTrace</b>, that can
+'de-obfuscate' stack traces produced by obfuscated applications. The
+reconstruction is based on the mapping file that <b>ProGuard</b> can write
+out. If line numbers have been obfuscated away, a list of alternative method
+names is presented for each obfuscated method name that has an ambiguous
+reverse mapping. Please refer to the <a href="manual/index.html">ProGuard User
+Manual</a> for more details.
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/GPL.html b/docs/GPL.html
new file mode 100644
index 0000000..c7a2458
--- /dev/null
+++ b/docs/GPL.html
@@ -0,0 +1,406 @@
+<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<HTML>
+<HEAD>
+<TITLE>GNU General Public License</TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#1F00FF" ALINK="#FF0000" VLINK="#9900DD">
+<H1>GNU General Public License</H1>
+<H2>Table of Contents</H2>
+<UL>
+
+ <LI><A NAME="TOC1" HREF="#SEC1">GNU GENERAL PUBLIC LICENSE</A>
+<UL>
+<LI><A NAME="TOC2" HREF="#SEC2">Preamble</A>
+<LI><A NAME="TOC3" HREF="#SEC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A>
+
+</UL>
+</UL>
+
+<P>
+
+<HR>
+
+<P>
+
+
+
+<H2><A NAME="SEC1" HREF="#TOC1">GNU GENERAL PUBLIC LICENSE</A></H2>
+<P>
+Version 2, June 1991
+
+</P>
+
+<PRE>
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+</PRE>
+
+
+
+<H2><A NAME="SEC2" HREF="#TOC2">Preamble</A></H2>
+
+<P>
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+</P>
+<P>
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+</P>
+<P>
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+</P>
+<P>
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+</P>
+<P>
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+</P>
+<P>
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+</P>
+<P>
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+</P>
+<P>
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+</P>
+
+
+<H2><A NAME="SEC3" HREF="#TOC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A></H2>
+
+
+<P>
+
+<STRONG>0.</STRONG>
+ This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+<P>
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+<P>
+
+<STRONG>1.</STRONG>
+ You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+<P>
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+<P>
+
+<STRONG>2.</STRONG>
+ You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+<P>
+
+<UL>
+
+<LI><STRONG>a)</STRONG>
+ You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+<P>
+<LI><STRONG>b)</STRONG>
+ You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+<P>
+<LI><STRONG>c)</STRONG>
+ If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+</UL>
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+<P>
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+<P>
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+<P>
+
+<STRONG>3.</STRONG>
+ You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+
+<!-- we use this doubled UL to get the sub-sections indented, -->
+<!-- while making the bullets as unobvious as possible. -->
+<UL>
+
+<LI><STRONG>a)</STRONG>
+ Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+<P>
+<LI><STRONG>b)</STRONG>
+ Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+<P>
+<LI><STRONG>c)</STRONG>
+ Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+</UL>
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+<P>
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+<P>
+
+<STRONG>4.</STRONG>
+ You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+<P>
+
+<STRONG>5.</STRONG>
+ You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+<P>
+
+<STRONG>6.</STRONG>
+ Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+<P>
+
+<STRONG>7.</STRONG>
+ If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+<P>
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+<P>
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+<P>
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+<P>
+
+<STRONG>8.</STRONG>
+ If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+<P>
+
+<STRONG>9.</STRONG>
+ The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+<P>
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+<P>
+
+
+<STRONG>10.</STRONG>
+ If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+
+
+<P><STRONG>NO WARRANTY</STRONG></P>
+
+<P>
+
+<STRONG>11.</STRONG>
+ BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+<P>
+
+<STRONG>12.</STRONG>
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+<P>
+
+
+<H2>END OF TERMS AND CONDITIONS</H2>
+</BODY>
+</HTML>
diff --git a/docs/GPL_exception.html b/docs/GPL_exception.html
new file mode 100644
index 0000000..3d136dc
--- /dev/null
+++ b/docs/GPL_exception.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<HTML>
+<HEAD>
+<TITLE>Special Exception to the GNU General Public License</TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#1F00FF" ALINK="#FF0000" VLINK="#9900DD">
+<H1>Special Exception to the GNU General Public License</H1>
+
+<P>
+Copyright © 2002-2004 Eric Lafortune
+</P>
+
+<P>
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+</P>
+
+<P>
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+</P>
+
+<P>
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+</P>
+
+<P>
+In addition, as a special exception, Eric Lafortune gives permission to link
+the code of this program with Apache Ant, the Sun J2ME Wireless Toolkit, and
+the Eclipse Platform, and distribute linked combinations including the two.
+You must obey the GNU General Public License in all respects for all of the
+code used other than these programs. If you modify this file, you may extend
+this exception to your version of the file, but you are not obligated to do
+so. If you do not wish to do so, delete this exception statement from your
+version.
+</P>
+
+</BODY>
+</HTML>
diff --git a/docs/acknowledgements.html b/docs/acknowledgements.html
new file mode 100644
index 0000000..71bd57c
--- /dev/null
+++ b/docs/acknowledgements.html
@@ -0,0 +1,58 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Acknowledgements</title>
+</head>
+<body>
+
+<h2>Acknowledgements</h2>
+
+<b>ProGuard</b> grew out of <b>RetroGuard</b>, which its author Mark Welsh has
+kindly made available under the GNU Lesser General Public License.
+<b>RetroGuard</b> is a very nice piece of code, but it only performs
+obfuscation. I started from the class file parsing code and wrote my own
+shrinker, optimizer, and obfuscator. At this point, both programs have little
+code in common.
+<p>
+
+Dirk Schnelle has generously contributed and maintained the first versions of
+the Ant task. The implementation has been rewritten for version 3.0, but the
+XML schema is still based on his work.
+<p>
+
+I am developing ProGuard in my spare time, in part on equipment that my
+employer <a href="http://www.luciad.com/" target="other">Luciad</a> is kindly
+allowing me to use.
+<p>
+
+<a href="http://sourceforge.net/forum/projects/proguard/"
+target="other">SourceForge</a> is graciously providing the resources for
+hosting this project and many other projects.
+<p>
+
+My colleagues at Luciad have been very patient trying early versions of the
+code. Since the first public release, others have chimed in with interesting
+ideas, bug reports, and bug fixes: Thorsten Heit, Oliver Retzl, Jonathan
+Knudsen, Bob Drury, Dave Jarvis, Marc Chapman, Dave Morehouse, Richard
+Osbaldeston, Peter Hawkins, Mark Sherington, David Sitsky, James Manning,
+Ptolemy Oberin, Frank-Michael Moser, QZ Shines, Thomas Singer, Michele
+Puccini, Roman Bednarek, Natalia Pujol, Daniel Sjöblom, Jan Filipsky,
+Charles Smith, and Gerrit Telkamp.
+Thanks! Your feedback has been invaluable.
+<p>
+
+The code and these web pages were written using Sun's JDKs, IBM Eclipse, Linux,
+GNU emacs, bash, sed, awk, and a whole host of other free tools which continue
+to make programming interesting.
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+
+</body>
+</html>
diff --git a/docs/alternatives.html b/docs/alternatives.html
new file mode 100644
index 0000000..6918ecb
--- /dev/null
+++ b/docs/alternatives.html
@@ -0,0 +1,433 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Alternatives</title>
+</head>
+<body>
+
+<h2>Alternatives</h2>
+
+There are quite a few Java class file shrinkers, optimizers, and obfuscators
+out there. Users of <b>ProGuard</b> tell me it compares with the best of them.
+However, you may want to check that out yourself.
+<p>
+This is a list of the programs of which I'm aware. Obviously, I've never
+personally tested all of them. Many programs, even commercial ones, have been
+abandoned. Please drop me a note if you know of any other shrinkers,
+optimizers, or obfuscators, or if some information provided below is
+incorrect.
+<p>
+
+<table>
+
+<tr>
+<th>Author/Company</th>
+<th>Program</th>
+<th>Shrinking</th>
+<th>Optimization</th>
+<th>Obfuscation</th>
+<th>License</th>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a></td>
+<td><a target="other" href="http://proguard.sourceforge.net/">ProGuard</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free (GPL)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.informatik.uni-oldenburg.de/leute/hoenicke.html">Jochen Hoenicke</a></td>
+<td><a target="other" href="http://jode.sourceforge.net/">Jode</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free (GPL)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.nq4.de/">NQ4</a></td>
+<td><a target="other" href="http://www.nq4.de/">Joga</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free (no source)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://sourceforge.net/users/hchacha/">Hidetoshi Ohuchi</a></td>
+<td><a target="other" href="http://jarg.sourceforge.net/">Jarg</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free (BSD)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.geocities.com/CapeCanaveral/Hall/2334/resume.html">Alexander Shvets</a></td>
+<td><a target="other" href="http://www.geocities.com/CapeCanaveral/Hall/2334/Programs/cafebabe.html">CafeBabe</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.cs.cornell.edu/nystrom/">Nate Nystrom</a></td>
+<td><a target="other" href="http://www.cs.purdue.edu/homes/hosking/bloat/">Bloat</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td>Free</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.cs.purdue.edu/homes/grothoff/">Christian Grothoff</a></td>
+<td><a target="other" href="http://www.ovmj.org/jamit/">Jamit</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td>Free (GPL)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.riggshill.com/">RiggsHill Software</a></td>
+<td><a target="other" href="http://genjar.sourceforge.net/">GenJar</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td>Free (Apache)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.sable.mcgill.ca/">Sable</a></td>
+<td><a target="other" href="http://www.sable.mcgill.ca/soot/">Soot</a></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td>Free (LGPL)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.utdallas.edu/~gxz014000/">Bajie</a></td>
+<td><a target="other" href="http://www.utdallas.edu/~gxz014000/jcmp/">JCMP</a></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.retrologic.com/">RetroLogic</a></td>
+<td><a target="other" href="http://www.retrologic.com/">RetroGuard</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free (LGPL)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://sourceforge.net/users/glurk/">Thorsten Heit</a></td>
+<td><a target="other" href="http://sourceforge.net/projects/javaguard/">JavaGuard</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free (LGPL)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://mwobfu.sourceforge.net/">Patrick Mueller</a></td>
+<td><a target="other" href="http://mwobfu.sourceforge.net/">Mwobfu</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free (GPL)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.yworks.com/">yWorks</a></td>
+<td><a target="other" href="http://www.yworks.com/en/products_yguard_about.htm">yGuard</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.drjava.de/">Dr. Java</a></td>
+<td><a target="other" href="http://www.drjava.de/obfuscator/">Marvin Obfuscator</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free (no source)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.alphaworks.ibm.com/">IBM AlphaWorks</a></td>
+<td><a target="other" href="http://www.alphaworks.ibm.com/tech/jax/">JAX</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.preemptive.com/">PreEmptive</a></td>
+<td><a target="other" href="http://www.preemptive.com/products.html">DashOPro</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.zelix.com/">Zelix</a></td>
+<td><a target="other" href="http://www.zelix.com/klassmaster/index.html">KlassMaster</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.s5systems.com/">S5 Systems</a></td>
+<td><a target="other" href="http://www.s5systems.com/jPresto.htm">jPresto</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.codingart.com/">CodingArt</a></td>
+<td><a target="other" href="http://www.codingart.com/codeshield.html">CodeShield</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.e-t.com/">Eastridge Technology</a></td>
+<td><a target="other" href="http://www.e-t.com/jshrink.html">Jshrink</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.helseth.com/">Helseth</a></td>
+<td><a target="other" href="http://www.helseth.com/HJO.htm">JObfuscator</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.leesw.com/">LeeSoftware</a></td>
+<td><a target="other" href="http://www.leesw.com/">Smokescreen Obfuscator</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.vegatech.com/">Vega Technologies</a></td>
+<td><a target="other" href="http://www.vegatech.com/jzipper/">JZipper</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.uni-vologda.ac.ru/~c3c/">Sergey Sverdlov</a></td>
+<td><a target="other" href="http://www.uni-vologda.ac.ru/~c3c/jco/">J.Class Optimizer</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://cs.arizona.edu/">U. of Arizona</a></td>
+<td><a target="other" href="http://sandmark.cs.arizona.edu/">SandMark</a></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.force5.com/">Force 5</a></td>
+<td><a target="other" href="http://www.force5.com/">JCloak</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.wingsoft.com/">WingSoft</a></td>
+<td><a target="other" href="http://www.wingsoft.com/wingguard.html">WingGuard</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.jammconsulting.com/">JAMM Consulting</a></td>
+<td><a target="other" href="http://www.jammconsulting.com/jamm/servlet/com.jammconsulting.servlet.JAMMServlet?pageId=ObfuscateProPage">ObfuscatePro</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.2lkit.com/">2LKit</a></td>
+<td><a target="other" href="http://www.2lkit.com/products/2LKitObf/index.htm">2LKit Obfuscator</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.duckware.com/">Duckware</a></td>
+<td><a target="other" href="http://www.duckware.com/jobfuscate/">Jobfuscate</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.jproof.com/">JProof</a></td>
+<td><a target="other" href="http://www.jproof.com/">JProof</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.4fang.net/">4Fang</a></td>
+<td><a target="other" href="http://www.4fang.net/jmix/">JMix</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.solutia.ro/">GITS</a></td>
+<td><a target="other" href="http://www.solutia.ro/pages/javadc/">Blurfuscator</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.jdevelop.com/">JDevelop</a></td>
+<td><a target="other" href="http://www.jdevelop.com/best-java-obfuscator.html">JSCO</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://sourceforge.net/projects/flmobf/">Alain Moran</a></td>
+<td><a target="other" href="http://sourceforge.net/projects/flmobf/">flmObf</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free (BSD)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.chez.com/vasile/">Vasile Calmatui</a></td>
+<td><a target="other" href="http://www.chez.com/vasile/obfu/VasObfuLite.html">VasObfuLite</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Free</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www-i2.informatik.rwth-aachen.de/~markusj/">Markus Jansen</a></td>
+<td><a target="other" href="http://www-i2.informatik.rwth-aachen.de/~markusj/jopt/">Jopt</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>(disappeared?)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.primenet.com/~ej">Eron Jokipii</a></td>
+<td><a target="other" href="http://www.primenet.com/~ej">Jobe</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>(disappeared?)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://jrc.krdl.org.sg/">JRC</a></td>
+<td><a target="other" href="http://jrc.krdl.org.sg/decaf/">DeCaf</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>(disappeared?)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.plumbdesign.com/">Plumb Design</a></td>
+<td><a target="other" href="http://www.condensity.com/">Condensity</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial (discontinued)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.4thpass.com/">4th Pass</a></td>
+<td><a target="other" href="http://www.4thpass.com/">SourceGuard</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial (discontinued?)</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.sbktech.org/">HashJava</a></td>
+<td><a target="other" href="http://www.sbktech.org/">HashJava</a></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td>Commercial (disappeared?)</td>
+</tr>
+
+</table>
+<p>
+All trademarks are property of their respective holders.
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+
+</body>
+</html>
diff --git a/docs/checkmark.gif b/docs/checkmark.gif
new file mode 100644
index 0000000..8afa677
Binary files /dev/null and b/docs/checkmark.gif differ
diff --git a/docs/downloads.html b/docs/downloads.html
new file mode 100644
index 0000000..c695e33
--- /dev/null
+++ b/docs/downloads.html
@@ -0,0 +1,221 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Downloads</title>
+</head>
+<body>
+
+<h2>Downloads</h2>
+
+<b>ProGuard</b> is distributed under the GNU General Public License.
+Please refer to the <a href="license.html">license page</a> for more details.
+<p>
+<b>ProGuard</b> is written in Java. It requires a Java 2 runtime environment.
+<p>
+You can download the latest release (containing the program jar, the
+documentation you're reading now, examples, and source code) from this
+location:
+<p>
+<center><a href="http://sourceforge.net/project/showfiles.php?group_id=54750"
+target="other">Download section</a> (at <a
+href="http://sourceforge.net/projects/proguard/"
+target="other">SourceForge</a>)</center>
+<p>
+
+If you're still working with an older version of <b>ProGuard</b>, check out
+the summary of changes below, to see if you're missing something essential.
+Better look at the up-to-date <a
+href="http://proguard.sourceforge.net/downloads.html">on-line version</a> if
+you're reading a local copy of this page. The download section may also contain
+updates with sub-minor version numbers. These versions are typically released
+shortly after their parent versions, for applying emergency fixes.
+<p>
+
+<h3>Version 3.2</h3>
+<ul>
+<li>Fixed JDK5.0 processing bugs.
+<li>Fixed optimization bugs.
+<li>Fixed relative paths in Ant task.
+<li>Improved speed of shrinking step.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 3.1</h3>
+<ul>
+<li>Improved obfuscation and shrinking of private class members.
+<li>Added inlining of interfaces with single implementations.
+<li>Added option to specify obfuscation dictionary.
+<li>Added option to read package visible library class members.
+<li>Extended support for JDK5.0 attributes.
+<li>Fixed various optimization bugs.
+<li>Modified Ant task to accept paths instead of filesets.
+<li>Fixed two Ant task bugs.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 3.0</h3>
+<ul>
+<li>Added bytecode optimization step, inbetween shrinking step and obfuscation
+ step.
+<li>Generalized filtered recursive reading and writing of jars, wars, ears,
+ zips, and directories.
+<li>Added support for grouping input and output jars, wars, ears, zips, and
+ directories.
+<li>Added support for applying mapping files to library classes.
+<li>Removed <code>-resourcejars</code> option. Resources should now be read
+ using regular <code>-injars</code> options, using filters if necessary.
+<li>Rewrote Ant task. Input and output modification dates are not checked at
+ the moment. Minor changes in XML schema:
+ <ul>
+ <li>Filters now specified using attributes.
+ <li>'<code>outjars</code>' now nested element instead of attribute.
+ <li>'<code>type</code>' attribute of <code><method></code> element no
+ longer defaults to '<code>void</code>'.
+ <li><code><</code> and <code>></code> characters now have to be
+ encoded in embedded configurations.
+ <li><code><proguardconfiguration></code> task no longer accepts
+ attributes.
+ </ul>
+<li>Updated J2ME WTK plugin, now customizable through configuration file.
+<li>Updated GUI.
+<li>Fixed various processing bugs.
+<li>Fixed ReTrace parsing bugs.
+<li>Improved jar compression.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 2.1</h3>
+<ul>
+<li>Added support for JDK1.5 classes.
+<li>Added additional wildcard for matching primitive types.
+<li>Added possibility to switch off notes about duplicate class definitions.
+<li>Fixed use of multiple filters on output jars.
+<li>Fixed option to keep all attributes.
+<li>Fixed various Ant task bugs.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 2.0</h3>
+<ul>
+<li>Added a graphical user interface for ProGuard and ReTrace.
+<li>Added <code>-applymapping</code> option for incremental obfuscation.
+<li>Added support for filtering input and output files.
+<li>Added support for the J++ <code>SourceDir</code> attribute.
+<li>Improved detection of <code>.class</code> constructs.
+<li>Improved handling of misplaced manifest files.
+<li>Improved implementation of ReTrace.
+<li>Worked around String UTF-8 encoding bug affecting foreign characters.
+<li>Fixed exception when ignoring warnings.
+<li>Fixed various Ant task bugs.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 1.7</h3>
+<ul>
+<li>Fixed various Ant task bugs.
+<li>Fixed ClassCastException due to explicitly used abstract classes with
+ implicitly used interfaces targeted at JRE1.2 (the default in JDK1.4).
+<li>Fixed <code>-defaultpackage</code> bug for protected classes and class
+ members.
+<li>Fixed ReTrace bug when retracing without line number tables.
+<li>Worked around zip package problems with duplicate out entries and rogue
+ manifest files.
+<li>Added work-around for handling malformed legacy interface class files.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 1.6</h3>
+<ul>
+<li>Added support for Ant.
+<li>Added support for the J2ME Wireless Toolkit.
+<li>Added support for reading and writing directory hierarchies.
+<li>Added option for specifying resource jars and directories.
+<li>Added support for wildcards in class member specifications.
+<li>Improved handling of the <code>-defaultpackage</code> option.
+<li>Improved stack trace parsing in ReTrace tool.
+<li>Fixed processing of libraries containing public as well as non-public
+ extensions of non-public classes.
+<li>Fixed examples for processing libraries, midlets, and serializable code.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 1.5</h3>
+<ul>
+<li>Fixed processing of retrofitted library interfaces.
+<li>Fixed processing of <code>.class</code> constructs in internal classes
+ targeted at JRE1.2 (the default in JDK1.4).
+<li>Fixed <code>-dump</code> option when <code>-outjar</code> option is not
+ present.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 1.4</h3>
+<ul>
+<li>Now copying resource files over from the input jars to the output jar.
+<li>Added option to obfuscate using lower-case class names only.
+<li>Added better option for obfuscating native methods.
+<li>Added option not to ignore non-public library classes.
+<li>Added automatic .class detection for classes compiled with Jikes.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 1.3</h3>
+<ul>
+<li>Added support for wildcards in class names.
+<li>Added tool to de-obfuscate stack traces.
+<li>Added options to print processing information to files.
+<li>Added option to rename source file attributes.
+<li>Fixed processing of implicitly used interfaces targeted at JRE1.2 (the
+ default in JDK1.4)
+<li>Fixed processing of configurations with negated access modifiers.
+<li>Fixed duplicate class entry bug.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 1.2</h3>
+<ul>
+<li>Improved speed.
+<li>Fixed processing of classes targeted at JRE1.2 (the default in JDK1.4)
+ with references to their own subclasses.
+<li>Fixed processing of static initializers in J2ME MIDP applications.
+<li>Fixed processing of retrofitted interfaces (again).
+<li>Added more flexible handling of white space in configuration.
+<li>Updated documentation.
+</ul>
+
+<h3>Version 1.1</h3>
+<ul>
+<li>Added automatic detection of <code>Class.forName("MyClass")</code>,
+ <code>MyClass.class</code>, and
+ <code>(MyClass)Class.forName(variable).newInstance()</code> constructs.
+ This greatly simplifies configuration.
+<li>Added options to keep class names and class member names without affecting
+ any shrinking. They are mostly useful for native methods and serializable
+ classes.
+<li>Fixed processing of retrofitted interfaces, like:
+ <pre>
+ class A { m() {...} }
+ interface I { m(); }
+ class B extends A implements I
+ </pre>
+<li>Added handling of missing/invalid manifest file in input jar.
+<li>Updated documentation and examples.
+</ul>
+
+<h3>Version 1.0</h3>
+<ul>
+<li>First public release, based on class parsing code from Mark Welsh's
+ <b>RetroGuard</b>.
+</ul>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+
+</body>
+</html>
diff --git a/docs/drop1.gif b/docs/drop1.gif
new file mode 100644
index 0000000..426d856
Binary files /dev/null and b/docs/drop1.gif differ
diff --git a/docs/drop2.gif b/docs/drop2.gif
new file mode 100644
index 0000000..b607542
Binary files /dev/null and b/docs/drop2.gif differ
diff --git a/docs/drop3.gif b/docs/drop3.gif
new file mode 100644
index 0000000..11ce424
Binary files /dev/null and b/docs/drop3.gif differ
diff --git a/docs/feedback.html b/docs/feedback.html
new file mode 100644
index 0000000..43ae9e9
--- /dev/null
+++ b/docs/feedback.html
@@ -0,0 +1,106 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-script-type" content="text/javascript">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Feedback</title>
+</head>
+<body>
+
+<h2>Feedback</h2>
+
+By now, I've invested a fair amount of time in <b>ProGuard</b>. You can help
+by providing feedback! If you have good experiences, bad experiences,
+problems, bugs, bug fixes, ideas, encouragements, etc. to share, please go
+ahead:
+<p>
+<ul>
+<li>A good place to share your thoughts about <b>ProGuard</b> is the <a
+ href="http://sourceforge.net/forum/forum.php?forum_id=182455"
+ target="other">open discussion forum</a> (at <a
+ href="http://sourceforge.net/projects/proguard/"
+ target="other">SourceForge</a>).
+ <p>
+
+<li>If you need help, please go to the <a
+ href="http://sourceforge.net/forum/forum.php?forum_id=182456"
+ target="other">help forum</a> (at <a
+ href="http://sourceforge.net/projects/proguard/"
+ target="other">SourceForge</a>).
+ <p>
+
+<li>You can submit and consult bug reports on the <a
+
+ href="http://sourceforge.net/tracker/?atid=474704&group_id=54750&func=browse"
+ target="other">bug tracking page</a> (at <a
+ href="http://sourceforge.net/projects/proguard/"
+ target="other">SourceForge</a>).
+ <p>
+
+<li>Likewise, you can submit and consult feature requests on the <a
+
+ href="http://sourceforge.net/tracker/?atid=474707&group_id=54750&func=browse"
+ target="other">feature request page</a> (at <a
+ href="http://sourceforge.net/projects/proguard/"
+ target="other">SourceForge</a>).
+ <p>
+
+<li>If you just want to stay abreast of the latest developments, you can
+ subscribe to the announcements of new releases in the <a
+ href="http://sourceforge.net/project/showfiles.php?group_id=54750"
+ target="other">download section</a> at <a
+ href="http://sourceforge.net/projects/proguard/"
+ target="other">SourceForge</a>, or the
+ <a href="http://software.freshmeat.net/projects/proguard/"
+ target="other">project page</a> at <a
+ href="http://software.freshmeat.net/">FreshMeat</a>.
+ <p>
+
+<li>If you have detailed bug reports with attachments, or just some
+ encouragements, or if <b>ProGuard</b> is useful to you and you want to
+ support it with software or hardware, you can mail me directly at
+
+<script type="text/javascript" language="JavaScript">
+<!--
+document.write("<a href=\"ma");
+document.write("ilto:");
+document.write("lafortune");
+document.write("@");
+document.write("users.sourceforge.net\">");
+document.write("lafortune");
+document.write("@");
+document.write("users.sourceforge.net");
+document.write("</a>");
+document.write(" <em>or</em> at ");
+document.write("<a href=\"ma");
+document.write("ilto:");
+document.write("eric");
+document.write("@");
+document.write("graphics.cornell.edu\">");
+document.write("eric");
+document.write("@");
+document.write("graphics.cornell.edu");
+document.write("</a>");
+//-->
+</script>
+<noscript>
+< lafortune @ users . sourceforge . net >
+<em>or</em> at
+< eric @ graphics . cornell . edu > (please remove the spaces)
+</noscript>
+.
+</ul>
+<p>
+I can't promise a swift answer, or any answer at all, for that matter, but I'd
+love to see your responses.
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+
+</body>
+</html>
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..802be28
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,54 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-script-type" content="text/javascript">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard</title>
+</head>
+<frameset
+ rows="50,*"
+ framespacing="0"
+ frameborder="no">
+
+<frame
+ name="title"
+ src="title.html"
+ scrolling="no"
+ marginwidth="0"
+ marginheight="0"
+ noresize>
+
+<frameset
+ cols="120,*"
+ framespacing="0"
+ frameborder="no">
+
+<frame
+ name="sections"
+ src="sections.html"
+ scrolling="no"
+ marginwidth="0"
+ marginheight="0"
+ noresize>
+
+<frame
+ name="main"
+ src="main.html"
+ scrolling="auto"
+ marginwidth="10"
+ marginheight="10"
+ noresize>
+
+</frameset>
+</frameset>
+
+<noframes>
+<body>
+Your browser doesn't support frames, but that's cool.
+<p>
+You can go straight to the <a href="main.html">main page</a>.
+</body>
+</noframes>
+</html>
diff --git a/docs/license.html b/docs/license.html
new file mode 100644
index 0000000..97d1f78
--- /dev/null
+++ b/docs/license.html
@@ -0,0 +1,46 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard License</title>
+</head>
+<body>
+
+<h2>License</h2>
+
+<b>ProGuard</b> is free. I wrote it for the challenge of it. And for eternal
+fame and glory, of course. You can use it for whatever purpose you deem
+useful. This includes processing your applications, commercial or not. Your
+code obviously remains yours after processing.
+<p>
+
+<b>ProGuard</b> is copyrighted, but the distribution license provides you with
+some rights for modifying and redistributing its code and its documentation.
+<p>
+<b>ProGuard</b> is distributed under the term of the <a href="GPL.html">GNU
+General Public License</a> (GPL), as published by the <a
+href="http://www.fsf.org/" target="other">Free Software Foundation</a> (FSF).
+In short, this means that you may freely redistribute the program, modified or
+as is, on the condition that you make the complete source code available as
+well. If you develop a program that is linked with <b>ProGuard</b>, the
+program as a whole has to be distributed at no charge under the GPL. I am
+granting a <a href="GPL_exception.html">special exception</a> to the latter
+clause (in wording suggested by the <a
+href="http://www.gnu.org/copyleft/gpl-faq.html#GPLIncompatibleLibs"
+target="other">FSF</a>), for combinations with Apache Ant, the Sun J2ME
+Wireless Toolkit, and the Eclipse Platform.
+
+<p>
+The user documentation represents an important part of this work. It may only
+be redistributed without changes, along with the unmodified version of the
+code.
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/luciadlogo.png b/docs/luciadlogo.png
new file mode 100644
index 0000000..0147ce3
Binary files /dev/null and b/docs/luciadlogo.png differ
diff --git a/docs/main.html b/docs/main.html
new file mode 100644
index 0000000..b782bf1
--- /dev/null
+++ b/docs/main.html
@@ -0,0 +1,79 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Main</title>
+</head>
+<body>
+
+<h2>Main</h2>
+
+<p class="intro">
+<b>ProGuard</b> is a free Java class file shrinker, optimizer, and obfuscator.
+It can detect and remove unused classes, fields, methods, and attributes. It
+can then optimize bytecode and remove unused instructions. Finally, it can
+rename the remaining classes, fields, and methods using short meaningless
+names. The resulting jars are smaller and harder to reverse-engineer.
+</p>
+<p>
+More compact jar files also means smaller storage requirements, faster
+transfer of applications across networks, faster loading, and smaller memory
+footprints.
+<p>
+<b>ProGuard</b>'s main advantage compared to other Java obfuscators is
+probably its compact template-based configuration. A few intuitive command
+line options or a simple configuration file are usually sufficient. For
+instance, the following configuration option preserves all applets in a jar:
+<pre>
+ -keep public class * extends java.applet.Applet
+</pre>
+The user manual explains all available options and shows more examples of this
+powerful configuration style.
+<p>
+<b>ProGuard</b> is fast. It only takes seconds to process programs and
+libraries of several megabytes. The results section presents actual figures
+for a number of applications.
+<p>
+<b>ProGuard</b> is a command-line tool with an optional graphical user
+interface. It also comes with plugins for Ant and for the J2ME Wireless
+Toolkit.
+<p>
+<p class="intro">
+Version 3.0 introduced bytecode optimization, reading and writing of nested
+jars, and a brand new Ant task. Please report any problems, so they can be
+fixed soon.
+</p>
+The following sections provide more detailed information:
+<ul>
+<li><a href="main.html">Main</a>: this overview page.
+<li><a href="results.html">Results</a>: some results obtained with
+ <b>ProGuard</b>, including timings and memory usage.
+<li><a href="FAQ.html">FAQ</a>: answers to some Frequently Asked Questions.
+<li><a href="manual/index.html">Manual</a>: the complete <b>ProGuard</b> user
+ manual, with examples and troubleshooting tips.
+<li><a href="quality.html">Quality</a>: a discussion of the (excellent) quality
+ of <b>ProGuard</b>'s code.
+<li><a href="screenshots.html">Screenshots</a>: some impressions of what <b>ProGuard</b> looks like.
+<li><a href="testimonials.html">Testimonials</a>: what users think of
+ <b>ProGuard</b>.
+<li><a href="license.html">License</a>: <b>ProGuard</b> is free, under a GPL
+ license.
+<li><a href="downloads.html">Downloads</a>: download the <b>ProGuard</b>
+ package yourself.
+<li><a href="feedback.html">Feedback</a>: tell me about your experiences, or
+ learn from others on our forums.
+<li><a href="acknowledgements.html">Acknowledgements</a>: people who have been
+ helpful.
+<li><a href="alternatives.html">Alternatives</a>: other Java obfuscators and
+ shrinking programs.
+</ul>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/ant.html b/docs/manual/ant.html
new file mode 100644
index 0000000..1043397
--- /dev/null
+++ b/docs/manual/ant.html
@@ -0,0 +1,417 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>Ant Task</title>
+</head>
+<body>
+
+<h2>Ant Task</h2>
+
+<b>ProGuard</b> can be run as a task in the Java-based build tool Ant (version
+1.6.0 or higher).
+<p>
+
+Before you can use the <code>proguard</code> task, you have to tell Ant about
+this new task. The easiest way is to add the following line to your
+<code>build.xml</code> file:
+<p>
+
+<pre>
+<taskdef resource="proguard/ant/task.properties"
+ classpath="/usr/local/java/proguard/lib/proguard.jar" />
+</pre>
+<p>
+
+Please make sure the class path is set correctly for your system.
+<p>
+
+There are three ways to configure the ProGuard task: using an external
+configuration file, using embedded ProGuard configuration options, and using
+the equivalent XML configuration tags. These three ways can be combined,
+depending on practical circumstances and personal preference.
+<p>
+
+<h3>1. An external ProGuard configuration file</h3>
+
+The simplest way to use the ProGuard task in an Ant build file is to keep
+your ProGuard configuration file, and include it from Ant. You can include
+your ProGuard configuration file by setting the <a
+href="#configuration"><code>configuration</code></a> attribute of your
+<code>proguard</code> task. Your ant build file will then look like this:
+<p>
+
+<pre>
+<taskdef resource="proguard/ant/task.properties"
+ classpath="/usr/local/java/proguard/lib/proguard.jar" />
+<proguard configuration="myconfigfile.pro"/>
+</pre>
+<p>
+
+This is a convenient option if you prefer ProGuard's configuration style over
+XML, if you want to keep your build file small, or if you have to share your
+configuration with developers who don't use Ant.
+<p>
+
+<h3>2. Embedded ProGuard configuration options</h3>
+
+Instead of keeping an external ProGuard configuration file, you can also copy
+the contents of the file into the nested text of the <code>proguard</code> task
+(the PCDATA area). Your Ant build file will then look like this:
+<p>
+
+<pre>
+<taskdef resource="proguard/ant/task.properties"
+ classpath="/usr/local/java/proguard/lib/proguard.jar" />
+<proguard>
+ -libraryjars ${java.home}/lib/rt.jar
+ -injars in.jar
+ -outjars out.jar
+
+ -keepclasseswithmembers public class * {
+ public static void main(java.lang.String[]);
+ }
+</proguard>
+</pre>
+<p>
+
+Some minor syntactical changes are required in order to conform with the XML
+standard.
+<p>
+
+Firstly, the <code>#</code> chararacter cannot be used for comments in an XML
+file. Comments must be enclosed by an opening <code><!--</code> and a
+closing <code>--></code>. All occurrences of the <code>#</code> chararacter
+can be removed.
+<p>
+
+Secondly, the use of <code><</code> and <code>></code> characters would
+upset the structure of the XML build file. Environment variables are now
+enclosed by an opening <code>${</code> and a closing <code>}</code>. This
+syntax also allows you to use Ant properties within the ProGuard
+configuration. Other occurrences of <code><</code> and <code>></code>
+have to be encoded as <code><</code> and <code>></code>.
+<p>
+
+<h3>3. XML configuration tags</h3>
+
+If you really prefer a full-blown XML configuration, you can replace the
+ProGuard configuration options by the equivalent XML configuration tags. The
+remainder of this page presents the supported tags. For a more extensive
+discussion of their meaning, please refer to the traditional <a
+href="usage.html">Usage</a> section.
+<p>
+
+<a name="proguard"> </a>
+<h2>Task Attributes and Nested Elements</h2>
+
+The <code><b><proguard></b></code> task and the
+<code><b><proguardconfiguration></b></code> task can have the following
+attributes (only for <code><proguard></code>) and nested
+elements:
+
+<dl>
+
+<dt><a name="configuration"><code><b>configuration</b></code></a> =
+ "<i>filename</i>"</dt>
+<dd>Read and merge options from the given ProGuard-style configuration
+ file.</dd>
+
+<dt><code><b>skipnonpubliclibraryclasses</b></code> = "<i>boolean</i>"
+ (default = true)</dt>
+<dd>Ignore non-public library classes.</dd>
+
+<dt><code><b>skipnonpubliclibraryclassmembers</b></code> = "<i>boolean</i>"
+ (default = true)</dt>
+<dd>Ignore package visible library class members.</dd>
+
+<dt><code><b>printseeds</b></code> = "<i>boolean or filename</i>"
+ (default = false)</dt>
+<dd>List classes and class members matched by the various <code>keep</code>
+ commands, to the standard output or to the given file.</dd>
+
+<dt><code><b>shrink</b></code> = "<i>boolean</i>" (default = true)</dt>
+<dd>Shrink the input class files.</dd>
+
+<dt><code><b>printusage</b></code> = "<i>boolean or filename</i>"
+ (default = false)</dt>
+<dd>List dead code of the input class files, to the standard output or to the
+ given file.</dd>
+
+<dt><code><b>optimize</b></code> = "<i>boolean</i>" (default = true)</dt>
+<dd>Optimize the input class files.</dd>
+
+<dt><code><b>allowaccessmodification</b></code> = "<i>boolean</i>"
+ (default = false)</dt>
+<dd>Allow the access modifiers of classes and class members to be modified,
+ while optimizing.</dd>
+
+<dt><code><b>obfuscate</b></code> = "<i>boolean</i>" (default = true)</dt>
+<dd>Obfuscate the input class files.</dd>
+
+<dt><code><b>printmapping</b></code> = "<i>boolean or filename</i>"
+ (default = false)</dt>
+<dd>Print the mapping from old names to new names for classes and class members
+ that have been renamed, to the standard output or to the given file.</dd>
+
+<dt><code><b>applymapping</b></code> = "<i>filename</i>"</dt>
+<dd>Reuse the given mapping, for incremental obfuscation.</dd>
+
+<dt><code><b>obfuscationdictionary</b></code> = "<i>filename</i>"</dt>
+<dd>Use the words in the given text file as obfuscated method names.</dd>
+
+<dt><code><b>overloadaggressively</b></code> = "<i>boolean</i>"
+ (default = false)</dt>
+<dd>Apply aggressive overloading while obfuscating.</dd>
+
+<dt><code><b>defaultpackage</b></code> = "<i>package_name</i>"</dt>
+<dd>Repackage all class files that are renamed into the single given
+ package.</dd>
+
+<dt><code><b>usemixedcaseclassnames</b></code> = "<i>boolean</i>"
+ (default = true)</dt>
+<dd>Generate mixed-case class names while obfuscating.</dd>
+
+<dt><code><b>renamesourcefileattribute</b></code> = "<i>string</i>"</dt>
+<dd>Put the given constant string in the <code>SourceFile</code>
+ attributes. The default is to keep the original string.</dd>
+
+<dt><code><b>verbose</b></code> = "<i>boolean</i>"
+ (default = false)</dt>
+<dd>Write out some more information during processing.</dd>
+
+<dt><code><b>note</b></code> = "<i>boolean</i>" (default = true)</dt>
+<dd>Print notes about class casts of variable dynamically created objects.</dd>
+
+<dt><code><b>warn</b></code> = "<i>boolean</i>" (default = true)</dt>
+<dd>Warn about unresolved references at all.</dd>
+
+<dt><code><b>ignorewarnings</b></code> = "<i>boolean</i>"
+ (default = false)</dt>
+<dd>Print warnings about unresolved references, but continue processing
+ anyhow. The default is not to ignore warnings. <i>Only use this option if
+ you know what you're doing!</i></dd>
+
+<dt><code><b>dump</b></code> = "<i>boolean or filename</i>"
+ (default = false)</dt>
+<dd>Write out the internal structure of the processed class files, to the
+ standard output or to the given file.</dd>
+
+<dt><code><b><injar</b></code>
+ <a href="#classpath"><i>class_path</i></a>
+ <code><b>/></b></code></dt>
+<dd>Specifies the program jars (or wars, ears, zips, or directories).</dd>
+
+<dt><code><b><outjar</b></code>
+ <a href="#classpath"><i>class_path</i></a>
+ <code><b>/></b></code></dt>
+<dd>Specifies the name of the output jars (or wars, ears, zips, or
+ directories).</dd>
+
+<dt><code><b><libraryjar</b></code>
+ <a href="#classpath"><i>class_path</i></a>
+ <code><b>/></b></code></dt>
+<dd>Specifies the library jars (or wars, ears, zips, or directories).</dd>
+
+<dt><code><b><keep</b></code>
+ <a href="#classspecification"><i>class_specification</i></a>
+ <code><b>></b></code>
+ <a href="#classmemberspecification"><i>class_member_specifications</i></a>
+ <code><b></keep></b></code></dt>
+<dd>Preserve the specified classes <i>and</i> class members.</dd>
+
+<dt><code><b><keepclassmembers</b></code>
+ <a href="#classspecification"><i>class_specification</i></a>
+ <code><b>></b></code>
+ <a href="#classmemberspecification"><i>class_member_specifications</i></a>
+ <code><b></keepclassmembers></b></code></dt>
+<dd>Preserve the specified class members, if their classes are preserved as
+ well.</dd>
+
+<dt><code><b><keepclasseswithmembers</b></code>
+ <a href="#classspecification"><i>class_specification</i></a>
+ <code><b>></b></code>
+ <a href="#classmemberspecification"><i>class_member_specifications</i></a>
+ <code><b></keepclasseswithmembers></b></code></dt>
+<dd>Preserve the specified classes <i>and</i> class members, if all of the
+ specified class members are present.</dd>
+
+<dt><code><b><keepnames</b></code>
+ <a href="#classspecification"><i>class_specification</i></a>
+ <code><b>></b></code>
+ <a href="#classmemberspecification"><i>class_member_specifications</i></a>
+ <code><b></keepnames></b></code></dt>
+<dd>Preserve the names of the specified classes <i>and</i> class members (if
+ they aren't removed in the shrinking step).</dd>
+
+<dt><code><b><keepclassmembernames</b></code>
+ <a href="#classspecification"><i>class_specification</i></a>
+ <code><b>></b></code>
+ <a href="#classmemberspecification"><i>class_member_specifications</i></a>
+ <code><b></keepclassmembernames></b></code></dt>
+<dd>Preserve the names of the specified class members (if they aren't removed
+ in the shrinking step).</dd>
+
+<dt><code><b><keepclasseswithmembernames</b></code>
+ <a href="#classspecification"><i>class_specification</i></a>
+ <code><b>></b></code>
+ <a href="#classmemberspecification"><i>class_member_specifications</i></a>
+ <code><b></keepclasseswithmembernames></b></code></dt>
+<dd>Preserve the names of the specified classes <i>and</i> class members, if
+ all of the specified class members are present (after the shrinking
+ step).</dd>
+
+<dt><code><b><assumenosideeffects</b></code>
+ <a href="#classspecification"><i>class_specification</i></a>
+ <code><b>></b></code>
+ <a href="#classmemberspecification"><i>class_member_specifications</i></a>
+ <code><b></assumenosideeffects></b></code></dt>
+<dd>Assume that the specified methods don't have any side effects, while
+ optimizing.</dd>
+
+<dt><code><b><keepattribute name = </b></code>"<i>attribute_name</i>"
+ <code><b>/></b></code></dt>
+<dd>Preserve the given optional Java bytecode attribute, with optional
+ wildcards. If no name is given, all attributes are preserved.</dd>
+
+<dt><code><b><configuration refid = </b></code>"<i>ref_id</i>"
+ <code><b>/></b></code></dt>
+<dd>Includes the configuration specified in the
+ <code><proguardconfiguration></code> task (or
+ <code><proguard></code> task) with the attribute <code>id</code> =
+ "<i>ref_id</i>". Note that only the nested elements of this configuration
+ are considered, not the attributes.</dd>
+
+</dl>
+
+<a name="classpath"> </a>
+<h2>Class Path Attributes and Nested Elements</h2>
+
+The jar tags are path tags, so they can have any of the path attributes (or
+nested elements). The most common attributes are:
+
+<dl>
+
+<dt><code><b>path</b></code> = "<i>path</i>"</dt>
+<dd>The names of the jars (or wars, ears, zips, or directories), separated by
+ the path separator.</dd>
+
+<dt><code><b>location</b></code> = "<i>name</i>" (or <code><b>file</b></code>
+ = "<i>name</i>", or <code><b>dir</b></code> = "<i>name</i>", or
+ <code><b>name</b></code> = "<i>name</i>")</dt>
+<dd>Alternatively, the name of a single jar (or war, ear, zip, or
+ directory).</dd>
+
+<dt><code><b>refid</b></code> = "<i>ref_id</i>"</dt>
+<dd>Alternatively, a reference to the path or file set with the attribute
+ <code>id</code> = "<i>ref_id</i>".</dd>
+
+</dl>
+
+In addition, the jar tags can have ProGuard-style filter attributes (as
+described in the section on <a href="usage.html#filters">Filters</a>):
+
+<dl>
+
+<dt><code><b>filter</b></code> = "<i>filter</i>"</dt>
+<dd>An optional filter for all class file names and resource file names that
+ are encountered.</dd>
+
+<dt><code><b>jarfilter</b></code> = "<i>jar_filter</i>"</dt>
+<dd>An optional filter for all jar names that are encountered.</dd>
+
+<dt><code><b>warfilter</b></code> = "<i>war_filter</i>"</dt>
+<dd>An optional filter for all war names that are encountered.</dd>
+
+<dt><code><b>earfilter</b></code> = "<i>ear_filter</i>"</dt>
+<dd>An optional filter for all ear names that are encountered.</dd>
+
+<dt><code><b>zipfilter</b></code> = "<i>zip_filter</i>"</dt>
+<dd>An optional filter for all zip names that are encountered.</dd>
+
+</dl>
+
+<a name="classspecification"> </a>
+<h2>Class Specification Attributes and Nested Elements</h2>
+
+The keep tags can have the following <i>class_specification</i> attributes and
+<i>class_member_specifications</i> nested elements:
+
+<dl>
+
+<dt><code><b>access</b></code> = "<i>access_modifiers</i>"</dt>
+<dd>The optional access modifiers of the class. Any space-separated list of
+ "public", "final", and "abstract", with optional negators "!".</dd>
+
+<dt><code><b>type</b></code> = "<i>type</i>"</dt>
+<dd>The optional type of the class: one of "class", "interface", or
+ "!interface".</dd>
+
+<dt><code><b>name</b></code> = "<i>class_name</i>"</dt>
+<dd>The optional fully qualified name of the class, with optional
+ wildcards.</dd>
+
+<dt><code><b>extends</b></code> = "<i>class_name</i>"</dt>
+<dd>The optional fully qualified name of the class the specified classes
+ must extend, with optional wildcards.</dd>
+
+<dt><code><b>implements</b></code> = "<i>class_name</i>"</dt>
+<dd>The optional fully qualified name of the class the specified classes
+ must implement, with optional wildcards.</dd>
+
+<dt><code><b><field</b></code>
+ <a href="#classmemberspecification"><i>class_member_specification</i></a>
+ <code><b>/></b></code></dt>
+<dd>Specifies a field.</dd>
+
+<dt><code><b><method</b></code>
+ <a href="#classmemberspecification"><i>class_member_specification</i></a>
+ <code><b>/></b></code></dt>
+<dd>Specifies a method.</dd>
+
+<dt><code><b><constructor</b></code>
+ <a href="#classmemberspecification"><i>class_member_specification</i></a>
+ <code><b>/></b></code></dt>
+<dd>Specifies a constructor.</dd>
+
+</dl>
+
+<a name="classmemberspecification"> </a>
+<h2>Class Member Specification Attributes</h2>
+
+The class member tags can have the following <i>class_member_specification</i>
+attributes:
+
+<dl>
+
+<dt><code><b>access</b></code> = "<i>access_modifiers</i>"</dt>
+<dd>The optional access modifiers of the class. Any space-separated list of
+ "public", "protected", "private", "static", etc., with optional negators
+ "!".</dd>
+
+<dt><code><b>type</b></code> = "<i>type</i>"</dt>
+<dd>The optional fully qualified type of the class member, with optional
+ wildcards. Not applicable for constructors, but required for methods for
+ which the <code>parameters</code> attribute is specified.</dd>
+
+<dt><code><b>name</b></code> = "<i>name</i>"</dt>
+<dd>The optional name of the class member, with optional wildcards. Not
+ applicable for constructors.</dd>
+
+<dt><code><b>parameters</b></code> = "<i>parameters</i>"</dt>
+<dd>The optional comma-separated list of fully qualified method parameters,
+ with optional wildcards. Not applicable for fields, but required for
+ constructors, and for methods for which the <code>type</code> attribute is
+ specified.</dd>
+
+</dl>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/examples.html b/docs/manual/examples.html
new file mode 100644
index 0000000..647ca03
--- /dev/null
+++ b/docs/manual/examples.html
@@ -0,0 +1,684 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Examples</title>
+</head>
+<body>
+
+<h2>Examples</h2>
+
+Some typical useful configurations:
+<ol>
+<li><a href="#application">A typical application</a>
+<li><a href="#applet">A typical applet</a>
+<li><a href="#midlet">A typical midlet</a>
+<li><a href="#applications">All possible applications in the input jars</a>
+<li><a href="#applets">All possible applets in the input jars</a>
+<li><a href="#midlets">All possible midlets in the input jars</a>
+<li><a href="#servlets">All possible servlets in the input jars</a>
+<li><a href="#library">Processing a library</a>
+<li><a href="#native">Processing native methods</a>
+<li><a href="#serializable">Processing serializable classes</a>
+<li><a href="#beans">Processing bean classes</a>
+<li><a href="#enumerations">Processing enumeration classes</a>
+<li><a href="#annotations">Processing annotations</a>
+<li><a href="#rmi">Processing RMI code</a>
+<li><a href="#stacktrace">Producing useful obfuscated stack traces</a>
+<li><a href="#multiple">Processing multiple applications at once</a>
+<li><a href="#incremental">Incremental obfuscation</a>
+<li><a href="#deadcode">Finding dead code</a>
+<li><a href="#structure">Printing out the internal structure of class files</a>
+</ol>
+
+<a name="application"> </a>
+<h3>A typical application</h3>
+To shrink, optimize, and obfuscate the ProGuard application itself, one would
+typically create a configuration file <code>proguard.pro</code> and then type:
+<pre>
+java -jar proguard.jar @proguard.pro
+</pre>
+<p>
+
+The configuration file would contain the following options:
+<pre>
+-injars proguard.jar
+-outjars proguard_out.jar
+-libraryjars <java.home>/lib/rt.jar
+-printmapping proguard.map
+-overloadaggressively
+-defaultpackage ''
+-allowaccessmodification
+
+-keep public class proguard.ProGuard {
+ public static void main(java.lang.String[]);
+}
+</pre>
+<p>
+Note the use of the <code><java.home></code> system property; it is
+replaced automatically.
+<p>
+Also note that the type names are fully specified:
+<code>proguard.ProGuard</code> and <code>java.lang.String[]</code>.
+<p>
+The access modifiers <code>public</code> and <code>static</code> are not
+really required in this case, since we know a priori that the specified class
+and method have the proper access flags. It just looks more familiar this way.
+<p>
+We're using the <code>-overloadaggressively</code>,
+<code>-defaultpackage</code>, and <code>-allowaccessmodification</code>
+options to shave off some extra bytes, but we could leave them out as well.
+The <code>-defaultpackage</code> directive moves all classes to the given
+package, in this case the root package. Only <code>proguard.ProGuard</code>
+keeps its original name.
+<p>
+We're writing out an obfuscation mapping file with <code>-printmapping</code>,
+for de-obfuscating any stack traces later on, or for incremental obfuscation of
+extensions.
+<p>
+In general, you might need a few additional directives for processing <a
+href="#native">native methods</a>, <a href="#enumerations">enumerations</a>,
+<a href="#serializable">serializable classes</a>, or <a href="#beans">bean
+classes</a>. For processing 'simple' applications like ProGuard, that is not
+required.
+
+<a name="applet"> </a>
+<h3>A typical applet</h3>
+These options shrink, optimize, and obfuscate the applet
+<code>mypackage.MyApplet</code>:
+<pre>
+-injars in.jar
+-outjars out.jar
+-libraryjars <java.home>/lib/rt.jar
+
+-keep public class mypackage.MyApplet
+</pre>
+<p>
+The typical applet methods will be preserved automatically, since
+<code>mypackage.MyApplet</code> is an extension of the <code>Applet</code>
+class in the library <code>rt.jar</code>.
+<p>
+If applicable, you should add directives for processing <a
+href="#native">native methods</a>, <a href="#enumerations">enumerations</a>,
+<a href="#serializable">serializable classes</a>, or <a href="#beans">bean
+classes</a>.
+
+<a name="midlet"> </a>
+<h3>A typical midlet</h3>
+These options shrink, optimize, and obfuscate the J2ME midlet
+<code>mypackage.MyMIDlet</code>:
+<pre>
+-injars in.jar
+-outjars out.jar
+-libraryjars /usr/local/java/wtk2.1/lib/midpapi20.jar
+-libraryjars /usr/local/java/wtk2.1/lib/cldcapi11.jar
+-overloadaggressively
+-defaultpackage ''
+-allowaccessmodification
+
+-keep public class mypackage.MyMIDlet
+</pre>
+<p>
+Note how we're now targeting the J2ME run-time environment of
+<code>midpapi20.jar</code> and <code>cldcapi11.jar</code>, instead of the J2SE
+run-time environment <code>rt.jar</code>. You can target other J2ME
+environments by picking the appropriate jars.
+<p>
+The typical midlet methods will be preserved automatically, since
+<code>mypackage.MyMIDlet</code> is an extension of the <code>MIDlet</code>
+class in the library <code>midpapi20.jar</code>.
+<p>
+If applicable, you should add directives for processing <a
+href="#native">native methods</a>, <a href="#enumerations">enumerations</a>,
+<a href="#serializable">serializable classes</a>, or <a href="#beans">bean
+classes</a>.
+<p>
+You must preverify your midlets <i>after</i> having processed them, using
+J2ME's <code>preverify</code> tool. Because this tool unpacks your processed
+jars, you should use ProGuard's <code>-dontusemixedcaseclassnames</code>
+option on platforms with case-insensitive filing systems, such as Windows.
+<p>
+Please note the in-depth article <a
+href="http://developers.sun.com/techtopics/mobility/midp/ttips/proguard/">"Obfuscating
+MIDlet Suites with ProGuard"</a> at <a
+href="http://developers.sun.com/">developers.sun.com</a>.
+
+<a name="applications"> </a>
+<h3>All possible applications in the input jars</h3>
+These options shrink, optimize, and obfuscate all public applications in
+<code>in.jar</code>:
+<pre>
+-injars in.jar
+-outjars out.jar
+-libraryjars <java.home>/lib/rt.jar
+-printseeds
+
+-keepclasseswithmembers public class * {
+ public static void main(java.lang.String[]);
+}
+</pre>
+<p>
+Note the use of <code>-keepclasseswithmembers</code>. We don't want to preserve
+all classes, just all classes that have main methods, and those methods.
+<p>
+The <code>-printseeds</code> option prints out which classes exactly will
+be preserved, so we know for sure we're getting what we want.
+<p>
+If applicable, you should add directives for processing <a
+href="#native">native methods</a>, <a href="#enumerations">enumerations</a>,
+<a href="#serializable">serializable classes</a>, or <a href="#beans">bean
+classes</a>.
+
+<a name="applets"> </a>
+<h3>All possible applets in the input jars</h3>
+These options shrink, optimize, and obfuscate all public applets in
+<code>in.jar</code>:
+<pre>
+-injars in.jar
+-outjars out.jar
+-libraryjars <java.home>/lib/rt.jar
+-printseeds
+
+-keep public class * extends java.applet.Applet
+</pre>
+<p>
+We're simply keeping all classes that extend the <code>Applet</code> class.
+<p>
+Again, the <code>-printseeds</code> option prints out which applets exactly
+will be preserved.
+<p>
+If applicable, you should add directives for processing <a
+href="#native">native methods</a>, <a href="#enumerations">enumerations</a>,
+<a href="#serializable">serializable classes</a>, or <a href="#beans">bean
+classes</a>.
+
+<a name="midlets"> </a>
+<h3>All possible midlets in the input jars</h3>
+These options shrink, optimize, and obfuscate all public J2ME midlets in
+<code>in.jar</code>:
+<pre>
+-injars in.jar
+-outjars out.jar
+-libraryjars /usr/local/java/wtk2.1/lib/midpapi20.jar
+-libraryjars /usr/local/java/wtk2.1/lib/cldcapi11.jar
+-overloadaggressively
+-defaultpackage ''
+-allowaccessmodification
+-printseeds
+
+-keep public class * extends javax.microedition.midlet.MIDlet
+</pre>
+<p>
+We're simply keeping all classes that extend the <code>MIDlet</code> class.
+<p>
+And again, the <code>-printseeds</code> option prints out which midlets exactly
+will be preserved.
+<p>
+If applicable, you should add directives for processing <a
+href="#native">native methods</a>, <a href="#enumerations">enumerations</a>,
+<a href="#serializable">serializable classes</a>, or <a href="#beans">bean
+classes</a>.
+<p>
+You must preverify your midlets <i>after</i> having processed them, using
+J2ME's <code>preverify</code> tool. Because this tool unpacks your processed
+jars, you should use ProGuard's <code>-dontusemixedcaseclassnames</code>
+option on platforms with case-insensitive filing systems, such as Windows.
+
+<a name="servlets"> </a>
+<h3>All possible servlets in the input jars</h3>
+These options shrink, optimize, and obfuscate all public servlets in
+<code>in.jar</code>:
+<pre>
+-injars in.jar
+-outjars out.jar
+-libraryjars <java.home>/lib/rt.jar
+-libraryjars /usr/local/java/servlet/servlet.jar
+-printseeds
+
+-keep public class * implements javax.servlet.Servlet
+</pre>
+<p>
+Keeping all servlets is very similar to keeping all applets. The servlet API
+is not part of the standard run-time jar, so we're specifying it as a library.
+Don't forget to use the right path name.
+<p>
+We're then keeping all classes that implement the <code>Servlet</code>
+interface. We're using the <code>implements</code> keyword because it looks
+more familiar in this context, but it is equivalent to <code>extends</code>,
+as far as ProGuard is concerned.
+<p>
+And again, the <code>-printseeds</code> option prints out which servlets
+exactly will be preserved.
+<p>
+If applicable, you should add directives for processing <a
+href="#native">native methods</a>, <a href="#enumerations">enumerations</a>,
+<a href="#serializable">serializable classes</a>, or <a href="#beans">bean
+classes</a>.
+
+<a name="library"> </a>
+<h3>Processing a library</h3>
+These options shrink, optimize, and obfuscate an entire library, keeping all
+public and protected classes and class members, native method names, and
+serialization code:
+<pre>
+-injars in.jar
+-outjars out.jar
+-libraryjars <java.home>/lib/rt.jar
+-printmapping out.map
+
+-renamesourcefileattribute SourceFile
+-keepattributes InnerClasses,SourceFile,LineNumberTable,Deprecated,
+ Signature,*Annotation*,EnclosingMethod
+
+-keep public class * {
+ public protected *;
+}
+
+-keepclassmembernames class * {
+ java.lang.Class class$(java.lang.String);
+ java.lang.Class class$(java.lang.String, boolean);
+}
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclassmembers class * extends java.lang.Enum {
+ public **[] values();
+}
+
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+</pre>
+<p>
+This configuration should preserve everything we'll ever want to access in the
+library. Only if there are any other non-public classes or methods that are
+invoked dynamically, they should be specified using additional
+<code>-keep</code> directives.
+<p>
+The <code>-keepclassmembernames</code> directive for the <code>class$</code>
+methods is not strictly necessary. These methods are inserted by the
+<code>javac</code> compiler and the <code>jikes</code> compiler respectively,
+to implement the <code>.class</code> construct. ProGuard will automatically
+detect them and deal with them, even when their names have been obfuscated.
+However, older versions of ProGuard and other obfuscators may rely on the
+original method names. It may therefore be helpful to preserve them, in case
+these other obfuscators are ever used for further obfuscation of the library.
+<p>
+We've added some directives for keeping the "Deprecated" attribute, for <a
+href="#stacktrace">useful stack traces</a>, for <a href="#native">native
+methods</a>, for <a href="#enumerations">enumerations</a>, for <a
+href="#serializable">serializable classes</a>, and for <a
+href="#annotations">annotations</a>, which are all discussed in their
+respective examples.
+<p>
+The "InnerClasses" attribute (or more precisely, its source name part) has to
+be preserved as well, for any inner classes that can be referenced from
+outside the library. The <code>javac</code> compiler would be unable to find
+the inner classes otherwise.
+<p>
+The "Signature" attribute is required to be able to access generic types when
+compiling in JDK 5.0.
+
+<a name="native"> </a>
+<h3>Processing native methods</h3>
+If your application, applet, servlet, library, etc., contains native methods,
+you'll want to preserve their names and their classes' names, so they can
+still be linked to the native library. The following additional option will
+ensure that:
+<pre>
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+</pre>
+<p>
+Note the use of <code>-keepclasseswithmembernames</code>. We don't want to
+preserve all classes or all native methods; we just want to keep the relevant
+names from being obfuscated.
+
+<a name="enumerations"> </a>
+<h3>Processing enumeration classes</h3>
+If your application, applet, servlet, library, etc., contains enumeration
+classes, you'll have to preserve a special method. Enumerations were
+introduced in JDK 5.0. The <code>javac</code> compiler will translate
+enumerations into classes with a special structure. The classes contain
+implementations of a method that the run-time environment accesses by
+introspection (Isn't that just grand? Introspection is the self-modifying code
+of a new generation). You'll therefore have to specify it explicitly:
+<pre>
+-keepclassmembers class * extends java.lang.Enum {
+ public **[] values();
+}
+</pre>
+
+<a name="serializable"> </a>
+<h3>Processing serializable classes</h3>
+More complex applications, applets, servlets, libraries, etc., may contain
+classes that are serialized. Depending on the way in which they are used, they
+may require special attention:
+<ul>
+
+<li>Often, serialization is simply a means of transporting data, without
+ long-term storage. Classes that are shrunk and obfuscated should then
+ continue to function fine with the following additional directives:
+
+<pre>
+-keepclassmembers class * implements java.io.Serializable {
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+</pre>
+<p>
+
+ The <code>-keepclassmembers</code> option makes sure that any
+ serialization methods are kept. By using this directive instead of the
+ basic <code>-keep</code> directive, we're not forcing preservation of
+ <i>all</i> serializable classes, just preservation of the listed members
+ of classes that are actually used.
+ <p>
+
+<li>Sometimes, the serialized data are stored, and read back later into newer
+ versions of the serializable classes. One then has to take care the classes
+ remain compatible with their unprocessed versions and with future
+ processed versions. In such cases, the relevant classes will most likely
+ have <code>serialVersionUID</code> fields. The following directives should
+ then be sufficient to ensure compatibility over time:
+
+<pre>
+-keepnames class * implements java.io.Serializable
+
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ !static !transient <fields>;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+</pre>
+<p>
+
+ The <code>serialVersionUID</code> line makes sure that field is preserved.
+ The <code><fields></code> line preserves all non-static,
+ non-transient fields, with their original names. The introspection of the
+ serialization process and the de-serialization process will then find
+ consistent names.
+
+<li>Occasionally, the serialized data have to remain compatible, but the
+ classes involved lack <code>serialVersionUID</code> fields. I imagine the
+ original code will then be hard to maintain, since the serial version UID
+ is then computed from a list of features the serializable class. Changing
+ the class ever so slightly may change the computed serial version UID. The
+ list of features is specified in the chapter on <a
+ href="http://java.sun.com/j2se/1.4/docs/guide/serialization/spec/class.html#wp4100">Stream
+ Unique Identifiers</a> of Sun's <a
+ href="http://java.sun.com/j2se/1.4/docs/guide/serialization/">Object
+ Serialization Guide</a>. The following directives should at least
+ partially ensure compatibility with the original classes
+
+<pre>
+-keepnames class * implements java.io.Serializable
+
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ !static !transient <fields>;
+ !private <fields>;
+ !private <methods>;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+</pre>
+<p>
+
+ The new directives force preservation of the elements involved in the UID
+ computation. In addition, the user will have to manually specify all
+ interfaces of the serializable classes (using something like "<code>-keep
+ interface MyInterface</code>"), since these names are also used when
+ computing the UID. A fast but sub-optimal alternative would be simply
+ keeping all interfaces with "<code>-keep interface *</code>".
+
+</ul>
+<p>
+
+Note that the above directives may preserve more classes and class members
+than strictly necessary. For instance, a large number of classes may implement
+the <code>Serialization</code> interface, yet only a small number may actually
+ever be serialized. Knowing your application and tuning the configuration will
+often produce more compact results.
+
+<a name="beans"> </a>
+<h3>Processing bean classes</h3>
+If your application, applet, servlet, library, etc., uses extensive
+introspection on bean classes to find bean editor classes, or getter and
+setter methods, then configuration may become laborious. There's not much else
+you can do than making sure the bean class names, or the getter and setter
+names don't change. For instance:
+<pre>
+-keep public class mypackage.MyBean {
+ public void setMyProperty(int);
+ public int getMyProperty();
+}
+
+-keep public class mypackage.MyBeanEditor
+</pre>
+<p>
+If there are too many elements to list explicitly, wildcards in class names
+and method signatures might be helpful. This example encompasses a wide range
+of setters and getters:
+<pre>
+-keep class mybeans.** {
+ void set*(%);
+ void set*(**);
+ void set*(%[]);
+ void set*(**[]);
+ void set*(int, %);
+ void set*(int, **);
+
+ % get*();
+ ** get*();
+ %[] get*();
+ **[] get*();
+ % get*(int);
+ ** get*(int);
+}
+</pre>
+<p>
+The '<code>%</code>' wildcard matches any primitive type, while the
+'<code>**</code>' wildcard matches any class name. Array types have to be
+specified explicitly. This results in a short list of alternative method
+signatures.
+
+<a name="annotations"> </a>
+<h3>Processing annotations</h3>
+As of JDK 5.0, class files can contain annotations. Annotations are
+represented by attributes that have no direct effect on the execution of the
+code. However, their values can be retrieved through introspection, allowing
+developers to adapt the execution behavior accordingly. By default, ProGuard
+treats annotation attributes as optional, and removes them in the obfuscation
+step. If they are required, you'll have to specify this explicitly:
+<pre>
+-keepattributes *Annotation*
+</pre>
+<p>
+For brevity, we're specifying a wildcarded attribute name, which will match
+<code>RuntimeVisibleAnnotations</code>,
+<code>RuntimeInvisibleAnnotations</code>,
+<code>RuntimeVisibleParameterAnnotations</code>,
+<code>RuntimeInvisibleParameterAnnotations</code>, and
+<code>AnnotationDefault</code>. Depending on the purpose of the processed
+code, you could refine this selection, for instance not keeping the run-time
+invisible annotations (which are only used at compile-time).
+<p>
+Some code may make further use of introspection to figure out the enclosing
+methods of anonymous inner classes. In that case, the corresponding attribute
+will have to be preserved as well:
+<pre>
+-keepattributes EnclosingMethod
+</pre>
+
+<a name="rmi"> </a>
+<h3>Processing RMI code</h3>
+Reportedly, the easiest way to handle RMI code is to process the code with
+ProGuard first and then invoke the <code>rmic</code> tool. If that is not
+possible, you may want to try something like this:
+<pre>
+-keep interface * extends java.rmi.Remote {
+ <methods>;
+}
+
+-keep class * implements java.rmi.Remote {
+ <init>(java.rmi.activation.ActivationID, java.rmi.MarshalledObject);
+}
+</pre>
+<p>
+The first directive keeps all your Remote interfaces and their methods. The
+second one keeps all the implementations, along with their particular RMI
+constructors, if any.
+
+<a name="stacktrace"> </a>
+<h3>Producing useful obfuscated stack traces</h3>
+These options let obfuscated applications or libraries produce stack traces
+that can still be deciphered later on:
+<pre>
+-printmapping out.map
+
+-renamesourcefileattribute SourceFile
+-keepattributes SourceFile,LineNumberTable
+</pre>
+<p>
+We're keeping all source file attributes, but we're replacing their values by
+the string "SourceFile". We could use any string. This string is already
+present in all class files, so it doesn't take up any extra space. If you're
+working with J++, you'll want to keep the "SourceDir" attribute as well.
+<p>
+We're also keeping the line number tables of all methods.
+<p>
+Whenever both of these attributes are present, the Java run-time environment
+will include line number information when printing out exception stack traces.
+<p>
+The information will only be useful if we can map the obfuscated names back to
+their original names, so we're saving the mapping to a file
+<code>out.map</code>. The information can then be used by the <a
+href="retrace/index.html">ReTrace</a> tool to restore the original stack trace.
+
+<a name="multiple"> </a>
+<h3>Processing multiple applications at once</h3>
+You can process several independent applications (or applets, midlets,...) in
+one go, in order to save time and effort. ProGuard's input and output handling
+offers various ways to keep the output nicely structured.
+<p>
+The easiest way is to specify your input jars (and/or wars, ears, zips, and
+directories) and a single output directory. ProGuard will then reconstruct the
+input in this directory, using the original jar names. For example, showing
+just the input and output options:
+<pre>
+-injars application1.jar
+-injars application2.jar
+-injars application3.jar
+-injars application.war
+-outjars processed_applications
+</pre>
+<p>
+After processing, the directory <code>processed_applications</code> will
+contain the processed application jars and war, with their original names.
+<p>
+If you want explicit control over the output names, or if you want to combine
+input jars (and/or wars, ears, zips, or directories) into output jars (and/or
+wars, ears, zips, or directories), you can group the <code>-injars</code> and
+<code>-outjars</code> options. For example:
+<pre>
+-injars application1.jar
+-injars application2.jar
+-injars application3.jar
+-outjars application_out1.war
+
+-injars application.war
+-outjars application_out2.war
+</pre>
+<p>
+This configuration creates two wars: one containing all processed application
+jars, and one containing the processed contents of the input war.
+<p>
+Note that ProGuard will try to package output archives in a sensible way,
+reconstructing the input entries as much as required. If you want even greater
+control, you can add filters to the input and the output, filtering out zips,
+ears, wars, jars, and/or ordinary files.
+
+<a name="incremental"> </a>
+<h3>Incremental obfuscation</h3>
+After having <a href="#application">processed an application</a>, e.g.
+ProGuard itself, you can still incrementally add other pieces of code that
+depend on it, e.g. the ProGuard GUI:
+<pre>
+-injars proguardgui.jar
+-outjars proguardgui_out.jar
+-libraryjars <java.home>/lib/rt.jar
+-libraryjars proguard.jar
+-applymapping proguard.map
+
+-keep public class proguard.gui.ProGuardGUI {
+ public static void main(java.lang.String[]);
+}
+</pre>
+<p>
+We're reading both unprocessed jars: the new one as the input jar, and the old
+one as a library jar. The <code>-applymapping</code> option then makes sure
+the ProGuard part of the code gets the previously produced obfuscation
+mapping. The final application will consist of the obfuscated ProGuard jar and
+the additional obfuscated GUI jar.
+
+<a name="deadcode"> </a>
+<h3>Finding dead code</h3>
+These options list unused fields and methods in the application
+<code>mypackage.MyApplication</code>:
+<pre>
+-injars in.jar
+-libraryjars <java.home>/lib/rt.jar
+-dontoptimize
+-dontobfuscate
+-printusage
+
+-keep public class mypackage.MyApplication {
+ public static void main(java.lang.String[]);
+}
+</pre>
+<p>
+We're not specifying an output jar, just printing out some results.
+<p>
+We're saving a little bit of time by skipping the optimization and obfuscation
+steps.
+
+<a name="structure"> </a>
+<h3>Printing out the internal structure of class files</h3>
+These options print out the internal structure of all class files in the input
+jar:
+<pre>
+-injars in.jar
+-dontshrink
+-dontoptimize
+-dontobfuscate
+-dump
+</pre>
+<p>
+Note how we don't need to specify the Java run-time jar, because we're not
+processing the input jar at all.
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/gui.html b/docs/manual/gui.html
new file mode 100644
index 0000000..7880b6e
--- /dev/null
+++ b/docs/manual/gui.html
@@ -0,0 +1,418 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard GUI</title>
+</head>
+<body>
+
+<h2>Graphical User Interface</h2>
+
+To run the ProGuard graphical user interface, just type:
+<p class="code">
+<code><b>java -jar proguardgui.jar</b> [-nosplash] </code>[<i>configuration_file</i>]
+</p>
+The GUI will pop up in a window. With the <code>-nosplash</code> option, you
+can switch off the short opening animation. If you have specified a ProGuard
+configuration file, it will be loaded. The GUI works like a wizard. You can
+edit the configuration and execute ProGuard through a few tabs:
+<p>
+
+<table cellspacing="5" cellpadding="5">
+<tr><td class="button"><a href="#proguard">ProGuard</a></td>
+ <td>Load an existing configuration file.</td></tr>
+<tr><td class="button"><a href="#inputoutput">Input/Output</a></td>
+ <td>Specify the program jars and library jars.</td></tr>
+<tr><td class="button"><a href="#shrinking">Shrinking</a></td>
+ <td>Specify the shrinking options.</td></tr>
+<tr><td class="button"><a href="#obfuscation">Obfuscation</a></td>
+ <td>Specify the obfuscation options.</td></tr>
+<tr><td class="button"><a href="#optimization">Optimization</a></td>
+ <td>Specify the optimization options.</td></tr>
+<tr><td class="button"><a href="#information">Information</a></td>
+ <td>Specify some options to get information.</td></tr>
+<tr><td class="button"><a href="#process">Process</a></td>
+ <td>View and save the resulting configuration, and run ProGuard.</td></tr>
+</table>
+<p>
+
+In addition, there is a tab to execute ReTrace interactively:
+<p>
+
+<table cellspacing="5" cellpadding="5">
+<tr><td class="button"><a href="#retrace">ReTrace</a></td>
+ <td>Set up and run ReTrace, to de-obfuscate stack traces.</td></tr>
+</table>
+<p>
+
+You can freely toggle between the tabs by means of the buttons on the left-hand
+side of the window, or by means of the <b>Previous</b> and <b>Next</b> buttons
+at the bottom of the tabs.
+<p>
+
+<a name="proguard"> </a>
+<h2>The ProGuard Tab</h2>
+
+The <i>ProGuard</i> tab presents a welcome message and one important button at
+the bottom:
+<p>
+
+<table cellspacing="5" cellpadding="5">
+<tr><td class="button">Load configuration...</td>
+ <td>opens a file chooser to load an existing ProGuard configuration
+ file.</td></tr>
+</table>
+<p>
+
+If you don't want to load an existing configuration, you can just continue
+creating a new configuration from scratch.
+<p>
+
+<a name="inputoutput"> </a>
+<h2>The Input/Output Tab</h2>
+
+The <i>Input/Output</i> tab contains two lists, respectively to specify the
+program jars (or wars, ears, zips, or directories), and the library jars (or
+wars, ears, zips, or directories).
+
+<ul>
+<li>The list of program jars contains input entries and output entries. Input
+ entries contain the class files and resource files to be processed. Output
+ entries specify the destinations to which the processed results will be
+ written. They are preceded by arrows, to distinguish them from input
+ entries. The results of each consecutive list of input entries will be
+ written to the subsequent consecutive list of output entries.
+
+<li>The library jars are not copied to the output jars; they contain class
+ files that are used by class files in the program jars and that are
+ necessary for correct processing. This list typically at least contains the
+ targeted Java runtime jar.
+</ul>
+<p>
+
+Each of these lists can be edited by means of a couple of buttons on the
+right-hand side:
+<p>
+
+<table cellspacing="5" cellpadding="5">
+<tr><td class="button">Add input...</td> <td>opens a file chooser to add an
+ input entry to the list of program jars.</td></tr>
+<tr><td class="button">Add output...</td> <td>opens a file chooser to add an
+ output entry to the list of program jars.</td></tr>
+<tr><td class="button">Add...</td>
+ <td>opens a file chooser to add an entry to the list of library
+ jars.</td></tr>
+<tr><td class="button">Edit...</td>
+ <td>opens a file chooser to edit the selected entry in the list.</td></tr>
+<tr><td class="button">Filter...</td>
+ <td>opens a text entry field to add or edit the filters of the selected
+ entries in the list.</td></tr>
+<tr><td class="button">Remove</td>
+ <td>removes the selected entries from the list.</td></tr>
+<tr><td class="button">Move up</td>
+ <td>moves the selected entries one position up the list.</td></tr>
+<tr><td class="button">Move down</td>
+ <td>moves the selected entries one position down the list.</td></tr>
+<tr><td class="button">Move to libraries</td>
+ <td>moves the selected entries in the list of program jars to the list of
+ library jars.</td></tr>
+<tr><td class="button">Move to program</td>
+ <td>moves the selected entries in the list of library jars to the list of
+ program jars.</td></tr>
+</table>
+<p>
+
+Filters allow to filter files based on their names. One can specify filters
+for class file names and resource file names, for jar file names, for war file
+names, for ear file names, and for zip file names. Multiple entries in the
+program list only make sense when combined with filters; each output file is
+written to the first entry with a matching filter.
+<p>
+
+Input entries that are currently not readable are colored red.
+<p>
+
+The order of the entries in each list may matter, as the first occurrence of
+any duplicate entries gets precedence, just as in conventional class paths.
+<p>
+
+Corresponding configuration options:
+<ul type="none">
+<li>-<a href="usage.html#injars">injars</a>
+<li>-<a href="usage.html#outjars">outjars</a>
+<li>-<a href="usage.html#libraryjars">libraryjars</a>
+<li><a href="usage.html#classpath"><i>class_path</i></a>
+<li><a href="usage.html#filters"><i>filters</i></a>
+</ul>
+<p>
+
+<a name="shrinking"> </a>
+<h2>The Shrinking Tab</h2>
+
+The <i>Shrinking</i> tab presents a number of options that affect the
+shrinking step. The basic options are followed by a few lists of classes and
+class members (fields and methods) that must be protected from shrinking (and
+implicitly from obfuscation as well).
+<p>
+
+The fixed lists contain predefined entries that are typically useful for many
+applications. Each of these entries can be toggled by means of a check box.
+The text field following each entry allows to constrain the applicable classes
+by means of a comma-separated list of wildcarded, fully-qualified class
+names. The default is "*", which means that all input classes of the
+corresponding type are considered.
+<p>
+
+For example, checking the <b>Applications</b> entry and filling in
+"myapplications.**" after it would mean: keep all classes that have a main
+method in the "myapplications" package and any of its subpackages.
+<p>
+
+The variable list at the bottom allows to define additional entries
+yourself. The list can be edited by means of a couple of buttons on the
+right-hand side:
+<p>
+
+<table cellspacing="5" cellpadding="5">
+<tr><td class="button">Add...</td>
+ <td>opens a window to add a new entry to the list.</td></tr>
+<tr><td class="button">Edit...</td>
+ <td>opens a window to edit the selected entry in the list.</td></tr>
+<tr><td class="button">Remove</td>
+ <td>removes the selected entries from the list.</td></tr>
+<tr><td class="button">Move up</td>
+ <td>moves the selected entries one position up the list.</td></tr>
+<tr><td class="button">Move down</td>
+ <td>moves the selected entries one position down the list.</td></tr>
+</table>
+<p>
+
+The interface windows allow to specify classes, fields, and methods. They
+contain text fields and check boxes to constrain these items. They have
+<b>Ok</b> and <b>Cancel</b> buttons to apply or to cancel the operation.
+<p>
+
+For example, your application may be creating some classes dynamically using
+<code>Class.forName</code>. You should then specify them here, so they are kept
+by their original names. Press the <b>Add...</b> button to open the class
+window. Fill out the fully-qualified class name in the <b>Code</b> text field,
+and press the <b>Ok</b> button. Repeat this for all required classes. Wildcards
+can be helpful to specify a large number of related classes in one go. If you
+want to specify all implementations of a certain interface, fill out the
+fully qualified interface name in the <b>Extends/implements class</b> instead.
+<p>
+
+For more advanced settings, it is advisable to become familiar with ProGuard's
+configuration options through the <a href="usage.html">Usage section</a> and
+the <a href="examples.html">Examples section</a>. We'll suffice with a brief
+overview of the three dialogs provided by the GUI.
+<p>
+
+The <i>keep class</i> dialog appears when adding or editing new special keep
+entries. It has text fields and selections for specifying and constraining
+classes and class members to keep.
+
+<ul>
+<li>The <b>Comments</b> text field allows to add optional comments to this
+ entry. The comments will identify the entry in the list and they will
+ appear as comments in the configuration file.
+
+<li>The <b>Keep</b> selection allows to specify whether you want to protect
+ the specified classes and their specified class members, or just the
+ specified class members from the specified classes, or the specified
+ classes and the specified class members, if the class members are present.
+ Note that class members will only be protected if they are explicitly
+ specified, even if only by means of a wildcard.
+
+<li>The <b>Access</b> selections allows to specify constraints on the class or
+ classes, based on their access modifiers.
+
+<li>The <b>Class</b> text field takes the fully-qualified name of the class or
+ classes. The class name can contain wildcards.
+
+<li>The <b>Extends/implements class</b> text field takes the fully-qualified
+ name of the class or interface that the above classes must extend.
+
+<li>The <b>Class members</b> list allows to specify a list of fields and
+ methods to keep. It can be edited by means of a list of buttons on the
+ right-hand side.
+</ul>
+<p>
+
+The <i>keep field</i> dialog appears when adding or editing fields within the
+above dialog. It has text fields and selections for specifying and constraining
+fields to keep.
+
+<ul>
+<li>The <b>Access</b> selections allows to specify constraints on the field or
+ fields, based on their access modifiers.
+
+<li>The <b>Return type</b> text field takes the fully-qualified type of the
+ field or fields. The type can contain wild-cards if it is a class name.
+
+<li>The <b>Name</b> text field takes the name of the field or fields. The field
+ name can contain wildcards.
+</ul>
+<p>
+
+Similarly, the <i>keep method</i> dialog appears when adding or editing methods
+within the keep class dialog. It has text fields and selections for specifying
+and constraining methods to keep.
+
+<ul>
+<li>The <b>Access</b> selections allows to specify constraints on the method or
+ methods, based on their access modifiers.
+
+<li>The <b>Return type</b> text field takes the fully-qualified type of the method or methods. The type can contain wild-cards if it is a class name.
+
+<li>The <b>Name</b> text field takes the name of the method or methods. The
+ method name can contain wildcards.
+
+<li>The <b>Arguments</b> text field takes the comma-separated list of
+ fully-qualified method arguments. Each of these arguments can contain
+ wildcards, if it is a class name.
+</ul>
+<p>
+
+Corresponding configuration options:
+<ul type="none">
+<li>-<a href="usage.html#dontshrink">dontshrink</a>
+<li>-<a href="usage.html#printusage">printusage</a>
+<li>-<a href="usage.html#keep">keep</a>
+<li>-<a href="usage.html#keepclassmembers">keepclassmembers</a>
+<li>-<a href="usage.html#keepclasseswithmembers">keepclasseswithmembers</a>
+</ul>
+<p>
+
+<a name="obfuscation"> </a>
+<h2>The Obfuscation Tab</h2>
+
+The <i>Obfuscation</i> tab presents a number of options that affect the
+obfuscation step. The basic options are followed by a few lists of classes and
+class members (fields and methods) that must be protected from obfuscation
+(but not necessarily from shrinking).
+<p>
+
+The lists are manipulated in the same way as in the <a
+href="#shrinking">Shrinking Tab</a>.
+<p>
+
+Corresponding configuration options:
+<ul type="none">
+<li>-<a href="usage.html#dontobfuscate">dontobfuscate</a>
+<li>-<a href="usage.html#printmapping">printmapping</a>
+<li>-<a href="usage.html#applymapping">applymapping</a>
+<li>-<a href="usage.html#obfuscationdictionary">obfuscationdictionary</a>
+<li>-<a href="usage.html#overloadaggressively">overloadaggressively</a>
+<li>-<a href="usage.html#defaultpackage">defaultpackage</a>
+<li>-<a href="usage.html#dontusemixedcaseclassnames">dontusemixedcaseclassnames</a>
+<li>-<a href="usage.html#keepattributes">keepattributes</a>
+<li>-<a href="usage.html#renamesourcefileattribute">renamesourcefileattribute</a>
+<li>-<a href="usage.html#keepnames">keepnames</a>
+<li>-<a href="usage.html#keepclassmembernames">keepclassmembernames</a>
+<li>-<a href="usage.html#keepclasseswithmembernames">keepclasseswithmembernames</a>
+<li><a href="usage.html#classspecification"><i>class_specification</i></a>
+</ul>
+<p>
+
+<a name="optimization"> </a>
+<h2>The Optimization Tab</h2>
+
+The <i>Optimization</i> tab presents a number of options that affect the
+optimization step. The basic options are followed by a few lists of class
+method calls that can be removed if ProGuard can determine that their results
+are not being used.
+<p>
+
+The lists are manipulated in much the same way as in the <a
+href="#shrinking">Shrinking Tab</a>.
+<p>
+
+Corresponding configuration options:
+<ul type="none">
+<li>-<a href="usage.html#dontoptimize">dontoptimize</a>
+<li>-<a href="usage.html#allowaccessmodification">allowaccessmodification</a>
+<li>-<a href="usage.html#assumenosideeffects">assumenosideeffects</a>
+<li><a href="usage.html#classspecification"><i>class_specification</i></a>
+</ul>
+<p>
+
+<a name="information"> </a>
+<h2>The Information Tab</h2>
+
+The <i>Information</i> tab presents a number of options that affect the
+information that ProGuard returns when processing your code.
+<p>
+
+Corresponding configuration options:
+<ul type="none">
+<li>-<a href="usage.html#printseeds">printseeds</a>
+<li>-<a href="usage.html#verbose">verbose</a>
+<li>-<a href="usage.html#dontnote">dontnote</a>
+<li>-<a href="usage.html#dontwarn">dontwarn</a>
+<li>-<a href="usage.html#ignorewarnings">ignorewarnings</a>
+<li>-<a href="usage.html#dontskipnonpubliclibraryclasses">dontskipnonpubliclibraryclasses</a>
+<li>-<a href="usage.html#dontskipnonpubliclibraryclassmembers">dontskipnonpubliclibraryclassmembers</a>
+</ul>
+<p>
+
+<a name="process"> </a>
+<h2>The Process Tab</h2>
+
+The <i>Process</i> tab has an output console for displaying the configuration
+and the messages while processing. There are three important buttons at the
+bottom:
+<p>
+
+<table cellspacing="5" cellpadding="5">
+<tr><td class="button">View configuration</td>
+ <td>displays the current ProGuard configuration in the console.</td></tr>
+<tr><td class="button">Save configuration...</td>
+ <td>opens a file chooser to save the current ProGuard
+ configuration.</td></tr>
+<tr><td class="button">Process!</td>
+ <td>executes ProGuard with the current configuration.</td></tr>
+</table>
+<p>
+
+<a name="retrace"> </a>
+<h2>The ReTrace Tab</h2>
+
+The <i>ReTrace</i> tab has a panel with a few settings, an input text area for
+the obfuscated stack trace, and an output console to view the de-obfuscated
+stack trace:
+
+<ul>
+<li>The <b>Mapping file</b> text field takes the name of the required mapping
+ file that ProGuard wrote while processing the original code. The file name
+ can be entered manually or by means of the <b>Browse...</b> button that
+ opens a file chooser.
+
+<li>The <b>Verbose</b> check box in the settings panel allows to toggle between
+ normal mode and verbose mode.
+
+<li>The <b>Obfuscated stack trace</b> text area allows to enter the stack
+ trace, typically by copying and pasting it from elsewhere. Alternatively,
+ it can be loaded from a file by means of the load button below.
+</ul>
+
+There are two buttons at the bottom:
+<p>
+
+<table cellspacing="5" cellpadding="5">
+<tr><td class="button">Load stack trace...</td>
+ <td>opens a file chooser to load an obfuscated stack trace.</td></tr>
+<tr><td class="button">ReTrace!</td>
+ <td>executes ReTrace with the current settings.</td></tr>
+</table>
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/index.html b/docs/manual/index.html
new file mode 100644
index 0000000..a4c9ee9
--- /dev/null
+++ b/docs/manual/index.html
@@ -0,0 +1,39 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Manual</title>
+</head>
+<body>
+
+<h2>ProGuard</h2>
+
+<ol>
+<li><a href="introduction.html">Introduction</a>
+<li><a href="usage.html">Usage</a>
+<li><a href="limitations.html">Limitations</a>
+<li><a href="examples.html">Examples</a>
+<li><a href="troubleshooting.html">Troubleshooting</a>
+<li><a href="refcard.html">Reference Card</a>
+<li><a href="gui.html">Graphical User Interface</a>
+<li><a href="ant.html">Ant Task</a>
+<li><a href="wtk.html">J2ME Wireless Toolkit Integration</a>
+</ol>
+
+<h2>ReTrace</h2>
+
+<ol>
+<li><a href="retrace/introduction.html">Introduction</a>
+<li><a href="retrace/usage.html">Usage</a>
+<li><a href="retrace/examples.html">Examples</a>
+</ol>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/introduction.html b/docs/manual/introduction.html
new file mode 100644
index 0000000..f8e939e
--- /dev/null
+++ b/docs/manual/introduction.html
@@ -0,0 +1,116 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Introduction</title>
+</head>
+<body>
+
+<h2>Introduction</h2>
+
+<b>ProGuard</b> is a Java class file shrinker, optimizer, and obfuscator. The
+shrinking step detects and removes unused classes, fields, methods, and
+attributes. The optimization step analyzes and optimizes the bytecode of the
+methods. The obfuscation step renames the remaining classes, fields, and
+methods using short meaningless names. The resulting jars are smaller and
+harder to reverse-engineer.
+<p>
+ProGuard can also be used to list unused fields and methods in an application,
+and to print out the internal structure of class files.
+<p>
+
+<table class="diagram" align="center">
+
+<tr>
+<td rowspan="4" class="lightblock">Input jars</td>
+<td colspan="6" class="transparentblock"></td>
+</tr>
+
+<tr>
+<td rowspan="2" class="transparentblock"></td>
+<td rowspan="3" class="lightblock">Shrunk code</td>
+<td colspan="4" class="transparentblock"></td>
+</tr>
+
+<tr>
+<td class="transparentblock"></td>
+<td rowspan="2" class="lightblock">Optimized code</td>
+<td colspan="2" class="transparentblock"></td>
+</tr>
+
+<tr>
+<td class="transparentblock">- shrink →</td>
+<td class="transparentblock">- optimize →</td>
+<td class="transparentblock">- obfuscate →</td>
+<td class="lightblock">Output jars</td>
+</tr>
+
+<tr>
+<td class="darkblock">Library jars</td>
+<td colspan="5" class="transparentblock">----------------- (unchanged) -----------------→</td>
+<td class="darkblock">Library jars</td>
+</tr>
+
+</table>
+<p>
+
+ProGuard typically reads the <b>input jars</b> (or wars, ears, zips, or
+directories). It then shrinks, optimizes, and obfuscates them. It then writes
+the results to one or more <b>output jars</b> (or wars, ears, zips, or
+directories). The input jars can optionally contain resource files. ProGuard
+copies all non-class resource files from the input jars to the output jars.
+Their names and contents remain unchanged.
+<p>
+ProGuard requires the <b>library jars</b> (or wars, ears, zips, or
+directories) of the input jars to be specified. It can then reconstruct class
+hierarchies and other class dependencies, which are necessary for proper
+shrinking, optimization, and obfuscation. The library jars themselves always
+remain unchanged. You should still put them in the class path of your final
+application.
+<p>
+In order to determine which code has to be preserved and which code can be
+discarded or obfuscated, you have to specify one or more entry points to your
+code. These entry points are typically classes with main methods, applets,
+midlets, etc.
+<ul>
+<li>In the <b>shrinking step</b>, ProGuard starts from these seeds and
+ recursively determines which classes and class members are used. All other
+ classes and class members are discarded.
+
+<li>In the <b>optimization step</b>, ProGuard further optimizes the code.
+ Among other optimizations, classes and methods that are not entry points
+ can be made final, and some methods may be inlined.
+<li>In the <b>obfuscation step</b>, ProGuard renames classes and class members
+ that are not entry points. In this entire process, keeping the entry
+ points ensures that they can still be accessed by their original names.
+</ul>
+<p>
+Any classes or class members of your code that are created or invoked
+dynamically (that is, by name) have to be specified as entry points too. It is
+generally impossible to determine these cases automatically, but ProGuard will
+offer some suggestions if keeping some classes or class members appears
+necessary. For proper results, you should at least be somewhat familiar with
+the code that you are processing.
+<p>
+ProGuard does handle <code>Class.forName("SomeClass")</code> and
+<code>SomeClass.class</code> constructs automatically. The referenced classes
+are preserved in the shrinking phase, and the string arguments are properly
+replaced in the obfuscation phase. With variable string arguments, it is
+generally impossible to determine their possible values (they might be read
+from a configuration file, for instance). However, as mentioned, ProGuard will
+note constructs like
+"<code>(SomeClass)Class.forName(variable).newInstance()</code>". These might
+be an indication that the class or interface <code>SomeClass</code> and/or its
+implementations may need to be preserved. You can then adapt your configuration
+accordingly.
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/limitations.html b/docs/manual/limitations.html
new file mode 100644
index 0000000..b69544f
--- /dev/null
+++ b/docs/manual/limitations.html
@@ -0,0 +1,95 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Limitations</title>
+</head>
+<body>
+
+<h2>Limitations</h2>
+
+When using ProGuard, you should be aware of a few issues, all of which are
+easily avoided or resolved:
+<p>
+<ul>
+<li>ProGuard handles the essential elements of Java: classes, interfaces, class
+ members, inheritance,... ProGuard itself is not aware of any additional
+ <b>naming conventions or APIs</b>: main methods, native methods, beans,
+ serialization,... You'll have to specify these in your configuration. The
+ configuration syntax is intended to be compact, readable, expressive, and
+ generally applicable. It's usually quite simple. The examples section of
+ this manual provides many typical examples. The graphical user interface
+ has checkboxes for common boilerplate configurations.
+ <p>
+
+<li>ProGuard currently copies <b>manifest files and resource files</b>
+ unchanged. Directory entries, on the other hand, are not copied to the
+ output jars. If your code has any special dependencies on these elements,
+ you should modify or add them manually.
+ <p>
+
+<li>For efficiency, ProGuard always ignores any <b>private or package visible
+ library classes</b> while reading library jars. If any of them are
+ extended by public library classes, and then extended again by input
+ classes, ProGuard will complain it can't find them. In that case, you'll
+ have to use the <code>-dontskipnonpubliclibraryclasses</code> option. The
+ graphical user interface has a checkbox for this setting.
+ <p>
+
+<li>For best results, ProGuard's <b>optimization</b> algorithms assume that
+ the processed code never intentionally causes NullPointerExceptions and
+ ArrayIndexOutOfBoundsExceptions to achieve something useful. For instance,
+ it may remove a method call <code>myObject.myMethod()</code> if that call
+ wouldn't have any effect. It ignores that <code>myObject</code> might be
+ null, causing a NullPointerException. In some way this is a good thing:
+ optimized code may throw fewer exceptions. Should this entire assumption be
+ false, you'll have to switch off optimization using the
+ <code>-dontoptimize</code> option.
+ <p>
+
+<li>If an input jar and a library jar contain classes in the <b>same
+ package</b>, the obfuscated output jar may contain class names that
+ overlap with class names in the library jar. This is most likely if the
+ library jar has been obfuscated before, as it will then probably contain
+ classes named 'a', 'b', etc. Packages should therefore never be split
+ across input jars and library jars.
+ <p>
+
+<li>ProGuard may not handle <b>obfuscation marker interfaces</b> as expected.
+ If you specify "<code>-keep class * implements MyKeepInterface</code>",
+ and <code>MyKeepInterface</code> is not used in your code, the specified
+ classes are kept, but they are obfuscated. Technically, the interface is
+ removed in the shrinking phase, making the directive void in the
+ obfuscation phase. This behavior may be fixed in the future. For now, you
+ can get around it by explicitly keeping the interface as well:
+ "<code>-keep class MyKeepInterface</code>". In any case, creating a proper
+ configuration file seems a cleaner solution than using such an obfuscation
+ marker interface.
+ <p>
+
+<li>ProGuard's obfuscation process currently doesn't follow the <b>naming
+ rule</b> specifying that internal classes must be named as
+ <code>ExternalClass$InternalClass</code>, for instance (cfr. <a href=
+ "http://java.sun.com/docs/books/jls/second_edition/html/j.title.doc.html"
+ >The Java Language Specification, Second Edition</a>, <a href=
+ "http://java.sun.com/docs/books/jls/second_edition/html/binaryComp.doc.html#59892"
+ >Section 13.1</a>). This should not present a problem in practice, since
+ the rule is mainly intended for transformations at the source code level.
+ Internal-external class relationships are still represented correctly
+ inside the binary class files. Decompilers or others tools that rely on
+ the naming rule may have problems processing obfuscated jars. I'm not
+ aware of any such cases.
+ <p>
+
+</ul>
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/refcard.html b/docs/manual/refcard.html
new file mode 100644
index 0000000..cf10b47
--- /dev/null
+++ b/docs/manual/refcard.html
@@ -0,0 +1,305 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Reference Card</title>
+</head>
+<body>
+
+<h1>ProGuard Reference Card</h1>
+
+<h2>Usage</h2>
+
+<code><b>java -jar proguard.jar </b></code><i>options</i> ...
+<p>
+ Typically:
+<p>
+<code><b>java -jar proguard.jar @myconfig.pro</b></code>
+<p>
+
+<h2>Options</h2>
+
+<table cellspacing="10">
+
+<tr>
+<td valign="top"><code><b>@</b></code><i>filename</i></td>
+
+<td>Short for '<code>-include</code> <i>filename</i>'.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-include</b></code> <i>filename</i></td>
+
+<td>Read configuration options from the given file.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-injars</b></code> <i>class_path</i></td>
+<td>Specifies the program jars (or wars, ears, zips, or directories).</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-outjars</b></code> <i>class_path</i></td>
+<td>Specifies the name of the output jars (or wars, ears, zips, or
+ directories).</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-libraryjars</b></code> <i>class_path</i></td>
+<td>Specifies the library jars (or wars, ears, zips, or directories).</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-dontskipnonpubliclibraryclasses</b></code></td>
+<td>Don't ignore non-public library classes.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-dontskipnonpubliclibraryclassmembers</b></code></td>
+<td>Don't ignore package visible library class members.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-keep</b></code> <i>class_specification</i></td>
+<td>Preserve the specified classes <i>and</i> class members.</td>
+
+</tr>
+<tr>
+<td valign="top"><code><b>-keepclassmembers</b></code>
+ <i>class_specification</i></td>
+<td>Preserve the specified class members, if their classes are preserved as
+ well.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-keepclasseswithmembers</b></code>
+ <i>class_specification</i></td>
+<td>Preserve the specified classes <i>and</i> class members, if all of the
+ specified class members are present.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-keepnames</b></code>
+ <i>class_specification</i></td>
+<td>Preserve the names of the specified classes <i>and</i> class members (if
+ they aren't removed in the shrinking step).</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-keepclassmembernames</b></code>
+ <i>class_specification</i></td>
+<td>Preserve the names of the specified class members (if they aren't removed
+ in the shrinking step).</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-keepclasseswithmembernames</b></code>
+ <i>class_specification</i></td>
+<td>Preserve the names of the specified classes <i>and</i> class members, if
+ all of the specified class members are present (after the shrinking
+ step).</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-printseeds</b></code> [<i>filename</i>]</td>
+<td>List classes and class members matched by the various <code>-keep</code>
+ options, to the standard output or to the given file.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-dontshrink</b></code></td>
+<td>Don't shrink the input class files.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-printusage</b></code> [<i>filename</i>]</td>
+<td>List dead code of the input class files, to the standard output or to the
+ given file.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-dontoptimize</b></code></td>
+<td>Don't optimize the input class files.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-assumenosideeffects</b></code>
+ <i>class_specification</i></td>
+<td>Assume that the specified methods don't have any side effects, while
+ optimizing.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-allowaccessmodification</b></code></td>
+<td>Allow the access modifiers of classes and class members to be modified,
+ while optimizing.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-dontobfuscate</b></code></td>
+<td>Don't obfuscate the input class files.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-printmapping</b></code> [<i>filename</i>]</td>
+<td>Print the mapping from old names to new names for classes and class members
+ that have been renamed, to the standard output or to the given file.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-applymapping</b></code> <i>filename</i></td>
+<td>Reuse the given mapping, for incremental obfuscation.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-obfuscationdictionary</b></code>
+ <i>filename</i></td>
+<td>Use the words in the given text file as obfuscated method names.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-overloadaggressively</b></code></td>
+<td>Apply aggressive overloading while obfuscating.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-defaultpackage</b></code> [<i>package_name</i>]</td>
+<td>Repackage all class files that are renamed into the single given
+ package.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-dontusemixedcaseclassnames</b></code></td>
+<td>Don't generate mixed-case class names while obfuscating.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-keepattributes</b></code>
+ [<i>attribute_name<b>,</b>...</i>]</td>
+<td>Preserve the given optional attributes; typically
+ <code>LineNumberTable</code>, <code>LocalVariableTable</code>,
+ <code>SourceFile</code>, <code>Deprecated</code>, <code>Synthetic</code>,
+ <code>Signature</code>, and <code>InnerClasses</code>.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-renamesourcefileattribute</b></code>
+ [<i>string</i>]</td>
+<td>Put the given constant string in the <code>SourceFile</code>
+ attributes.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-verbose</b></code></td>
+<td>Write out some more information during processing.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-dontnote</b></code></td>
+<td>Don't print notes about class casts of variable dynamically created
+ objects.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-dontwarn</b></code></td>
+<td>Don't warn about unresolved references at all.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-ignorewarnings</b></code></td>
+<td>Print warnings about unresolved references, but continue processing
+ anyhow.</td>
+</tr>
+
+<tr>
+<td valign="top"><code><b>-dump</b></code> [<i>filename</i>]</td>
+<td>Write out the internal structure of the processed class files, to the
+ standard output or to the given file.</td>
+</tr>
+
+</table>
+<p>
+Notes:
+<ul>
+
+<li><i>class_path</i> is a list of jars, wars, ears, zips, and directories,
+ with optional filters, separated by path separators.
+<li><i>filename</i> can contain Java system properties delimited by
+ '<b><</b>' and '<b>></b>'.
+<li>If <i>filename</i> contains special characters, the entire name
+ should be quoted with single or double quotes.
+</ul>
+<p>
+
+<h2>Overview of <code>Keep</code> Options</h2>
+
+<table cellpadding="5">
+
+<tr>
+<th>Keep</th>
+<td>From being removed or renamed</td>
+<td>From being renamed</td>
+</tr>
+
+<tr>
+<td>Classes and class members</td>
+<td bgcolor="#E0E0E0"><code>-keep</code></td>
+<td bgcolor="#E0E0E0"><code>-keepnames</code></td>
+</tr>
+
+<tr>
+<td>Class members only</td>
+<td bgcolor="#E0E0E0"><code>-keepclassmembers</code></td>
+<td bgcolor="#E0E0E0"><code>-keepclassmembernames</code></td>
+</tr>
+
+<tr>
+<td>Classes and class members, if class members present</td>
+<td bgcolor="#E0E0E0"><code>-keepclasseswithmembers</code></td>
+<td bgcolor="#E0E0E0"><code>-keepclasseswithmembernames</code></td>
+</tr>
+
+</table>
+<p>
+
+<h2>Class Specifications</h2>
+
+<pre>
+[[<b>!</b>]<b>public</b>|<b>final</b>|<b>abstract</b> ...] ([<b>!</b>]<b>interface</b>)|<b>class</b> <i>classname</i>
+ [<b>extends</b>|<b>implements</b> <i>classname</i>]
+[<b>{</b>
+ [[<b>!</b>]<b>public</b>|<b>private</b>|<b>protected</b>|<b>static</b>|<b>volatile</b>|<b>transient</b> ...] <b><fields></b> |
+ (<i>fieldtype fieldname</i>)<b>;</b>
+ [[<b>!</b>]<b>public</b>|<b>private</b>|<b>protected</b>|<b>static</b>|<b>synchronized</b>|<b>native</b>|<b>abstract</b>|<b>strictfp</b> ...] <b><methods></b> |
+ <b><init>(</b><i>argumenttype,...</i><b>)</b> |
+ <i>classname</i><b>(</b><i>argumenttype,...</i><b>)</b> |
+ (<i>returntype methodname</i><b>(</b><i>argumenttype,...</i><b>)</b>)<b>;</b>
+ [[<b>!</b>]<b>public</b>|<b>private</b>|<b>protected</b>|<b>static</b> ... ] <b>*;</b>
+ ...
+<b>}</b>]
+</pre>
+<p>
+Notes:
+<ul>
+<li>Class names must always be fully qualified, i.e. including their package
+ names.
+<li>Types in <i>classname</i>, <i>returntype</i>, and <i>argumenttype</i> can
+ contain wildcards: '<code><b>?</b></code>' for a single character,
+ '<code><b>*</b></code>' for any number of characters (but not the package
+ separator), '<code><b>**</b></code>' for any number of (any)
+ characters, and '<code><b>%</b></code>' for any primitive type.
+<li><i>fieldname</i> and <i>methodname</i> can contain wildcards as well:
+ '<code><b>?</b></code>' for a single character and '<code><b>*</b></code>'
+ for any number of characters.
+</ul>
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/retrace/examples.html b/docs/manual/retrace/examples.html
new file mode 100644
index 0000000..75f7ae4
--- /dev/null
+++ b/docs/manual/retrace/examples.html
@@ -0,0 +1,336 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="../style.css">
+<title>ReTrace Examples</title>
+</head>
+<body>
+
+<h2>Examples</h2>
+
+Some typical example uses:
+<ol>
+<li><a href="#with">Restoring a stack trace with line numbers</a>
+<li><a href="#withverbose">Restoring a stack trace with line numbers (verbose)</a>
+<li><a href="#without">Restoring a stack trace without line numbers</a>
+</ol>
+
+<a name="with"> </a>
+<h3>Restoring a stack trace with line numbers</h3>
+
+Assume for instance ProGuard itself has been obfuscated using the following
+extra options:
+<pre>
+-printmapping proguard.map
+
+-renamesourcefileattribute ProGuard
+-keepattributes SourceFile,LineNumberTable
+</pre>
+<p>
+
+Now assume the processed application throws an exception, and we have saved the
+stack trace in <code>proguard.trace</code>, shown below. Of course, in real
+life ProGuard rarely throws exceptions, so this is a purposely generated
+exception. :)
+
+<pre>
+Exception in thread "main" java.lang.Error: Random exception
+ at pro.bY.a(ProGuard:576)
+ at pro.bO.a(ProGuard:431)
+ at pro.bj.a(ProGuard:145)
+ at pro.bY.a(ProGuard:522)
+ at pro.bj.a(ProGuard:129)
+ at pro.bN.a(ProGuard:125)
+ at pro.bY.a(ProGuard:251)
+ at pro.bY.a(ProGuard:229)
+ at pro.l.a(ProGuard:55)
+ at pro.bo.b(ProGuard:405)
+ at pro.ci.a(ProGuard:51)
+ at pro.bo.a(ProGuard:356)
+ at pro.be.a(ProGuard:109)
+ at pro.bo.a(ProGuard:356)
+ at pro.be.a(ProGuard:186)
+ at pro.bg.a(ProGuard:369)
+ at pro.bY.a(ProGuard:286)
+ at pro.bh.a(ProGuard:55)
+ at pro.bg.b(ProGuard:408)
+ at pro.bY.a(ProGuard:190)
+ at pro.bg.a(ProGuard:369)
+ at pro.M.a(ProGuard:110)
+ at pro.bY.a(ProGuard:449)
+ at pro.M.a(ProGuard:99)
+ at pro.bo.a(ProGuard:372)
+ at pro.bY.a(ProGuard:649)
+ at pro.bY.a(ProGuard:112)
+ at pro.P.a(ProGuard:66)
+ at pro.p.a(ProGuard:83)
+ at pro.bU.a(ProGuard:69)
+ at pro.bo.a(ProGuard:356)
+ at pro.J.a(ProGuard:149)
+ at pro.I.a(ProGuard:49)
+ at pro.J.a(ProGuard:105)
+ at pro.cf.c(ProGuard:370)
+ at pro.cf.a(ProGuard:317)
+ at pro.bc.a(ProGuard:55)
+ at proguard.ProGuard.a(ProGuard:363)
+ at proguard.ProGuard.c(ProGuard:187)
+ at proguard.ProGuard.b(ProGuard:385)
+ at proguard.ProGuard.main(ProGuard:429)
+</pre>
+<p>
+
+We can then use the following command to recover the stack trace:
+<pre>
+<b>java -jar retrace.jar proguard.map proguard.trace</b>
+</pre>
+<p>
+
+The output will look as follows:
+<pre>
+Exception in thread "main" java.lang.Error: Random exception
+ at proguard.shrink.UsageMarker.visitInstruction(ProGuard:576)
+ at proguard.classfile.instruction.GenericInstruction.accept(ProGuard:431)
+ at proguard.classfile.CodeAttrInfo.instructionsAccept(ProGuard:145)
+ at proguard.shrink.UsageMarker.visitCodeAttrInfo(ProGuard:522)
+ at proguard.classfile.CodeAttrInfo.accept(ProGuard:129)
+ at proguard.classfile.ProgramMemberInfo.attributesAccept(ProGuard:125)
+ at proguard.shrink.UsageMarker.visitMemberInfo(ProGuard:251)
+ at proguard.shrink.UsageMarker.visitProgramMethodInfo(ProGuard:229)
+ at proguard.classfile.ProgramMethodInfo.accept(ProGuard:55)
+ at proguard.classfile.ProgramClassFile.methodAccept(ProGuard:405)
+ at proguard.classfile.visitor.NamedMethodVisitor.visitProgramClassFile(ProGuard:51)
+ at proguard.classfile.ProgramClassFile.accept(ProGuard:356)
+ at proguard.classfile.visitor.ClassFileUpDownTraveler.visitProgramClassFile(ProGuard:109)
+ at proguard.classfile.ProgramClassFile.accept(ProGuard:356)
+ at proguard.classfile.visitor.ClassFileUpDownTraveler.visitLibraryClassFile(ProGuard:186)
+ at proguard.classfile.LibraryClassFile.accept(ProGuard:369)
+ at proguard.shrink.UsageMarker.visitLibraryMethodInfo(ProGuard:286)
+ at proguard.classfile.LibraryMethodInfo.accept(ProGuard:55)
+ at proguard.classfile.LibraryClassFile.methodsAccept(ProGuard:408)
+ at proguard.shrink.UsageMarker.visitLibraryClassFile(ProGuard:190)
+ at proguard.classfile.LibraryClassFile.accept(ProGuard:369)
+ at proguard.classfile.ClassCpInfo.referencedClassAccept(ProGuard:110)
+ at proguard.shrink.UsageMarker.visitClassCpInfo(ProGuard:449)
+ at proguard.classfile.ClassCpInfo.accept(ProGuard:99)
+ at proguard.classfile.ProgramClassFile.constantPoolEntryAccept(ProGuard:372)
+ at proguard.shrink.UsageMarker.markCpEntry(ProGuard:649)
+ at proguard.shrink.UsageMarker.visitProgramClassFile(ProGuard:112)
+ at proguard.classfile.visitor.VariableClassFileVisitor.visitProgramClassFile(ProGuard:66)
+ at proguard.classfile.visitor.MultiClassFileVisitor.visitProgramClassFile(ProGuard:83)
+ at proguard.classfile.visitor.FilteredClassFileVisitor.visitProgramClassFile(ProGuard:69)
+ at proguard.classfile.ProgramClassFile.accept(ProGuard:356)
+ at proguard.classfile.ClassPool.classFileAccept(ProGuard:149)
+ at proguard.classfile.visitor.NamedClassFileVisitor.visitClassPool(ProGuard:49)
+ at proguard.classfile.ClassPool.accept(ProGuard:105)
+ at proguard.KeepCommand.executeShrinkingPhase(ProGuard:370)
+ at proguard.KeepCommand.execute(ProGuard:317)
+ at proguard.CompoundCommand.execute(ProGuard:55)
+ at proguard.ProGuard.executeCommands(ProGuard:363)
+ at proguard.ProGuard.shrink(ProGuard:187)
+ at proguard.ProGuard.execute(ProGuard:385)
+ at proguard.ProGuard.main(ProGuard:429)
+</pre>
+
+<a name="withverbose"> </a>
+<h3>Restoring a stack trace with line numbers (verbose)</h3>
+
+In the previous example, we could also use the verbose flag:
+<pre>
+<b>java -jar retrace.jar -verbose proguard.map proguard.trace</b>
+</pre>
+<p>
+
+The output will then look as follows:
+<pre>
+Exception in thread "main" java.lang.Error: Random exception
+ at proguard.shrink.UsageMarker.void visitInstruction(proguard.classfile.ClassFile,proguard.classfile.instruction.Instruction)(ProGuard:576)
+ at proguard.classfile.instruction.GenericInstruction.void accept(proguard.classfile.ClassFile,proguard.classfile.instruction.InstructionVisitor)(ProGuard:431)
+ at proguard.classfile.CodeAttrInfo.void instructionsAccept(proguard.classfile.ClassFile,proguard.classfile.instruction.InstructionVisitor)(ProGuard:145)
+ at proguard.shrink.UsageMarker.void visitCodeAttrInfo(proguard.classfile.ClassFile,proguard.classfile.CodeAttrInfo)(ProGuard:522)
+ at proguard.classfile.CodeAttrInfo.void accept(proguard.classfile.ClassFile,proguard.classfile.visitor.AttrInfoVisitor)(ProGuard:129)
+ at proguard.classfile.ProgramMemberInfo.void attributesAccept(proguard.classfile.ProgramClassFile,proguard.classfile.visitor.AttrInfoVisitor)(ProGuard:125)
+ at proguard.shrink.UsageMarker.void visitMemberInfo(proguard.classfile.ProgramClassFile,proguard.classfile.ProgramMemberInfo)(ProGuard:251)
+ at proguard.shrink.UsageMarker.void visitProgramMethodInfo(proguard.classfile.ProgramClassFile,proguard.classfile.ProgramMethodInfo)(ProGuard:229)
+ at proguard.classfile.ProgramMethodInfo.void accept(proguard.classfile.ProgramClassFile,proguard.classfile.visitor.MemberInfoVisitor)(ProGuard:55)
+ at proguard.classfile.ProgramClassFile.void methodAccept(proguard.classfile.visitor.MemberInfoVisitor,java.lang.String,java.lang.String)(ProGuard:405)
+ at proguard.classfile.visitor.NamedMethodVisitor.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:51)
+ at proguard.classfile.ProgramClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:356)
+ at proguard.classfile.visitor.ClassFileUpDownTraveler.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:109)
+ at proguard.classfile.ProgramClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:356)
+ at proguard.classfile.visitor.ClassFileUpDownTraveler.void visitLibraryClassFile(proguard.classfile.LibraryClassFile)(ProGuard:186)
+ at proguard.classfile.LibraryClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:369)
+ at proguard.shrink.UsageMarker.void visitLibraryMethodInfo(proguard.classfile.LibraryClassFile,proguard.classfile.LibraryMethodInfo)(ProGuard:286)
+ at proguard.classfile.LibraryMethodInfo.void accept(proguard.classfile.LibraryClassFile,proguard.classfile.visitor.MemberInfoVisitor)(ProGuard:55)
+ at proguard.classfile.LibraryClassFile.void methodsAccept(proguard.classfile.visitor.MemberInfoVisitor)(ProGuard:408)
+ at proguard.shrink.UsageMarker.void visitLibraryClassFile(proguard.classfile.LibraryClassFile)(ProGuard:190)
+ at proguard.classfile.LibraryClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:369)
+ at proguard.classfile.ClassCpInfo.void referencedClassAccept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:110)
+ at proguard.shrink.UsageMarker.void visitClassCpInfo(proguard.classfile.ClassFile,proguard.classfile.ClassCpInfo)(ProGuard:449)
+ at proguard.classfile.ClassCpInfo.void accept(proguard.classfile.ClassFile,proguard.classfile.visitor.CpInfoVisitor)(ProGuard:99)
+ at proguard.classfile.ProgramClassFile.void constantPoolEntryAccept(proguard.classfile.visitor.CpInfoVisitor,int)(ProGuard:372)
+ at proguard.shrink.UsageMarker.void markCpEntry(proguard.classfile.ClassFile,int)(ProGuard:649)
+ at proguard.shrink.UsageMarker.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:112)
+ at proguard.classfile.visitor.VariableClassFileVisitor.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:66)
+ at proguard.classfile.visitor.MultiClassFileVisitor.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:83)
+ at proguard.classfile.visitor.FilteredClassFileVisitor.void visitProgramClassFile(proguard.classfile.ProgramClassFile)(ProGuard:69)
+ at proguard.classfile.ProgramClassFile.void accept(proguard.classfile.visitor.ClassFileVisitor)(ProGuard:356)
+ at proguard.classfile.ClassPool.void classFileAccept(proguard.classfile.visitor.ClassFileVisitor,java.lang.String)(ProGuard:149)
+ at proguard.classfile.visitor.NamedClassFileVisitor.void visitClassPool(proguard.classfile.ClassPool)(ProGuard:49)
+ at proguard.classfile.ClassPool.void accept(proguard.classfile.visitor.ClassPoolVisitor)(ProGuard:105)
+ at proguard.KeepCommand.void executeShrinkingPhase(proguard.classfile.ClassPool,proguard.classfile.ClassPool)(ProGuard:370)
+ at proguard.KeepCommand.void execute(int,proguard.classfile.ClassPool,proguard.classfile.ClassPool)(ProGuard:317)
+ at proguard.CompoundCommand.void execute(int,proguard.classfile.ClassPool,proguard.classfile.ClassPool)(ProGuard:55)
+ at proguard.ProGuard.void executeCommands(int)(ProGuard:363)
+ at proguard.ProGuard.void shrink()(ProGuard:187)
+ at proguard.ProGuard.void execute(java.lang.String[])(ProGuard:385)
+ at proguard.ProGuard.void main(java.lang.String[])(ProGuard:429)
+</pre>
+
+
+<a name="without"> </a>
+<h3>Restoring a stack trace without line numbers</h3>
+
+Assume for instance ProGuard itself has been obfuscated using the following
+extra options, this time without preserving the line number tables:
+<pre>
+-printmapping proguard.map
+</pre>
+<p>
+
+A stack trace <code>proguard.trace</code> will then lack line number
+information:
+<pre>
+Exception in thread "main" java.lang.Error: Random exception
+ at pro.bY.a(Unknown Source)
+ at pro.bO.a(Unknown Source)
+ at pro.bj.a(Unknown Source)
+ at pro.bY.a(Unknown Source)
+ at pro.bj.a(Unknown Source)
+ at pro.bN.a(Unknown Source)
+ at pro.bY.a(Unknown Source)
+ at pro.bY.a(Unknown Source)
+ at pro.l.a(Unknown Source)
+ at pro.bo.b(Unknown Source)
+ at pro.ci.a(Unknown Source)
+ at pro.bo.a(Unknown Source)
+ at pro.be.a(Unknown Source)
+ at pro.bo.a(Unknown Source)
+ at pro.be.a(Unknown Source)
+ at pro.bg.a(Unknown Source)
+ at pro.bY.a(Unknown Source)
+ at pro.bh.a(Unknown Source)
+ at pro.bg.b(Unknown Source)
+ at pro.bY.a(Unknown Source)
+ at pro.bg.a(Unknown Source)
+ at pro.M.a(Unknown Source)
+ at pro.bY.a(Unknown Source)
+ at pro.M.a(Unknown Source)
+ at pro.bo.a(Unknown Source)
+ at pro.bY.a(Unknown Source)
+ at pro.bY.a(Unknown Source)
+ at pro.P.a(Unknown Source)
+ at pro.p.a(Unknown Source)
+ at pro.bU.a(Unknown Source)
+ at pro.bo.a(Unknown Source)
+ at pro.J.a(Unknown Source)
+ at pro.I.a(Unknown Source)
+ at pro.J.a(Unknown Source)
+ at pro.cf.c(Unknown Source)
+ at pro.cf.a(Unknown Source)
+ at pro.bc.a(Unknown Source)
+ at proguard.ProGuard.a(Unknown Source)
+ at proguard.ProGuard.c(Unknown Source)
+ at proguard.ProGuard.b(Unknown Source)
+ at proguard.ProGuard.main(Unknown Source)
+</pre>
+<p>
+
+We can still use the same command to recover the stack trace:
+<pre>
+<b>java -jar retrace.jar proguard.map proguard.trace</b>
+</pre>
+<p>
+
+The output will now give a list of alternative original method names for each
+ambiguous obfuscated method name:
+<pre>
+Exception in thread "main" java.lang.Error: Random exception
+ at proguard.shrink.UsageMarker.visitProgramClassFile(Unknown Source)
+ visitLibraryClassFile
+ visitProgramFieldInfo
+ visitProgramMethodInfo
+ visitMemberInfo
+ visitLibraryFieldInfo
+ visitLibraryMethodInfo
+ visitIntegerCpInfo
+ visitLongCpInfo
+ visitFloatCpInfo
+ visitDoubleCpInfo
+ visitStringCpInfo
+ visitUtf8CpInfo
+ visitFieldrefCpInfo
+ visitInterfaceMethodrefCpInfo
+ visitMethodrefCpInfo
+ visitClassCpInfo
+ visitNameAndTypeCpInfo
+ visitUnknownAttrInfo
+ visitInnerClassesAttrInfo
+ visitConstantValueAttrInfo
+ visitExceptionsAttrInfo
+ visitCodeAttrInfo
+ visitLineNumberTableAttrInfo
+ visitLocalVariableTableAttrInfo
+ visitSourceFileAttrInfo
+ visitDeprecatedAttrInfo
+ visitSyntheticAttrInfo
+ visitInstruction
+ visitCpInstruction
+ visitExceptionInfo
+ visitInnerClassesInfo
+ visitLocalVariableInfo
+ markCpEntry
+ markAsUnused
+ isUsed
+ at proguard.classfile.instruction.GenericInstruction.create(Unknown Source)
+ isWide
+ getLength
+ accept
+ at proguard.classfile.CodeAttrInfo.getAttribute(Unknown Source)
+ getAttrInfoLength
+ readInfo
+ accept
+ instructionsAccept
+ exceptionsAccept
+ [...]
+ at proguard.KeepCommand.executeShrinkingPhase(Unknown Source)
+ access$100
+ at proguard.KeepCommand.keepField(Unknown Source)
+ ensureMultiClassFileVisitorForMembers
+ execute
+ executeObfuscationPhase
+ access$002
+ access$000
+ access$102
+ access$108
+ at proguard.CompoundCommand.addCommand(Unknown Source)
+ execute
+ at proguard.ProGuard.readCommands(Unknown Source)
+ obfuscate
+ executeCommands
+ at proguard.ProGuard.shrink(Unknown Source)
+ at proguard.ProGuard.check(Unknown Source)
+ execute
+ at proguard.ProGuard.main(Unknown Source)
+</pre>
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
+
diff --git a/docs/manual/retrace/index.html b/docs/manual/retrace/index.html
new file mode 100644
index 0000000..d69eaea
--- /dev/null
+++ b/docs/manual/retrace/index.html
@@ -0,0 +1,25 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="../style.css">
+<title>ReTrace Manual</title>
+</head>
+<body>
+
+<h2>ReTrace</h2>
+
+<ol>
+<li><a href="introduction.html">Introduction</a>
+<li><a href="usage.html">Usage</a>
+<li><a href="examples.html">Examples</a>
+</ol>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/retrace/introduction.html b/docs/manual/retrace/introduction.html
new file mode 100644
index 0000000..e90e150
--- /dev/null
+++ b/docs/manual/retrace/introduction.html
@@ -0,0 +1,66 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="../style.css">
+<title>ReTrace Introduction</title>
+</head>
+<body>
+
+<h2>Introduction</h2>
+
+<b>ReTrace</b> is a companion tool for <b>ProGuard</b> that 'de-obfuscates'
+stack traces. When an obfuscated program throws an exception, the resulting
+stack trace typically isn't very informative. Class names and method names
+have been replaced by short meaningless strings. Source file names and line
+numbers are missing altogether. While this may be intentional, it can also be
+inconvenient when debugging problems.
+<p>
+
+<table class="diagram" align="center">
+
+<tr>
+<td rowspan="1" class="lightblock">Original code</td>
+<td class="transparentblock">- <b>ProGuard</b> →</td>
+<td rowspan="1" class="lightblock">Obfuscated code</td>
+</tr>
+
+<tr>
+<td rowspan="3" class="transparentblock"></td>
+<td class="transparentblock">↓</td>
+<td class="transparentblock">↓</td>
+</tr>
+
+<tr>
+<td class="whiteblock">Mapping file</td>
+<td class="transparentblock">↓</td>
+</tr>
+
+<tr>
+<td class="transparentblock">↓</td>
+<td class="transparentblock">↓</td>
+</tr>
+
+<tr>
+<td class="whiteblock">Readable stack trace</td>
+<td class="transparentblock">← <b>ReTrace</b> -</td>
+<td class="whiteblock">Obfuscated stack trace</td>
+</tr>
+
+</table>
+<p>
+ReTrace can read an obfuscated stack trace and restore it to what it would
+look like without obfuscation. The restoration is based on the mapping file
+that ProGuard can write out during obfuscation. The mapping file links the
+original class names and class member names to their obfuscated names.
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
+
diff --git a/docs/manual/retrace/usage.html b/docs/manual/retrace/usage.html
new file mode 100644
index 0000000..239c39c
--- /dev/null
+++ b/docs/manual/retrace/usage.html
@@ -0,0 +1,81 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="../style.css">
+<title>ReTrace Usage</title>
+</head>
+<body>
+
+<h2>Usage</h2>
+
+To run ReTrace, just type:
+<p>
+<p class="code">
+<code><b>java -jar retrace.jar [-verbose] </b></code><i>mapping_file</i>
+[<i>stacktrace_file</i>]
+</p>
+where the arguments have the following meaning:
+<p>
+<table cellspacing="10">
+<tr>
+<td valign="top"><code><b>-verbose</b></code></td>
+
+<td>Optionally specifies to print out more informative stack traces that
+ include not only method names, but also method return types and
+ arguments.</td>
+
+</tr>
+<tr>
+<td valign="top"><i>mapping_file</i></td>
+
+<td>Specifies the name of the mapping file, produced by ProGuard with the
+ option "<code>-printmapping</code> <i>mapping_file</i>", while obfuscating
+ the application that produced the stack trace.</td>
+
+</tr>
+<tr>
+<td valign="top"><i>stacktrace_file</i></td>
+
+<td>Optionally specifies the name of the file containing the stack trace. If
+ no file is specified, a stack trace is read from the standard input. Blank
+ lines and unrecognized lines are ignored, as far as possible.</td>
+
+</tr>
+</table>
+
+The restored stack trace is printed to the standard output. The completeness
+of the restored stack trace depends on the presence of line number tables in
+the obfuscated class files:
+
+<ul>
+<li>If all line numbers have been preserved while obfuscating the application,
+ ReTrace will be able to restore the stack trace completely.
+ <p>
+
+<li>If the line numbers have been removed, mapping obfuscated method names
+ back to their original names has become ambiguous. Retrace will list all
+ possible original method names for each line in the stack trace. The user
+ can then try to deduce the actual stack trace manually, based on the logic
+ of the program.
+
+</ul>
+<p>
+
+Preserving line number tables is explained in detail in this <a
+href="../examples.html#stacktrace">example</a> in the ProGuard User Manual.
+<p>
+
+Unobfuscated elements and obfuscated elements for which no mapping is available
+will be left unchanged.
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
+
diff --git a/docs/manual/sections.html b/docs/manual/sections.html
new file mode 100644
index 0000000..fab98e2
--- /dev/null
+++ b/docs/manual/sections.html
@@ -0,0 +1,136 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-script-type" content="text/javascript">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="../style.css">
+<title>Sections</title>
+
+<script type="text/javascript" language="JavaScript">
+<!--
+function defineSection(aName, aTarget, aURL) {
+ document.write("<tr><th class=\"sections\"");
+ document.write(document.body != null ?
+ (" onMouseOver=\"lightUp(this)\" onMouseOut=\"lightDown(this)\" onClick=\"goTo(this,'"+aTarget+"','"+aURL+"')\" onAfterUpdate=\"lightUp(this)\">"+aName) :
+ ("><a target=\""+aTarget+"\" href=\""+aURL+"\">"+aName+"</a>"));
+ document.write("</th></tr>");
+}
+
+function lightUp(aTH) {
+ if (aTH != fTH)
+ aTH.bgColor = "#eeeeee";
+}
+function lightDown(aTH) {
+ if (aTH != fTH)
+ aTH.bgColor = "";
+}
+function goTo(aTH, aTarget, aURL) {
+ if (fTH != null)
+ fTH.bgColor = "";
+
+ fTH = aTH;
+ fTH.bgColor = "white";
+ f = findFrameByName(parent.frames, aTarget);
+ if (f != null)
+ f.document.location.href=aURL;
+}
+function findFrameByName(aFrames, aFrameName) {
+ for (i = 0; i < aFrames.length; i++)
+ if (aFrames[i].name == aFrameName)
+ return aFrames[i];
+ return null;
+}
+//-->
+</script>
+
+</head>
+<body class="title">
+
+<script type="text/javascript" language="JavaScript">
+<!--
+var fTH = null;
+//-->
+</script>
+
+<script type="text/javascript" language="JavaScript">
+<!--
+document.write("<table class=\"sections\"");
+defineSection("<< Main Menu","sections","../sections.html");
+document.write("<tr><th class=\"sections\" bgcolor=\"white\">ProGuard<br>Manual</th></tr>");
+defineSection("Introduction", "main","introduction.html");
+defineSection("Usage", "main","usage.html");
+defineSection("Limitations", "main","limitations.html");
+defineSection("Examples", "main","examples.html");
+defineSection("Troubleshooting","main","troubleshooting.html");
+defineSection("Reference Card", "main","refcard.html");
+defineSection("GUI", "main","gui.html");
+defineSection("Ant Task", "main","ant.html");
+defineSection("J2ME WTK", "main","wtk.html");
+document.write("<tr><th class=\"sections\" bgcolor=\"white\">ReTrace<br>Manual</th></tr>");
+defineSection("Introduction", "main","retrace/introduction.html");
+defineSection("Usage", "main","retrace/usage.html");
+defineSection("Examples", "main","retrace/examples.html");
+document.write("</table>");
+document.write("<p>");
+document.write("<center>");
+document.write("<small>With support of</small>");
+document.write("<p>");
+document.write("<a href=\"http://sourceforge.net/projects/proguard/\" target=\"other\">");
+document.write("<img src=\"");
+document.write(document.location.hostname == "proguard.sourceforge.net" ?
+ "http://sourceforge.net/sflogo.php?group_id=54750&type=1" :
+ "../sflogo.png");
+document.write("\" width=\"88\" height=\"31\" border=\"0\" alt=\"SourceForge\">");
+document.write("</a>");
+document.write("<p>");
+document.write("<a href=\"http://www.luciad.com/\" target=\"other\">");
+document.write("<img src=\"../luciadlogo.png\" width=\"88\" height=\"24\" border=\"0\" alt=\"Luciad\">");
+document.write("</a>");
+document.write("</center>");
+//-->
+</script>
+
+<noscript>
+<table
+ width="120"
+ border="1"
+ style="border-style:outset"
+ cellspacing="0"
+ cellpadding="0"
+ background="../steel.gif"
+ bgcolor="#cccccc">
+
+<tr><th height="40" valign="middle"><a href="../sections.html"><< Main menu</a></th></tr>
+
+<tr><th class="sections" bgcolor="white">ProGuard<br>Manual</th></tr>
+<tr><th class="sections"><a target="main" href="introduction.html">Introduction</a></th></tr>
+<tr><th class="sections"><a target="main" href="usage.html">Usage</a></th></tr>
+<tr><th class="sections"><a target="main" href="limitations.html">Limitations</a></th></tr>
+<tr><th class="sections"><a target="main" href="examples.html">Examples</a></th></tr>
+<tr><th class="sections"><a target="main" href="troubleshooting.html">Troubleshooting</a></th></tr>
+<tr><th class="sections"><a target="main" href="refcard.html">Reference Card</a></th></tr>
+<tr><th class="sections"><a target="main" href="gui.html">GUI</a></th></tr>
+<tr><th class="sections"><a target="main" href="ant.html">Ant Task</a></th></tr>
+<tr><th class="sections"><a target="main" href="wtk.html">J2ME WTK</a></th></tr>
+
+<tr><th class="sections" bgcolor="white">ReTrace<br>Manual</th></tr>
+<tr><th class="sections"><a target="main" href="retrace/introduction.html">Introduction</a></th></tr>
+<tr><th class="sections"><a target="main" href="retrace/usage.html">Usage</a></th></tr>
+<tr><th class="sections"><a target="main" href="retrace/examples.html">Examples</a></th></tr>
+
+</table>
+<p>
+<center>
+<small>With support of</small>
+<p>
+<a href="http://sourceforge.net/projects/proguard/" target="other">
+<img src="../sflogo.png" width="88" height="31" alt="SourceForge"></a>
+<p>
+<a href="http://www.luciad.com/" target="other">
+<img src="../luciadlogo.png" width="88" height="24" alt="Luciad"></a>
+</center>
+</noscript>
+
+</body>
+</html>
diff --git a/docs/manual/style.css b/docs/manual/style.css
new file mode 100644
index 0000000..1b0cc55
--- /dev/null
+++ b/docs/manual/style.css
@@ -0,0 +1,81 @@
+ at charset "iso-8859-1";
+
+/* Global settings. */
+
+body {
+ background: #FFFFFF;
+}
+
+h1 {
+ text-align: center;
+}
+
+h2 {
+ background: #EEEEFF;
+ padding: 10px;
+}
+
+dt {
+ padding: 6px;
+}
+
+dd {
+ padding: 6px;
+}
+
+pre {
+ padding: 10px;
+ background: #E0E0E0;
+}
+
+/* Settings for variable width code. */
+
+p.code {
+ padding: 10px;
+ background: #E0E0E0;
+}
+
+
+/* Settings for diagrams. */
+
+table.diagram {
+ padding: 8px;
+ border: none;
+ border-spacing: 2px;
+}
+
+td.transparentblock {
+ text-align: center;
+ padding: 10px 0px;
+}
+
+td.whiteblock {
+ width: 100px;
+ text-align: center;
+ border: solid #C0C0C0 1px;
+ background: #E0E0E0;
+ padding: 10px 0px;
+}
+
+td.lightblock {
+ width: 100px;
+ text-align: center;
+ border: solid #8888FF 1px;
+ background: #BBBBFF;
+ padding: 20px 0px;
+}
+
+td.darkblock {
+ width: 100px;
+ text-align: center;
+ background: #8888FF;
+ padding: 20px 0px;
+}
+
+/* Settings for buttons. */
+
+td.button {
+ background: #E0E0E0;
+ border: outset #FFFFFF 1px;
+ font-weight: bold;
+}
diff --git a/docs/manual/troubleshooting.html b/docs/manual/troubleshooting.html
new file mode 100644
index 0000000..b598108
--- /dev/null
+++ b/docs/manual/troubleshooting.html
@@ -0,0 +1,269 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Troubleshooting</title>
+</head>
+<body>
+
+<h2>Troubleshooting</h2>
+
+While preparing a configuration for processing your code, you may bump into a
+few problems. The following sections discuss some common issues and solutions:
+<ul>
+<li><a href="#processing">Problems while processing</a>
+<li><a href="#preverifying">Problems while preverifying for J2ME</a>
+<li><a href="#runtime">Problems at run-time</a>
+</ul>
+
+<a name="processing"> </a>
+<h2>Problems while processing</h2>
+
+ProGuard may print out some notes and non-fatal warnings:
+
+<dl>
+<dt><a name="dynamical"><b>Note: ... calls '(...)Class.forName(variable).newInstance()'</b></a></dt>
+
+<dd>ProGuard lists all class casts of dynamically created class instances,
+ like "<code>(MyClass)Class.forName(variable).newInstance()</code>".
+ Depending on your application, you may need to keep the mentioned classes
+ with an option like "<code>-keep class MyClass</code>", or their
+ implementations with an option like "<code>-keep class * implements
+ MyClass</code>". You can switch off these notes by specifying the
+ <code>-dontnote</code> option.</dd>
+
+<dt><a name="duplicateclass"><b>Note: duplicate definition of program/library class</b></a></dt>
+
+<dd>Your program jars or library jars contain multiple definitions of the
+ listed classes. ProGuard continues processing as usual, only considering
+ the first definitions. The warning may be an indication of some problem
+ though, so it's advisable to remove the duplicates. A convenient way to do
+ so is by specifying filters on the input jars or library jars. You can
+ switch off these notes by specifying the <code>-dontnote</code>
+ option.</dd>
+
+<dt><a name="duplicatezipentry"><b>Warning: can't write resource... Duplicate zip entry</b></a></dt>
+
+<dd>Your input jars contain multiple resource files with the same name.
+ ProGuard continues copying the resource files as usual, skipping any files
+ with previously used names. Once more, the warning may be an indication of
+ some problem though, so it's advisable to remove the duplicates. A
+ convenient way to do so is by specifying filters on the input jars. There
+ is no option to switch off these warnings.</dd>
+
+</dl>
+<p>
+
+ProGuard may terminate when it encounters parsing errors or I/O errors, or
+some more serious warnings:
+
+<dl>
+<dt><a name="unresolvedclass"><b>Warning: can't find superclass or interface</b></a></dt>
+
+<dd>If there are unresolved references to superclasses or interfaces, you most
+ likely forgot to specify an essential library. All libraries that are
+ referenced by your code should be specified, including the Java run-time
+ library. For specifying libraries, use the <code>-libraryjars</code>
+ option.
+ <p>
+ If the class that is reported as missing is a non-public library class,
+ you should specify the <code>-dontskipnonpubliclibraryclasses</code>
+ option. A common example is the class
+ <code>java.util.zip.ZipConstants</code>, which is used as an interface
+ class in some public classes, even though it is only package visible (in
+ this case, the warning could also be ignored, because the class is not a
+ fundamental part of the class hierarchy).
+ <p>
+ If you're missing a library and you're absolutely sure it isn't used
+ anyway, you can try your luck with the <code>-ignorewarnings</code>
+ option, or even the <code>-dontwarn</code> option.</dd>
+
+<dt><a name="unresolvedclassmember"><b>Warning: can't find referenced field/method</b></a></dt>
+
+<dd>If there are unresolved references to class members in input classes, your
+ class files are most likely inconsistent. Possibly, some class file didn't
+ get recompiled properly, or some class file was left behind after its
+ source file was removed. Try removing all class files, recompiling them,
+ zipping them up, and running ProGuard again.
+ <p>
+ If your program classes reside in the same packages as library classes,
+ and refer to their package visible class members, then you should specify
+ the <code>-dontskipnonpubliclibraryclassmembers</code> option.</dd>
+
+<dt><a name="keep"><b>Error: You have to specify '-keep' options</b></a></dt>
+
+<dd>You either forgot to specify <code>-keep</code> options, or you mistyped
+ the class names. ProGuard has to know exactly what you want to keep: an
+ application, an applet, a servlet, a midlet,..., or any combination of
+ these. Without the proper seed specifications, ProGuard would shrink,
+ optimize, or obfuscate all class files away.</dd>
+
+</dl>
+<p>
+
+Should ProGuard crash while processing your application:
+
+<dl>
+<dt><a name="outofmemoryerror"><b>OutOfMemoryError</b></a></dt>
+
+<dd>You can try increasing the heap size of the Java virtual machine (with the
+ usual <code>-Xms</code> and <code>-Xmx</code> options). You can also
+ reduce the amount of memory that ProGuard needs by removing unnecessary
+ library jars from your configuration, or by filtering out unused library
+ packages and classes. Remember that only classes or interfaces that are
+ extended or implemented by classes in your input jars are required.</dd>
+
+<dt><a name="otherwise"><b>Otherwise...</b></a></dt>
+
+<dd>Maybe your class files are corrupt. See if recompiling them and trying
+ again helps. If not, please report the problem, preferably with the
+ simplest example that causes ProGuard to crash.</dd>
+
+</dl>
+<p>
+
+<a name="preverifying"> </a>
+<h2>Problems while preverifying for J2ME</h2>
+
+If ProGuard seems to run fine, but the preverifier subsequently produces
+errors, it's usually for a single reason:
+<dl>
+
+<dt><a name="invalidclassexception1"><b>InvalidClassException</b>,
+ <b>class loading error</b>, or
+ <b>verification error</b></a></dt>
+
+<dd>If you get any such message from the preverifier, you are probably working
+ on a platform with a case-insensitive file system, such as Windows. The
+ <code>preverify</code> tool always unpacks the jars, so class files with
+ similar lower-case and upper-case names overwrite each other. You can use
+ ProGuard's <code>-dontusemixedcaseclassnames</code> option to work around
+ this problem.</dd>
+
+</dl>
+<p>
+
+<a name="runtime"> </a>
+<h2>Problems at run-time</h2>
+
+If ProGuard runs fine, but your processed application doesn't work, there
+might be several reasons:
+
+<dl>
+<dt><a name="disappearingclasses"><b>Disappearing classes</b></a></dt>
+
+<dd>If you are working on Windows and it looks like some classes have
+ disappeared from your output, you should make sure you're not writing
+ your output class files to a directory (or unpacking the output jar). On
+ platforms with case-insensitive file systems, such as Windows, unpacking
+ tools often let class files with similar lower-case and upper-case names
+ overwrite each other. If you really can't switch to a different operating
+ system, you could consider using ProGuard's
+ <code>-dontusemixedcaseclassnames</code> option.</dd>
+
+<dt><a name="notkept"><b>Classes or class members not being kept</b></a></dt>
+
+<dd>If ProGuard is not keeping the right classes or class members, make
+ sure you are using fully qualified class names. If the package name of
+ some class is missing, ProGuard won't match the elements that you might be
+ expecting. It may help to double-check for typos too. You can use the
+ <code>-printseeds</code> option to see which elements are being kept
+ exactly.</dd>
+
+<dt><a name="stacktraces"><b>Stack traces without class names or line numbers</b></a></dt>
+
+<dd>If your stack traces don't contain any class names or lines numbers,
+ even though you are keeping the proper attributes, make sure this debugging
+ information is present in your compiled code to start with. Notably the Ant
+ javac task has debugging information switched off by default.</dd>
+
+<dt><a name="noclassdeffounderror"><b>NoClassDefFoundError</b></a></dt>
+
+<dd>Your class path is probably incorrect. It should at least contain all
+ library jars and, of course, your processed program jar.</dd>
+
+<dt><a name="classnotfoundexception"><b>ClassNotFoundException</b></a></dt>
+
+<dd>Your code is probably calling <code>Class.forName</code>, trying to create
+ the missing class dynamically. ProGuard can only detect constant name
+ arguments, like <code>Class.forName("mypackage.MyClass")</code>. For
+ variable name arguments like <code>Class.forName(someClass)</code>, you
+ have to keep all possible classes using the <code>-keep</code> option,
+ e.g. "<code>-keep class mypackage.MyClass</code>" or "<code>-keep class *
+ implements mypackage.MyInterface</code>".</dd>
+
+<dt><a name="nosuchmethodexception"><b>NoSuchMethodException</b></a></dt>
+
+<dd>Your code is probably calling something like
+ <code>myClass.getMethod</code>, trying to find some method dynamically.
+ Since ProGuard isn't detecting this (yet), you have to keep the missing
+ method in using the <code>-keep</code> option, e.g. "<code>-keep class
+ mypackage.MyClass { void myMethod(); }</code>".</dd>
+
+<dt><a name="nullpointerexception"><b>NullPointerException</b> (or missing resources, icons, sounds,...)</a></dt>
+
+<dd>Your processed code may be unable to find some resource files. ProGuard
+ currently simply copies resource files over from the input jars to the
+ output jar. Their names and contents remain unchanged. If you've used the
+ <code>-defaultpackage</code> option, the package names of some classes may
+ have changed, and along with them, the directory in which they look for
+ their resource files. It's better not to use this option in these
+ circumstances.</dd>
+
+<dt><a name="invalidclassexception2"><b>InvalidClassException</b>,
+ <b>class loading error</b>, or
+ <b>verification error</b> (in J2ME)</a></dt>
+
+<dd>If you get such an error in J2ME, you may have
+ forgotten to preverify your program jar <i>after</i> having processed it
+ with ProGuard.</dd>
+
+<dt><a name="securityexception"><b>SecurityException: SHA1 digest error</b></a></dt>
+
+<dd>You may have forgotten to sign your program jar <i>after</i> having
+ processed it with ProGuard.</dd>
+
+<dt><a name="nosuchfieldormethod"><b>Error: No Such Field or Method</b>,
+ <b>Error verifying method</b> (in J2ME emulator)</a></dt>
+
+<dd>If you get such a message in a Motorola or Sony Ericsson J2ME phone
+ emulator, it's because these emulators don't like packageless classes
+ and/or overloaded fields and methods. You can work around it by not using
+ the options <b>-defaultpackage ''</b> and <b>-overloadaggressively</b>. If
+ you're using the J2ME WTK plugin, you can adapt the configuration
+ <code>proguard/wtk/default.pro</code> that's inside the
+ <code>proguard.jar</code>.</dd>
+
+<dt><a name="classformaterror"><b>ClassFormatError: repetitive field name/signature</b></a></dt>
+
+<dd>You are probably processing some code that has been obfuscated before with
+ the <code>-overloadaggressively</code> option. You should then use the
+ same option again in the second processing round.</dd>
+
+<dt><a name="nosuchmethoderror"><b>NoSuchMethodError</b> or
+ <b>AbstractMethodError</b></a></dt>
+
+<dd>Again, you should make sure you're not writing your output class files to a
+ directory on a platform with a case-insensitive file system, such as
+ Windows. Please refer to the first item on this list for details.
+ <p>
+ Furthermore, you should check whether you have specified your program jars
+ and library jars properly. Program classes can refer to library classes,
+ but not the other way around.
+ <p>
+ If all of this seems ok, perhaps there's a bug in ProGuard (gasp!). If so,
+ please report it, preferably with the simplest example on which you can
+ find ProGuard to fail.</dd>
+
+</dl>
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/usage.html b/docs/manual/usage.html
new file mode 100644
index 0000000..6b96def
--- /dev/null
+++ b/docs/manual/usage.html
@@ -0,0 +1,849 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Usage</title>
+</head>
+<body>
+
+<h2>Usage</h2>
+
+To run ProGuard, just type:
+<p class="code">
+<code><b>java -jar proguard.jar </b></code><i>options</i> ...
+</p>
+Options can also be put in one or more configuration files. Typically, you'll
+put most options in a configuration file (say, <code>myconfig.pro</code>), and
+just call:
+<p class="code">
+<code><b>java -jar proguard.jar @myconfig.pro</b></code>
+</p>
+You can simply combine command line options and options from configuration
+files, e.g.:
+<p class="code">
+<code><b>java -jar proguard.jar @myconfig.pro -verbose</b></code>
+</p>
+<p>
+In a configuration file, a <code><b>#</b></code> sign and all remaining
+characters on that line are ignored, allowing you to add comments.
+<p>
+Extra whitespace between words and delimiters is ignored. To specify file
+names with spaces or special characters, words can be quoted with single or
+double quotes. Note that the quotes may need to be escaped when used on the
+command line, to avoid them being gobbled by the shell.
+<p>
+Options can be grouped arbitrarily in arguments on the command line and in
+lines in configuration files. This means that you can quote any arbitrary
+section of command line options, to avoid shell expansion of special
+characters, for instance.
+<p>
+The order of the options is generally irrelevant. They can be abbreviated to
+their first unique characters.
+<p>
+
+The sections below provide more details:
+<ul>
+<li><a href="#iooptions">Input/Output Options</a>
+<li><a href="#keepoptions">Keep Options</a>
+<li><a href="#shrinkingoptions">Shrinking Options</a>
+<li><a href="#optimizationoptions">Optimization Options</a>
+<li><a href="#obfuscationoptions">Obfuscation Options</a>
+<li><a href="#classpath">Class Paths</a>
+<li><a href="#filename">File Names</a>
+<li><a href="#filters">Filters</a>
+<li><a href="#keepoverview">Overview of <code>Keep</code> Options</a>
+<li><a href="#classspecification">Class Specifications</a>
+</ul>
+
+<a name="iooptions"> </a>
+<h2>Input/Output Options</h2>
+
+<dl>
+<dt><code><b>@</b></code><a href="#filename"><i>filename</i></a></dt>
+
+<dd>Short for '<code>-include</code> <i>filename</i>'.</dd>
+
+<dt><a name="include"><code><b>-include</b></code></a>
+ <a href="#filename"><i>filename</i></a></dt>
+
+<dd>Recursively reads configuration options from the given file
+ <i>filename</i>.</dd>
+
+<dt><a name="injars"><code><b>-injars</b></code></a>
+ <a href="#classpath"><i>class_path</i></a></dt>
+
+<dd>Specifies the input jars (or wars, ears, zips, or directories) of the
+ application to be processed. The class files in these jars will be
+ processed and written to the output jars. Any non-class files will be
+ copied without changes. Please be aware of any temporary files (e.g.
+ created by IDEs), especially if you are reading your input files straight
+ from directories. The entries in the class path can be filtered, as
+ explained in the <a href="#filters">filters</a> section. For better
+ readability, class path entries can be specified using multiple
+ <code>-injars</code> options.</dd>
+
+<dt><a name="outjars"><code><b>-outjars</b></code></a>
+ <a href="#classpath"><i>class_path</i></a></dt>
+
+<dd>Specifies the names of the output jars (or wars, ears, zips, or
+ directories). The processed input of the preceding <code>-injars</code>
+ options will be written to the named jars. This allows you to collect the
+ contents of groups of input jars into corresponding groups of output jars.
+ In addition, the output entries can be filtered, as explained in the <a
+ href="#filters">filters</a> section. Each processed class file or resource
+ file is then written to the first output entry with a matching filter,
+ within the group of output jars.
+ <p>
+ You must avoid letting the output files overwrite any input files. For
+ better readability, class path entries can be specified using multiple
+ <code>-outjars</code> options. Without any <code>-outjars</code> options,
+ no jars will be written.</dd>
+
+<dt><a name="libraryjars"><code><b>-libraryjars</b></code></a>
+ <a href="#classpath"><i>class_path</i></a></dt>
+
+<dd>Specifies the library jars (or wars, ears, zips, or directories) of the
+ application to be processed. The files in these jars will not be included
+ in the output jars. The specified library jars should at least contain the
+ class files that are <i>extended</i> by application class files. Library
+ class files that are only <i>called</i> needn't be present, although their
+ presence can improve the results of the optimization step. The entries in
+ the class path can be filtered, as explained in the <a
+ href="#filters">filters</a> section. For better readability, class path
+ entries can be specified using multiple <code>-libraryjars</code> options.
+ <p>
+ Please note that the boot path and the class path set for running ProGuard
+ are not considered when looking for library classes. This means that you
+ explicitly have to specify the run-time jar that your code will use.
+ Although this may seem cumbersome, it allows you to process applications
+ targeted at different run-time environments. For example, you can process
+ <a href="examples.html#application">J2SE applications</a> as well as <a
+ href="examples.html#midlet">J2ME midlets</a>, just by specifying the
+ appropriate run-time jar.</dd>
+
+<dt><a name="dontskipnonpubliclibraryclasses"><code><b>-dontskipnonpubliclibraryclasses</b></code></a></dt>
+
+<dd>Specifies not to ignore non-public library classes. By default, non-public
+ library classes are skipped while parsing library jars. The classes are
+ typically not relevant during processing, since they don't affect the
+ actual program code in the input jars. Ignoring them reduces memory usage
+ and processing time. Occasionally, a badly designed library may contain a
+ non-public library class that is extended/implemented by a public library
+ class. If the latter library class in turn is extended/implemented by a
+ program class, ProGuard will complain that it can't find the non-public
+ library class, which it had ignored during parsing. This option will
+ overcome that problem, at the cost of greater memory usage and longer
+ processing time.</dd>
+
+<dt><a name="dontskipnonpubliclibraryclassmembers"><code><b>-dontskipnonpubliclibraryclassmembers</b></code></a></dt>
+
+<dd>Specifies not to ignore package visible library class members (fields and
+ methods). By default, these class members are skipped while parsing
+ library classes, as program classes will generally not refer to them.
+ Sometimes however, program classes reside in the same packages as library
+ classes, and they do refer to their package visible class members. In
+ those cases, it can be useful to actually read the class members, in order
+ to make sure the processed code remains consistent.</dd>
+
+</dl>
+<p>
+
+<a name="keepoptions"> </a>
+<h2>Keep Options</h2>
+
+<dl>
+<dt><a name="keep"><code><b>-keep</b></code></a>
+ <a href="#classspecification"><i>class_specification</i></a></dt>
+
+<dd>Specifies classes and class members (fields and methods) to be preserved.
+ They will be preserved with their original names. This is typically the
+ required seed for recursively determining which other classes and class
+ members need to be preserved. For example, in order to <a
+ href="examples.html#application">keep an application</a>, you can specify
+ the main class along with its main method. In order to <a
+ href="examples.html#library">process a library</a>, you should specify all
+ publicly accessible items.</dd>
+
+<dt><a name="keepclassmembers"><code><b>-keepclassmembers</b></code></a>
+ <a href="#classspecification"><i>class_specification</i></a></dt>
+
+<dd>Specifies class members to be preserved, if their classes are preserved as
+ well. For example, you may want to <a
+ href="examples.html#serializable">keep all serialization fields and
+ methods</a> of classes that implement the <code>Serializable</code>
+ interface.</dd>
+
+<dt><a name="keepclasseswithmembers"><code><b>-keepclasseswithmembers</b></code></a>
+ <a href="#classspecification"><i>class_specification</i></a></dt>
+
+<dd>Specifies classes and class members to be preserved, on the condition that
+ all of the specified class members are present. For example, you may want
+ to <a href="examples.html#applications">keep all applications</a> that
+ have a main method, without having to list them explicitly.</dd>
+
+<dt><a name="keepnames"><code><b>-keepnames</b></code></a>
+ <a href="#classspecification"><i>class_specification</i></a></dt>
+
+<dd>Specifies classes and class members whose names are to be preserved, if
+ they aren't removed in the shrinking phase. For example, you may want to
+ <a href="examples.html#serializable">keep all class names</a> of classes
+ that implement the <code>Serializable</code> interface, so that the
+ processed code remains compatible with any originally serialized classes.
+ Classes that aren't used at all can still be removed. Only applicable when
+ obfuscating.</dd>
+
+<dt><a name="keepclassmembernames"><code><b>-keepclassmembernames</b></code></a>
+ <a href="#classspecification"><i>class_specification</i></a></dt>
+
+<dd>Specifies class members whose names are to be preserved, if they aren't
+ removed in the shrinking phase. For example, you may want to preserve the
+ name of the synthetic <code>class$</code> methods when <a
+ href="examples.html#library">processing a library</a>, so obfuscators can
+ detect it again when processing an application that uses the processed
+ library (although ProGuard itself doesn't need this). Only applicable when
+ obfuscating.</dd>
+
+<dt><a name="keepclasseswithmembernames"><code><b>-keepclasseswithmembernames</b></code></a>
+ <a href="#classspecification"><i>class_specification</i></a></dt>
+
+<dd>Specifies classes and class members whose names are to be preserved, on
+ the condition that all of the specified class members are present after
+ the shrinking phase. For example, you may want to <a
+ href="examples.html#native">keep all native method names</a> and the names
+ of their classes, so that the processed code can still link with the
+ native library code. Native methods that aren't used at all can still be
+ removed. If a class file is used, but none of its native methods are, its
+ name will still be obfuscated. Only applicable when obfuscating.</dd>
+
+<dt><a name="printseeds"><code><b>-printseeds</b></code></a>
+ [<a href="#filename"><i>filename</i></a>]</dt>
+
+<dd>Specifies to exhaustively list classes and class members matched by the
+ various <code>-keep</code> options. The list is printed to the standard
+ output or to the given file. The list can be useful to verify if the
+ intended class members are really found, especially if you're using
+ wildcards. For example, you may want to list all the <a
+ href="examples.html#applications">applications</a> or all the <a
+ href="examples.html#applets">applets</a> that you are keeping.</dd>
+
+</dl>
+<p>
+
+<a name="shrinkingoptions"> </a>
+<h2>Shrinking Options</h2>
+
+<dl>
+<dt><a name="dontshrink"><code><b>-dontshrink</b></code></a></dt>
+
+<dd>Specifies not to shrink the input class files. By default, shrinking is
+ applied; all classes and class members are removed, except for the ones
+ listed by the various <code>-keep</code> options, and the ones on which
+ they depend, directly or indirectly.</dd>
+
+<dt><a name="printusage"><code><b>-printusage</b></code></a>
+ [<a href="#filename"><i>filename</i></a>]</dt>
+
+<dd>Specifies to list dead code of the input class files. The list is printed
+ to the standard output or to the given file. For example, you can <a
+ href="examples.html#deadcode">list the unused code of an application</a>.
+ Only applicable when shrinking.</dd>
+
+</dl>
+<p>
+
+<a name="optimizationoptions"> </a>
+<h2>Optimization Options</h2>
+
+<dl>
+<dt><a name="dontoptimize"><code><b>-dontoptimize</b></code></a></dt>
+
+<dd>Specifies not to optimize the input class files. By default, optimization
+ is enabled; all methods are optimized at a bytecode level.</dd>
+
+<dt><a name="assumenosideeffects"><code><b>-assumenosideeffects</b></code></a>
+ <a href="#classspecification"><i>class_specification</i></a></dt>
+
+<dd>Specifies methods that don't have any side effects (other than maybe
+ returning a value). In the optimization step, ProGuard will then remove
+ calls to such methods, if it can determine that the return values aren't
+ used. Note that ProGuard will analyze your program code to find such
+ methods automatically. It will not analyze library code, for which this
+ option can thus be useful. For example, you could specify the method
+ <code>System.currentTimeMillis()</code>, so that any idle calls to it will
+ be removed. Only applicable when optimizing. In general, making
+ assumptions can be dangerous; you can break your application. <i>Only use
+ this option if you know what you're doing!</i></dd>
+
+<dt><a name="allowaccessmodification"><code><b>-allowaccessmodification</b></code></a></dt>
+
+<dd>Specifies that the access modifiers of classes and class members may be
+ modified during processing. This can improve the results of the
+ optimization step. For instance, when inlining a public getter, it may be
+ necessary to make the accessed field public too. Although Java's binary
+ compatibility specifications (cfr. <a href=
+ "http://java.sun.com/docs/books/jls/second_edition/html/j.title.doc.html"
+ >The Java Language Specification, Second Edition</a>, <a href=
+ "http://java.sun.com/docs/books/jls/second_edition/html/binaryComp.doc.html#47259"
+ >Section 13.4.6</a>) formally do not require this, some virtual machines
+ would have problems with the processed code otherwise. Only applicable
+ when optimizing.</dd>
+
+</dl>
+<p>
+
+<a name="obfuscationoptions"> </a>
+<h2>Obfuscation Options</h2>
+
+<dl>
+<dt><a name="dontobfuscate"><code><b>-dontobfuscate</b></code></a></dt>
+
+<dd>Specifies not to obfuscate the input class files. By default, obfuscation
+ is applied; classes and class members receive new short random names,
+ except for the ones listed by the various <code>-keep</code> options.
+ Internal attributes that are useful for debugging, such as source files
+ names, variable names, and line numbers are removed.</dd>
+
+<dt><a name="printmapping"><code><b>-printmapping</b></code></a>
+ [<a href="#filename"><i>filename</i></a>]</dt>
+
+<dd>Specifies to print the mapping from old names to new names for classes and
+ class members that have been renamed. The mapping is printed to the
+ standard output or to the given file. It is required for subsequent
+ incremental obfuscation, or if you ever want to make sense again of <a
+ href="examples.html#stacktrace">obfuscated stack traces</a>. Only
+ applicable when obfuscating.</dd>
+
+<dt><a name="applymapping"><code><b>-applymapping</b></code></a>
+ <a href="#filename"><i>filename</i></a></dt>
+
+<dd>Specifies to reuse the given name mapping that was printed out in a
+ previous obfuscation run of ProGuard. Classes and class members that are
+ listed in the mapping file receive the names specified along with them.
+ Classes and class members that are not mentioned receive new names. The
+ mapping may refer to input classes as well as library classes. This option
+ can be useful for <a href="examples.html#incremental">incremental
+ obfuscation</a>, i.e. processing add-ons or small patches to an existing
+ piece of code. Only applicable when obfuscating.</dd>
+
+<dt><a name="obfuscationdictionary"><code><b>-obfuscationdictionary</b></code></a>
+ <a href="#filename"><i>filename</i></a></dt>
+
+<dd>Specifies a text file from which all valid words are used as obfuscated
+ method names. White space, punctuation characters, duplicate words, and
+ comments after a <code><b>#</b></code> sign are ignored. By default, short
+ names like 'a', 'b', etc. are used as obfuscated method names. With an
+ obfuscation dictionary, you can specify a list of reserved key words, or
+ identifiers with foreign characters, for instance. Note that this hardly
+ improves the obfuscation. Decent compilers can automatically replace them,
+ and the effect can fairly simply be undone by obfuscating again with
+ simpler names. The most useful application is specifying strings that are
+ typically already present in class files (such as 'Code' and
+ 'Exceptions'), thus reducing the class file sizes just a little bit more.
+ Only applicable when obfuscating.</dd>
+
+<dt><a name="overloadaggressively"><code><b>-overloadaggressively</b></code></a></dt>
+
+<dd>Specifies to apply aggressive overloading while obfuscating. Multiple
+ fields and methods can then get the same names, as long as their arguments
+ and return types are different (not just their arguments). This option can
+ make the output jar even smaller (and less comprehensible). Only
+ applicable when obfuscating.
+ <p>
+ Counter-indications: the resulting class files fall within the Java
+ bytecode specification (cfr. <a href=
+ "http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html"
+ >The Java Virtual Machine Specification, Second Edition</a>, first
+ paragraphs of <a href=
+ "http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#2877"
+ >Section 4.5</a> and <a href=
+ "http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#1513"
+ >Section 4.6</a>), even though this kind of overloading is not allowed in
+ the Java language (cfr. <a href=
+ "http://java.sun.com/docs/books/jls/second_edition/html/j.title.doc.html"
+ >The Java Language Specification, Second Edition</a>, <a href=
+ "http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#40898"
+ >Section 8.3</a> and <a href=
+ "http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#227768"
+ >Section 8.4.7</a>). Still, some tools have problems with it. Notably,
+ Sun's JREs 1.4 and later fail to serialize objects with overloaded
+ primitive fields. Also, Sun's JDK 1.2.2 javac compiler produces an
+ exception when compiling with such a library (cfr. <a href=
+ "http://developer.java.sun.com/developer/bugParade/bugs/4216736.html">Bug
+ #4216736</a>). You therefore probably shouldn't use this option for
+ processing libraries.</dd>
+
+<dt><a name="defaultpackage"><code><b>-defaultpackage</b></code></a>
+ [<i>package_name</i>]</dt>
+
+<dd>Specifies to repackage all class files that are renamed into the single
+ given package. Without argument or with an empty string (''), the package
+ is removed completely. This option can make the output jar even smaller
+ (and less comprehensible). Only applicable when obfuscating.
+ <p>
+ This option implies the <a
+ href="#allowaccessmodification"><code><b>-allowaccessmodification</b></code></a>
+ option. In this case, ProGuard avoids access permissions becoming
+ inconsistent, by making all package visible classes and class members
+ public. These changes don't affect the functioning of applications. It
+ might be confusing and therefore less desirable when processing libraries.
+ <p>
+ Counter-indications: classes that look for resource files in their package
+ directories will no longer work properly if they are moved elsewhere. When
+ in doubt, just leave the packaging untouched by not using this
+ option.</dd>
+
+<dt><a name="dontusemixedcaseclassnames"><code><b>-dontusemixedcaseclassnames</b></code></a></dt>
+
+<dd>Specifies not to generate mixed-case class names while obfuscating. By
+ default, obfuscated class names can contain a mix of upper-case characters
+ and lower-case characters. This creates perfectly acceptable and usable
+ jars. Only if a jar is unpacked on a platform with a case-insensitive
+ filing system (say, Windows), the unpacking tool may let similarly named
+ class files overwrite each other. Code that self-destructs when it's
+ unpacked! Developers who really want to unpack their jars on Windows can
+ use this option to switch off this behavior. Note that the obfuscated jars
+ will become larger as a result. Only applicable when obfuscating.</dd>
+
+<dt><a name="keepattributes"><code><b>-keepattributes</b></code></a>
+ [<i>attribute_name<b>,</b>...</i>]</dt>
+
+<dd>Specifies any optional attributes to be preserved. The attributes can be
+ specified with one or more <code>-keepattributes</code> directives.
+ Multiple attributes should be separated by commas. An empty list preserves
+ all attributes. Attribute names can contain <b>?</b> and
+ <b>*</b> wildcards, and they can be preceded by the <b>!</b> negator (much
+ like file name filters). Typical optional attributes are
+ <code>LineNumberTable</code>, <code>LocalVariableTable</code>,
+ <code>LocalVariableTypeTable</code>, <code>SourceFile</code>,
+ <code>SourceDir</code>, <code>Deprecated</code>, <code>Synthetic</code>,
+ <code>Signature</code>, <code>EnclosingMethod</code>,
+ <code>RuntimeVisibleAnnotations</code>,
+ <code>RuntimeInvisibleAnnotations</code>,
+ <code>RuntimeVisibleParameterAnnotations</code>,
+ <code>RuntimeInvisibleParameterAnnotations</code>, and
+ <code>AnnotationDefault</code>. The <code>InnerClasses</code> attribute
+ name can be specified as well, referring to the source name part of this
+ attribute. For example, you could keep the <code>Deprecated</code>
+ attribute when <a href="examples.html#library">processing a library</a>.
+ Only applicable when obfuscating.</dd>
+
+<dt><a name="renamesourcefileattribute"><code><b>-renamesourcefileattribute</b></code></a>
+ [<i>string</i>]</dt>
+
+<dd>Specifies a constant string to be put in the <code>SourceFile</code>
+ attributes (and <code>SourceDir</code> attributes) of the class files.
+ Note that the attribute has to be present to start with, so it also has to
+ be preserved explicitly using the <code>-keepattributes</code> directive.
+ For example, you may want to have your processed libraries and
+ applications produce <a href="examples.html#stacktrace">useful obfuscated
+ stack traces</a>. Only applicable when obfuscating.</dd>
+
+</dl>
+<p>
+
+<a name="generaloptions"> </a>
+<h2>General Options</h2>
+
+<dl>
+<dt><a name="verbose"><code><b>-verbose</b></code></a></dt>
+
+<dd>Specifies to write out some more information during processing. If the
+ program terminates with an exception, this option will print out the entire
+ stack trace, instead of just the exception message.</dd>
+
+<dt><a name="dontnote"><code><b>-dontnote</b></code></a></dt>
+
+<dd>Specifies not to print notes about class casts of variable dynamically
+ created objects. These notes provide hints about classes that may have to
+ be kept.</dd>
+
+<dt><a name="dontwarn"><code><b>-dontwarn</b></code></a></dt>
+
+<dd>Specifies not to warn about unresolved references at all. Again, if the
+ unresolved classes or class members are indeed required for processing,
+ the output jar will not function properly. <i>Only use this option if you
+ know what you're doing!</i></dd>
+
+<dt><a name="ignorewarnings"><code><b>-ignorewarnings</b></code></a></dt>
+
+<dd>Specifies to print any warnings about unresolved references to
+ superclasses, interfaces, or class members, but to continue processing in
+ any case. If the classes or class members are indeed required for
+ processing, the output jar will not function properly. <i>Only use this
+ option if you know what you're doing!</i></dd>
+
+<dt><a name="dump"><code><b>-dump</b></code></a>
+ [<a href="#filename"><i>filename</i></a>]</dt>
+
+<dd>Specifies to write out the internal structure of the class files, after
+ any processing. The structure is printed to the standard output or to the
+ given file. For example, you may want to <a
+ href="examples.html#structure">write out the contents of a given jar
+ file</a>, without shrinking or obfuscating it first.</dd>
+
+</dl>
+<p>
+
+<a name="classpath"> </a>
+<h2>Class Paths</h2>
+
+ProGuard accepts a generalisation of class paths to specify input files and
+output files. A class path consists of entries, separated by the path
+separator (e.g. '<b>:</b>' on Unix, or '<b>;</b>' on Windows platforms). The
+order of the entries determines their priorities, in case of duplicates.
+<p>
+Each input entry can be:
+<ul>
+<li>A class file or resource file.
+<li>A jar file, containing any of the above,
+<li>A war file, containing any of the above,
+<li>An ear file, containing any of the above,
+<li>A zip file, containing any of the above,
+<li>A directory (structure), containing any of the above.
+</ul>
+<p>
+The paths of directly specified class files and resource files is ignored, so
+class files should generally be part of a jar file, a war file, an ear file, a
+zip file, or a directory. In addition, the paths of class files should not have
+any additional directory prefixes inside the archives or directories.
+
+<p>
+Each output entry can be:
+<ul>
+<li>A jar file, in which all processed class files and resource files will be
+ collected.
+<li>A war file, in which any and all of the above will be collected,
+<li>An ear file, in which any and all of the above will be collected,
+<li>A zip file, in which any and all of the above will be collected,
+<li>A directory, in which any and all of the above will be collected.
+</ul>
+<p>
+When writing output entries, ProGuard will generally package the results in a
+sensible way, reconstructing the input entries as much as required. Writing
+everything to an output directory is the most straightforward option: the
+output directory will contain a complete reconstruction of the input entries.
+The packaging can be almost arbitrarily complex though: you could process an
+entire application, packaged in a zip file along with its documentation,
+writing it out as a zip file again.
+<p>
+Files and directories can be specified as discussed in the section on <a
+href="#filename">file names</a> below.
+<p>
+In addition, the individual class patch entries and their contents can be
+filtered, as explained in the <a href="#filters">filters</a> section below.
+This allows for an almost infinite number of packaging and repackaging
+possibilities.
+<p>
+
+<a name="filename"> </a>
+<h2>File Names</h2>
+
+ProGuard accepts absolute paths and relative paths for the various file names
+and directory names.
+<p>
+The names can contain Java system properties delimited by '<b><</b>' and
+'<b>></b>'. The system properties
+are automatically replaced by their respective values.
+<p>
+For example, <code><java.home>/lib/rt.jar</code> will automatically be
+expanded to something like <code>/usr/local/java/jdk/jre/lib/rt.jar</code>.
+<p>
+Names with special characters like spaces and parentheses must be quoted
+with single or double quotes. Note that each file name in a list of names has
+to be quoted individually. Also note that the quotes may need to be escaped
+when used on the command line, to avoid them being gobbled by the shell.
+<p>
+For example, on the command line, you could use an option like <code>'-injars
+"my program.jar":"/your directory/your program.jar"'</code>.
+<p>
+
+<a name="filters"> </a>
+<h2>Filters</h2>
+
+ProGuard provides the possibility to filter the class path entries and their
+contents, based on their full relative file names. Each class path entry can
+be followed by up to 5 types of filters between parentheses, separated by
+semi-colons:
+<ul>
+<li>A filter for all zip names that are encountered,
+<li>A filter for all ear names that are encountered,
+<li>A filter for all war names that are encountered,
+<li>A filter for all jar names that are encountered,
+<li>A filter for all class file names and resource file names that are
+ encountered.
+</ul>
+<p>
+If fewer than 5 filters are specified, they are assumed to be the latter
+filters. Any empty filters are ignored. More formally, a filtered class path
+entry looks like this:
+<pre>
+<i>classpathentry</i><b>(</b>[[[[<i>zipfilter</i><b>;</b>]<i>earfilter</i><b>;</b>]<i>warfilter</i><b>;</b>]<i>jarfilter</i><b>;</b>]<i>filefilter</i><b>)</b>
+</pre>
+<p>
+Square brackets "[]" mean that their contents are optional.
+
+<p>
+A filter consists of one or more comma-separated file names that can contain
+wildcards. Only files with matching file names are read (in the case of input
+jars), or written (in the case of output jars). The following wildcards are
+supported:
+
+<table cellspacing="10">
+<tr><td valign="top"><code><b>?</b></code></td>
+ <td>matches any single character in a file name.</td></tr>
+<tr><td valign="top"><code><b>*</b></code></td>
+ <td>matches any part of a filename not containing the directory
+ separator.</td></tr>
+<tr><td valign="top"><code><b>**</b></code></td>
+ <td>matches any part of a filename, possibly containing any number of
+ directory separators.</td></tr>
+</table>
+
+For example, "<code>rt.jar(java/**.class,javax/**.class)</code>" matches all
+class files in the <code>java</code> and <code>javax</code> directories inside
+the <code>rt</code> jar.
+<p>
+
+Furthermore, a file name can be preceded by an exclamation mark '<b>!</b>' to
+<i>exclude</i> the file name from further attempts to match with
+<i>subsequent</i> file names. You can think of the filtering mechanism as a
+conveyor belt, with pushers that accept or reject files as they pass by.
+<p>
+For example, "<code>input.jar(!**.gif,images/**)</code>" matches all files in
+the <code>images</code> directory inside the <code>input</code> jar, except
+gif files.
+<p>
+
+Note that the different filters are applied to all corresponding file types,
+irrespective of their nesting levels in the input; they are orthogonal.
+<p>
+For example,
+"<code>input.war(lib/**.jar,support/**.jar;**.class,**.gif)</code>" only
+considers jar files in the <code>lib</code> and <code>support</code>
+directories in the <code>input</code> war, not any other jar files. It then
+matches all class files and gif files that are encountered.
+
+<a name="keepoverview"> </a>
+<h2>Overview of <code>Keep</code> Options</h2>
+
+The various <code>-keep</code> options for shrinking and obfuscation may seem
+a bit confusing at first, but there's actually a pattern behind them. The
+following table summarizes how they are related:
+<p>
+
+<table cellpadding="5">
+
+<tr>
+<th>Keep</th>
+<td>From being removed or renamed</td>
+<td>From being renamed</td>
+</tr>
+
+<tr>
+<td>Classes and class members</td>
+<td bgcolor="#E0E0E0"><code>-keep</code></td>
+<td bgcolor="#E0E0E0"><code>-keepnames</code></td>
+</tr>
+
+<tr>
+<td>Class members only</td>
+<td bgcolor="#E0E0E0"><code>-keepclassmembers</code></td>
+<td bgcolor="#E0E0E0"><code>-keepclassmembernames</code></td>
+</tr>
+
+<tr>
+<td>Classes and class members, if class members present</td>
+<td bgcolor="#E0E0E0"><code>-keepclasseswithmembers</code></td>
+<td bgcolor="#E0E0E0"><code>-keepclasseswithmembernames</code></td>
+</tr>
+
+</table>
+<p>
+
+Each of these <code>-keep</code> options is of course followed by a
+<a href="#classspecification">specification</a> of the classes and class
+members (fields and methods) to which it should be applied.
+<p>
+If you're not sure which option you need, you should probably simply use
+<code>-keep</code>. It will make sure the specified classes and class members
+are not removed in the shrinking step, and not renamed in the obfuscation step.
+<p>
+
+<a name="classspecification"> </a>
+<h2>Class Specifications</h2>
+
+A class specification is a template of classes and class members (fields and
+methods). It is used in the various <code>-keep</code> options and in the
+<code>-assumenosideeffects</code> option. The corresponding option is only
+applied to classes and class members that match the template.
+<p>
+The template was designed to look very Java-like, with some extensions for
+wildcards. To get a feel for the syntax, you should probably look at the <a
+href="examples.html">examples</a>, but this is an attempt at a complete formal
+definition:
+<p>
+
+<pre>
+[[<b>!</b>]<b>public</b>|<b>final</b>|<b>abstract</b> ...] ([<b>!</b>]<b>interface</b>)|<b>class</b> <i>classname</i>
+ [<b>extends</b>|<b>implements</b> <i>classname</i>]
+[<b>{</b>
+ [[<b>!</b>]<b>public</b>|<b>private</b>|<b>protected</b>|<b>static</b>|<b>volatile</b>|<b>transient</b> ...] <b><fields></b> |
+ (<i>fieldtype fieldname</i>)<b>;</b>
+ [[<b>!</b>]<b>public</b>|<b>private</b>|<b>protected</b>|<b>static</b>|<b>synchronized</b>|<b>native</b>|<b>abstract</b>|<b>strictfp</b> ...] <b><methods></b> |
+ <b><init>(</b><i>argumenttype,...</i><b>)</b> |
+ <i>classname</i><b>(</b><i>argumenttype,...</i><b>)</b> |
+ (<i>returntype methodname</i><b>(</b><i>argumenttype,...</i><b>)</b>)<b>;</b>
+ [[<b>!</b>]<b>public</b>|<b>private</b>|<b>protected</b>|<b>static</b> ... ] <b>*;</b>
+ ...
+<b>}</b>]
+</pre>
+<p>
+Square brackets "[]" mean that their contents are optional. Ellipsis dots
+"..." mean that any number of the preceding items may be specified. A vertical
+bar "|" delimits two alternatives. Non-bold parentheses "()" just group parts
+of the specification that belong together. The indentation tries to clarify
+the intended meaning, but white-space is irrelevant in actual configuration
+files.
+<p>
+<ul>
+
+<li>The <code><b>class</b></code> keyword refers to any interface or class.
+ The <code><b>interface</b></code> keyword restricts matches to interface
+ classes. Preceding the <code><b>interface</b></code> keyword by a
+ <code><b>!</b></code> restricts matches to classes that are not
+ interfaces.
+ <p>
+
+<li>Every <i>classname</i> must be fully qualified, e.g.
+ <code>java.lang.String</code>. Class names may be specified as regular
+ expressions containing the following wildcards:
+
+<table cellspacing="10">
+
+<tr><td valign="top"><code><b>?</b></code></td>
+
+<td>matches any single character in a class name, but not the package
+ separator. For example, "<code>mypackage.Test?</code>" matches
+ "<code>mypackage.Test1</code>" and "<code>mypackage.Test2</code>", but not
+ "<code>mypackage.Test12</code>".</td></tr>
+
+<tr><td valign="top"><code><b>*</b></code></td>
+
+<td>matches any part of a class name not containing the package separator. For
+ example, "<code>mypackage.*Test*</code>" matches
+ "<code>mypackage.Test</code>" and
+ "<code>mypackage.YourTestApplication</code>", but not
+ "<code>mypackage.mysubpackage.MyTest</code>". Or, more generally,
+ "<code>mypackage.*</code>" matches all classes in
+ "<code>mypackage</code>", but not in its subpackages.</td></tr>
+
+<tr><td valign="top"><code><b>**</b></code></td>
+
+<td>matches any part of a class name, possibly containing any number of
+ package separators. For example, "<code>**.Test</code>" matches all
+ <code>Test</code> classes in all packages except the root package. Or,
+ "<code>mypackage.**</code>" matches all classes in
+ "<code>mypackage</code>" and in its subpackages.</td></tr>
+
+</table>
+
+ For convenience and for backward compatibility, the class name
+ <code><b>*</b></code> refers to any class, irrespective of its package.
+ <p>
+
+<li>The <code><b>extends</b></code> and <code><b>implements</b></code>
+ specifications are typically used to restrict classes with wildcards. They
+ are currently equivalent, specifying that only classes extending or
+ implementing the given class qualify. Note that the given class itself is
+ not included in this set. If required, it should be specified in a
+ separate option.
+ <p>
+
+<li>Fields and methods are specified much like in Java, except that method
+ argument lists don't contain argument names (as is common in other tools
+ like <code>javadoc</code> and <code>javap</code>). The specifications can
+ also contain the following catch-all wildcards:
+
+<table cellspacing="10">
+
+<tr><td valign="top"><code><b><init></b></code></td>
+<td>matches any constructor.</td></tr>
+
+<tr><td valign="top"><code><b><fields></b></code></td>
+<td>matches any field.</td></tr>
+
+<tr><td valign="top"><code><b><methods></b></code></td>
+<td>matches any method.</td></tr>
+
+<tr><td valign="top"><code><b>*</b></code></td>
+<td>matches any field or method.</td></tr>
+
+</table>
+
+ Note that the above wildcards don't have return types. Only the
+ <code><b><init></b></code> wildcard has an argument list.
+ <p>
+
+ Fields and methods may also be specified using regular expressions. Names
+ can contain the following wildcards:
+
+<table cellspacing="10">
+<tr><td valign="top"><code><b>?</b></code></td>
+ <td>matches any single character in a method name.</td></tr>
+<tr><td valign="top"><code><b>*</b></code></td>
+ <td>matches any part of a method name.</td></tr>
+</table>
+
+ Types in descriptors can contain the following wildcards:
+
+<table cellspacing="10">
+<tr><td valign="top"><code><b>?</b></code></td>
+ <td>matches any single character in a class name.</td></tr>
+<tr><td valign="top"><code><b>*</b></code></td>
+ <td>matches any part of a class name not containing the package separator.</td></tr>
+<tr><td valign="top"><code><b>**</b></code></td>
+ <td>matches any part of a class name, possibly containing any number of
+ package separators.</td></tr>
+<tr><td valign="top"><code><b>%</b></code></td>
+ <td>matches any primitive type ("<code>boolean</code>", "<code>int</code>",
+ etc, but not "<code>void</code>").</td></tr>
+</table>
+
+ Note that the <code>?</code>, <code>*</code>, and <code>**</code>
+ wildcards will never match primitive types. None of the wildcards will
+ match array types of different dimensions than specified by the regular
+ expression. For example, "<code>** get*()</code>" matches
+ "<code>java.lang.Object getObject()</code>", but not "<code>float
+ getFloat()</code>", nor "<code>java.lang.Object[] getObjects()</code>".
+ <p>
+
+<li>Constructors can also be specified using their short class names (without
+ package) or using their full class names. As in the Java language, the
+ constructor specification has an argument list, but no return type.
+ <p>
+
+<li>The class access modifiers and class member access modifiers are typically
+ used to restrict wildcarded classes and class members. They specify that
+ the corresponding access flags have to be set for the member to match. A
+ preceding <code><b>!</b></code> specifies that the corresponding access
+ flag should be unset.
+ <p>
+ Combining multiple flags is allowed (e.g. <code>public static</code>). It
+ means that both access flags have to be set (e.g. <code>public</code>
+ <i>and</i> <code>static</code>), except when they are conflicting, in
+ which case at least one of them has to be set (e.g. at least
+ <code>public</code>
+ <i>or</i> <code>protected</code>).
+
+</ul>
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/manual/wtk.html b/docs/manual/wtk.html
new file mode 100644
index 0000000..5c3325f
--- /dev/null
+++ b/docs/manual/wtk.html
@@ -0,0 +1,58 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard J2ME Wireless Toolkit Integration</title>
+</head>
+<body>
+
+<h2>J2ME Wireless Toolkit Integration</h2>
+
+<b>ProGuard</b> can be seamlessly integrated in the Sun J2ME Wireless Toolkit
+(WTK).
+<p>
+
+The WTK already comes with a plug-in for ProGuard. Alternatively, ProGuard
+offers its own implementation. The latter implementation solves some problems
+and is somewhat more efficient. It invokes the ProGuard engine directly,
+instead of writing out a configuration file and running ProGuard in a separate
+virtual machine.
+<p>
+
+In order to integrate this plug-in in the toolkit, you'll have to put the
+following lines in the file
+{j2mewtk.dir}<code>/wtklib/Linux/ktools.properties</code> or
+{j2mewtk.dir}<code>\wtklib\Windows\ktools.properties</code> (whichever is
+applicable).
+<p>
+
+<pre>
+obfuscator.runner.class.name: proguard.wtk.ProGuardObfuscator
+obfuscator.runner.classpath: /usr/local/java/proguard/lib/proguard.jar
+</pre>
+<p>
+
+Please make sure the class path is set correctly for your system.
+<p>
+
+Once ProGuard has been set up, you can apply it to your projects as part of
+the build process. The build process is started from the WTK menu bar:
+<p>
+<center><b>Project -> Package -> Create Obfuscated Package</b></center>
+<p>
+This option will compile, shrink, obfuscate, verify, and install your midlets
+for testing.
+<p>
+Should you ever need to customize your ProGuard configuration for the J2ME WTK,
+you can adapt the configuration file <code>proguard/wtk/default.pro</code>
+that's inside the <code>proguard.jar</code>.
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/quality.html b/docs/quality.html
new file mode 100644
index 0000000..fe8f4df
--- /dev/null
+++ b/docs/quality.html
@@ -0,0 +1,37 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Quality</title>
+</head>
+<body>
+
+<h2>Quality</h2>
+
+In order to get a feel for the quality of the <b>ProGuard</b> code, it is run
+through a nightly automatic build process. This process produces numerous
+statistics on the source code, Java lint comments, Java documentation
+comments, the Java documentation itself, html lint comments on the Java
+documentation, spell checks, compilation results, an output jar, dead code
+analysis, a shrunk and obfuscated jar (using ProGuard itself!), test runs with
+memory and performance analyses, etc. Most analyses are produced using freely
+available tools. The results are poured into a convenient set of web pages
+using bash/sed/awk scripts. You're welcome to have a look at them:
+<p>
+<center><a href="http://proguard.sourceforge.net/quality/"
+target="other">Automated Code Analysis and Testing Pages</a> (at <a
+href="http://sourceforge.net/projects/proguard/"
+target="other">SourceForge</a>)</center>
+<p>
+The pages will appear in a new window, which you probably want to view at
+full-screen size.
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/results.html b/docs/results.html
new file mode 100644
index 0000000..b62a629
--- /dev/null
+++ b/docs/results.html
@@ -0,0 +1,134 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Results</title>
+</head>
+<body>
+
+<h2>Results</h2>
+
+<b>ProGuard</b> shrinks, optimizes, and obfuscates jars quickly and
+effectively. The benefits obviously depend on the original code. The table
+below presents some typical results:
+<p>
+
+<table>
+
+<tr>
+<th width="28%">Input Program</th>
+<th width="12%">Original size</th>
+<th width="12%">After shrinking</th>
+<th width="12%">After optim.</th>
+<th width="12%">After obfusc.</th>
+<th width="12%">Total reduction</th>
+<th width="12%">Time</th>
+<th width="12%">Memory usage</th>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.gnu.org/software/classpath/">ClassPath</a>, the GNU runtime library</td>
+<td align="center">2.0 M</td>
+<td align="center">2.0 M</td>
+<td align="center">1.9 M</td>
+<td align="center">1.9 M</td>
+<td align="center">4 %</td>
+<td align="center">31 s</td>
+<td align="center">39 M</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://java.sun.com/j2me/">Worm</a>, a sample midlet from Sun's J2ME</td>
+<td align="center">9.9 K</td>
+<td align="center">9.4 K</td>
+<td align="center">9.3 K</td>
+<td align="center">8.1 K</td>
+<td align="center">17 %</td>
+<td align="center">2 s</td>
+<td align="center">13 M</td>
+</tr>
+
+<tr>
+<td><b>ProGuard</b> itself</td>
+<td align="center">404 K</td>
+<td align="center">364 K</td>
+<td align="center">361 K</td>
+<td align="center">231 K</td>
+<td align="center">42 %</td>
+<td align="center">21 s</td>
+<td align="center">35 M</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.clarkware.com/software/JDepend.html">JDepend</a>, a Java quality metrics tool</td>
+<td align="center">57 K</td>
+<td align="center">36 K</td>
+<td align="center">35 K</td>
+<td align="center">30 K</td>
+<td align="center">48 %</td>
+<td align="center">8 s</td>
+<td align="center">24 M</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://jakarta.apache.org/tomcat/index.html">Tomcat</a>, the Apache servlet container</td>
+<td align="center">1.2 M</td>
+<td align="center">538 K</td>
+<td align="center">528 K</td>
+<td align="center">363 K</td>
+<td align="center">68 %</td>
+<td align="center">20 s</td>
+<td align="center">39 M</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://www.kclee.com/clemens/java/javancss/">JavaNCSS</a>, a Java source metrics tool</td>
+<td align="center">624 K</td>
+<td align="center">243 K</td>
+<td align="center">235 K</td>
+<td align="center">158 K</td>
+<td align="center">74 %</td>
+<td align="center">13 s</td>
+<td align="center">35 M</td>
+</tr>
+
+<tr>
+<td><a target="other" href="http://ant.apache.org/">Ant</a>, the Apache build tool</td>
+<td align="center">2.3 M</td>
+<td align="center">276 K</td>
+<td align="center">265 K</td>
+<td align="center">203 K</td>
+<td align="center">91 %</td>
+<td align="center">20 s</td>
+<td align="center">49 M</td>
+</tr>
+
+</table>
+<p>
+Results were measured with ProGuard 3.0 on a 2.6 GHz Pentium 4 with 512 MB
+of memory, using Sun JDK 1.4.2 in Fedora Core 1 Linux.
+<p>
+The program sizes include companion libraries. The shrinking step produces the
+best results for programs that use only small parts of their libraries. The
+obfuscation step can significantly shrink large programs even further, since
+the identifiers of their many internal references can be replaced by short
+identifiers.
+<p>
+Timings are mainly governed by the fixed overhead of reading jars and
+initializing data structures. The actual shrinking, optimization, and
+obfuscation are typically fast in comparison.
+<p>
+Memory usage (the amount of physical memory used by ProGuard while processing)
+is governed by the basic java virtual machine and the total size of the
+library jars and program jars.
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+
+</body>
+</html>
diff --git a/docs/screenshot_console.gif b/docs/screenshot_console.gif
new file mode 100644
index 0000000..f920538
Binary files /dev/null and b/docs/screenshot_console.gif differ
diff --git a/docs/screenshot_console_small.gif b/docs/screenshot_console_small.gif
new file mode 100644
index 0000000..f8cd9dc
Binary files /dev/null and b/docs/screenshot_console_small.gif differ
diff --git a/docs/screenshot_gui1.gif b/docs/screenshot_gui1.gif
new file mode 100644
index 0000000..68b1ee9
Binary files /dev/null and b/docs/screenshot_gui1.gif differ
diff --git a/docs/screenshot_gui2.gif b/docs/screenshot_gui2.gif
new file mode 100644
index 0000000..4ab61af
Binary files /dev/null and b/docs/screenshot_gui2.gif differ
diff --git a/docs/screenshot_gui3.gif b/docs/screenshot_gui3.gif
new file mode 100644
index 0000000..5805e39
Binary files /dev/null and b/docs/screenshot_gui3.gif differ
diff --git a/docs/screenshot_gui4.gif b/docs/screenshot_gui4.gif
new file mode 100644
index 0000000..9326203
Binary files /dev/null and b/docs/screenshot_gui4.gif differ
diff --git a/docs/screenshot_gui5.gif b/docs/screenshot_gui5.gif
new file mode 100644
index 0000000..ac510e9
Binary files /dev/null and b/docs/screenshot_gui5.gif differ
diff --git a/docs/screenshot_gui6.gif b/docs/screenshot_gui6.gif
new file mode 100644
index 0000000..f75027a
Binary files /dev/null and b/docs/screenshot_gui6.gif differ
diff --git a/docs/screenshot_gui7.gif b/docs/screenshot_gui7.gif
new file mode 100644
index 0000000..12e088c
Binary files /dev/null and b/docs/screenshot_gui7.gif differ
diff --git a/docs/screenshot_gui8.gif b/docs/screenshot_gui8.gif
new file mode 100644
index 0000000..f862ccf
Binary files /dev/null and b/docs/screenshot_gui8.gif differ
diff --git a/docs/screenshots.html b/docs/screenshots.html
new file mode 100644
index 0000000..61f401b
--- /dev/null
+++ b/docs/screenshots.html
@@ -0,0 +1,56 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Screenshots</title>
+</head>
+<body>
+
+<h2>Screenshots</h2>
+
+<table><tr><td>
+<a href="screenshot_gui1.gif" target="other">
+<img src="screenshots_gui_small.gif" width="320" height="223" align="right"
+ alt="GUI screenshot" usemap="#guimap"></a>
+
+<map id="guimap" name="guimap">
+<area shape="rect" coords="2,7,46,16" alt="ProGuard" href="screenshot_gui1.gif" target="other">
+<area shape="rect" coords="2,17,46,27" alt="Input/Output" href="screenshot_gui2.gif" target="other">
+<area shape="rect" coords="2,28,46,37" alt="Shrinking" href="screenshot_gui3.gif" target="other">
+<area shape="rect" coords="2,38,46,48" alt="Optimization" href="screenshot_gui4.gif" target="other">
+<area shape="rect" coords="2,49,46,58" alt="Obfuscation" href="screenshot_gui5.gif" target="other">
+<area shape="rect" coords="2,59,46,69" alt="Information" href="screenshot_gui6.gif" target="other">
+<area shape="rect" coords="2,70,46,79" alt="Process" href="screenshot_gui7.gif" target="other">
+<area shape="rect" coords="2,80,46,90" alt="ReTrace" href="screenshot_gui8.gif" target="other">
+</map>
+
+The graphical user interface to <b>ProGuard</b> works like a wizard. It allows
+you to browse through the presented tabs and fill them out.
+<p>
+You can click on the small tab buttons to see the full-size versions of the
+tabs.
+
+</td></tr>
+<tr><td>
+<a href="screenshot_console.gif" target="other">
+<img src="screenshot_console_small.gif" width="320" height="268" align="left"
+ alt="Console screenshot"></a>
+
+Of course, real developers don't need all this point-and-click fluff. They
+write a short configuration file using their favorite text editor and invoke
+<b>ProGuard</b> from the command-line.
+<p>
+You can click on the image to see the full-size version.
+
+</td></tr></table>
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+</body>
+</html>
diff --git a/docs/screenshots_gui_small.gif b/docs/screenshots_gui_small.gif
new file mode 100644
index 0000000..a367431
Binary files /dev/null and b/docs/screenshots_gui_small.gif differ
diff --git a/docs/sections.html b/docs/sections.html
new file mode 100644
index 0000000..39a1866
--- /dev/null
+++ b/docs/sections.html
@@ -0,0 +1,121 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-script-type" content="text/javascript">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>Sections</title>
+
+<script type="text/javascript" language="JavaScript">
+<!--
+function defineSection(aName, aTarget, aURL) {
+ document.write("<tr><th class=\"sections\"");
+ document.write(document.body != null ?
+ (" onMouseOver=\"lightUp(this)\" onMouseOut=\"lightDown(this)\" onClick=\"goTo(this,'"+aTarget+"','"+aURL+"')\" onAfterUpdate=\"lightUp(this)\">"+aName) :
+ ("><a target=\""+aTarget+"\" href=\""+aURL+"\">"+aName+"</a>"));
+ document.write("</th></tr>");
+}
+
+function lightUp(aTH) {
+ if (aTH != fTH)
+ aTH.bgColor = "#eeeeee";
+}
+function lightDown(aTH) {
+ if (aTH != fTH)
+ aTH.bgColor = "";
+}
+function goTo(aTH, aTarget, aURL) {
+ if (fTH != null)
+ fTH.bgColor = "";
+
+ fTH = aTH;
+ fTH.bgColor = "white";
+ f = findFrameByName(parent.frames, aTarget);
+ if (f != null)
+ f.document.location.href=aURL;
+}
+function findFrameByName(aFrames, aFrameName) {
+ for (i = 0; i < aFrames.length; i++)
+ if (aFrames[i].name == aFrameName)
+ return aFrames[i];
+ return null;
+}
+//-->
+</script>
+
+</head>
+<body class="title">
+
+<script type="text/javascript" language="JavaScript">
+<!--
+var fTH = null;
+//-->
+</script>
+
+<script type="text/javascript" language="JavaScript">
+<!--
+document.write("<table class=\"sections\" width=\"120\">");
+defineSection("Main", "main", "main.html");
+defineSection("Results", "main", "results.html");
+defineSection("FAQ", "main", "FAQ.html");
+defineSection("Manual", "sections","manual/sections.html");
+defineSection("Quality", "main", "quality.html");
+defineSection("Screenshots", "main", "screenshots.html");
+defineSection("Testimonials","main", "testimonials.html");
+defineSection("License", "main", "license.html");
+defineSection("Downloads", "main", "downloads.html");
+defineSection("Feedback", "main", "feedback.html");
+defineSection("Ack'ments", "main", "acknowledgements.html");
+defineSection("Alternatives","main", "alternatives.html");
+document.write("</table>");
+document.write("<p>");
+document.write("<center>");
+document.write("<small>With support of</small>");
+document.write("<p>");
+document.write("<a href=\"http://sourceforge.net/projects/proguard/\" target=\"other\">");
+document.write("<img src=\"");
+document.write(document.location.hostname == "proguard.sourceforge.net" ?
+ "http://sourceforge.net/sflogo.php?group_id=54750&type=1" :
+ "sflogo.png");
+document.write("\" width=\"88\" height=\"31\" alt=\"SourceForge\">");
+document.write("</a>");
+document.write("<p>");
+document.write("<a href=\"http://www.luciad.com/\" target=\"other\">");
+document.write("<img src=\"luciadlogo.png\" width=\"88\" height=\"24\" alt=\"Luciad\">");
+document.write("</a>");
+document.write("</center>");
+//-->
+</script>
+
+<noscript>
+<table class="sections">
+
+<tr><th class="sections"><a target="main" href="main.html">Main</a></th></tr>
+<tr><th class="sections"><a target="main" href="results.html">Results</a></th></tr>
+<tr><th class="sections"><a target="main" href="FAQ.html">FAQ</a></th></tr>
+<tr><th class="sections"><a href="manual/sections.html">Manual</a></th></tr>
+<tr><th class="sections"><a target="main" href="quality.html">Quality</a></th></tr>
+<tr><th class="sections"><a target="main" href="screenshots.html">Screenshots</a></th></tr>
+<tr><th class="sections"><a target="main" href="testimonials.html">Testimonials</a></th></tr>
+<tr><th class="sections"><a target="main" href="license.html">License</a></th></tr>
+<tr><th class="sections"><a target="main" href="downloads.html">Downloads</a></th></tr>
+<tr><th class="sections"><a target="main" href="feedback.html">Feedback</a></th></tr>
+<tr><th class="sections"><a target="main" href="acknowledgements.html">Ack'ments</a></th></tr>
+<tr><th class="sections"><a target="main" href="alternatives.html">Alternatives</a></th></tr>
+
+</table>
+<p>
+<center>
+<small>With support of</small>
+<p>
+<a href="http://sourceforge.net/projects/proguard/" target="other">
+<img src="sflogo.png" width="88" height="31" alt="SourceForge"></a>
+<p>
+<a href="http://www.luciad.com/" target="other">
+<img src="luciadlogo.png" width="88" height="24" alt="Luciad"></a>
+</center>
+</noscript>
+
+</body>
+</html>
diff --git a/docs/sflogo.png b/docs/sflogo.png
new file mode 100644
index 0000000..1105bc7
Binary files /dev/null and b/docs/sflogo.png differ
diff --git a/docs/steel.gif b/docs/steel.gif
new file mode 100644
index 0000000..307b57a
Binary files /dev/null and b/docs/steel.gif differ
diff --git a/docs/style.css b/docs/style.css
new file mode 100644
index 0000000..b763813
--- /dev/null
+++ b/docs/style.css
@@ -0,0 +1,128 @@
+
+ at charset "iso-8859-1";
+
+/* Global settings. */
+
+body {
+ background: #FFFFFF;
+}
+
+h1 {
+ text-align: center;
+}
+
+h2 {
+ text-align: center;
+}
+
+h3 {
+ background: #EEEEFF;
+ padding: 10px;
+}
+
+table {
+ width: 100%;
+}
+
+th {
+ padding: 4px;
+}
+
+td {
+ background: #EEEEFF;
+ padding: 8px;
+}
+
+img {
+ border: none;
+}
+
+/* Settings for the introductory paragraph. */
+
+p.intro {
+ background: #EEEEFF;
+ padding: 10px;
+ border: solid #000000 1px
+}
+
+/* Settings for the title and section frames. */
+
+body.title {
+ margin: 0px;
+ background: #FFFFFF;
+}
+
+table.title {
+ width: 100%;
+ height: 50px;
+ background: url("steel.gif");
+ border: outset #FFFFFF 1px;
+ border-spacing: 0px;
+}
+
+th.title, td.title {
+ background: transparent;
+ border: none;
+ border-spacing: 0px;
+}
+
+.title a:link { color: #000000; text-decoration: none; }
+.title a:visited { color: #000000; text-decoration: none; }
+.title a:hover { color: #222222; text-decoration: none; }
+.title a:active { color: #FFFFFF; text-decoration: none; }
+
+table.sections {
+ width: 100%;
+ height: 50px;
+ background: url("steel.gif");
+ border: 0px;
+ border-spacing: 0px;
+}
+
+th.sections, td.sections {
+ height: 40px;
+ border: outset #FFFFFF 1px;
+}
+
+/* Settings for the yellow note tables. */
+
+table.note {
+ width: 408px;
+ border: none;
+ border-spacing: 0px;
+}
+
+td.shadow8 {
+ width: 8px;
+ padding: 0px;
+ margin: 0px;
+ vertical-align: bottom;
+ background: transparent;
+}
+
+td.shadow400 {
+ width: 400px;
+ padding: 0px;
+ margin: 0px;
+ text-align: right;
+ background: transparent;
+}
+
+td.note {
+ width: 380px;
+ background: #FFFFC0;
+ padding: 0px;
+ margin: 0px;
+}
+
+p.note {
+ padding: 0px;
+ margin: 0px 10px;
+ text-align: center;
+}
+
+p.author {
+ padding: 0px;
+ margin: 0px 10px;
+ text-align: right;
+}
diff --git a/docs/testimonials.html b/docs/testimonials.html
new file mode 100644
index 0000000..87a4faa
--- /dev/null
+++ b/docs/testimonials.html
@@ -0,0 +1,98 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard Testimonials</title>
+</head>
+<body>
+
+<h2>Testimonials</h2>
+
+And now for some shameless self-glorification and name-dropping...
+<p>
+Since its first public release, <b>ProGuard</b> has been welcomed with general
+enthusiasm. It is already being used by developers at companies and
+organizations like Sun, IBM, Siemens, Nokia, and NATO. Although the quotes
+below probably don't represent official views of any kind, encouragements like
+these do keep me happy.
+<p>
+
+<center><table class="note">
+<tr><td class="note"><p class="note"><cite>
+ProGuard is <b>the</b> ultimate java obfuscator!
+</cite></p>
+<p class="author">P.S, IBM</p></td>
+<td class="shadow8"><img src="drop2.gif" width="8" height="100"></td></tr><tr>
+<td class="shadow400"><img src="drop1.gif" width="400" height="8"></td>
+<td class="shadow8"><img src="drop3.gif" width="8" height="8"></td>
+</tr></table></center>
+<p>
+
+And indeed:
+<center><table class="note">
+<tr><td class="note"><p class="note"><cite>
+ProGuard rules. Much easier to use than the commercial alternatives.
+</cite></p>
+<p class="author">B.G., Quiotix Corp.</p></td>
+<td class="shadow8"><img src="drop2.gif" width="8" height="100"></td></tr><tr>
+<td class="shadow400"><img src="drop1.gif" width="400" height="8"></td>
+<td class="shadow8"><img src="drop3.gif" width="8" height="8"></td>
+</tr></table></center>
+<p>
+
+Straight from <b>ProGuard</b>'s open discussion forum:
+<p>
+<center><table class="note">
+<tr><td class="note"><p class="note"><cite>
+After searching for, trying to trial, and futzing with numerous other
+obfuscators and shrinkers, ProGuard stands out as the simplest, most robust,
+and accurate shrinker of them all.
+</cite></p>
+<p class="author">D.J., Joot</p></td>
+<td class="shadow8"><img src="drop2.gif" width="8" height="100"></td></tr><tr>
+<td class="shadow400"><img src="drop1.gif" width="400" height="8"></td>
+<td class="shadow8"><img src="drop3.gif" width="8" height="8"></td>
+</tr></table></center>
+<p>
+
+From the article <a target="other"
+href="http://developers.sun.com/techtopics/mobility/midp/ttips/proguard/">"Obfuscating
+MIDlet Suites with ProGuard"</a> at <a target="other"
+href="http://developers.sun.com/">developers.sun.com</a>:
+<p>
+<center><table class="note">
+<tr><td class="note"><p class="note"><cite>
+Its friendly license, attractive price tag, compelling performance, and
+powerful configuration options make it an excellent addition to your MIDlet
+development toolbox.
+</cite></p>
+<p class="author">J.K., Sun</p></td>
+<td class="shadow8"><img src="drop2.gif" width="8" height="100"></td></tr><tr>
+<td class="shadow400"><img src="drop1.gif" width="400" height="8"></td>
+<td class="shadow8"><img src="drop3.gif" width="8" height="8"></td>
+</tr></table></center>
+<p>
+
+And, of course, the price is stunning:
+<p>
+<center><table class="note">
+<tr><td class="note"><p class="note"><cite>
+You could've been rich.
+</cite></p>
+<p class="author">My mother</p></td>
+<td class="shadow8"><img src="drop2.gif" width="8" height="100"></td></tr><tr>
+<td class="shadow400"><img src="drop1.gif" width="400" height="8"></td>
+<td class="shadow8"><img src="drop3.gif" width="8" height="8"></td>
+</tr></table></center>
+<p>
+
+<hr>
+<address>
+Copyright © 2002-2004
+<a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
+</address>
+
+</body>
+</html>
diff --git a/docs/title.gif b/docs/title.gif
new file mode 100644
index 0000000..5e6ca26
Binary files /dev/null and b/docs/title.gif differ
diff --git a/docs/title.html b/docs/title.html
new file mode 100644
index 0000000..09f51c8
--- /dev/null
+++ b/docs/title.html
@@ -0,0 +1,19 @@
+<!doctype html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="content-style-type" content="text/css">
+<link rel="stylesheet" type="text/css" href="style.css">
+<title>ProGuard</title>
+</head>
+<body class="title">
+
+<table class="title">
+<tr>
+<th class="title"><h1><img src="title.gif" width="154" height="29" alt="ProGuard"></h1></th>
+<td class="title" width="100">Version 3.2</td>
+</tr>
+</table>
+
+</body>
+</html>
diff --git a/docs/vtitle.gif b/docs/vtitle.gif
new file mode 100644
index 0000000..cb2f070
Binary files /dev/null and b/docs/vtitle.gif differ
diff --git a/examples/ant/applets.xml b/examples/ant/applets.xml
new file mode 100644
index 0000000..a02dd3d
--- /dev/null
+++ b/examples/ant/applets.xml
@@ -0,0 +1,74 @@
+<!-- This Ant build file illustrates how to process applets.
+ Usage: ant -f applets.xml -->
+
+<project name="Applets" default="obfuscate" basedir="../..">
+
+<target name="obfuscate">
+ <taskdef resource="proguard/ant/task.properties"
+ classpath="lib/proguard.jar" />
+
+ <proguard printseeds="on">
+
+ <!-- Specify the input jars, output jars, and library jars. -->
+
+ <injar file="in.jar" />
+ <outjar file="out.jar" />
+
+ <libraryjar file="${java.home}/lib/rt.jar" />
+
+ <!-- Preserve all public applets. -->
+
+ <keep access="public" extends="java.applet.Applet" />
+
+ <!-- Preserve all annotations. -->
+
+ <keepattribute name="*Annotation*" />
+
+ <!-- Preserve all native method names and the names of their classes. -->
+
+ <keepclasseswithmembernames>
+ <method access="native" />
+ </keepclasseswithmembernames>
+
+ <!-- Preserve a method that is required in all enumeration classes. -->
+
+ <keepclassmembers extends="java.lang.Enum">
+ <method access="public"
+ type="**[]"
+ name="values"
+ parameters="" />
+ </keepclassmembers>
+
+ <!-- Explicitly preserve all serialization members. The Serializable
+ interface is only a marker interface, so it wouldn't save them.
+ You can comment this out if your library doesn't use serialization.
+ If your code contains serializable classes that have to be backward
+ compatible, please refer to the manual. -->
+
+ <keepclassmembers implements="java.io.Serializable">
+ <field access ="final"
+ type ="long"
+ name ="serialVersionUID" />
+ <method access ="private"
+ type ="void"
+ name ="writeObject"
+ parameters="java.io.ObjectOutputStream" />
+ <method access ="private"
+ type ="void"
+ name ="readObject"
+ parameters="java.io.ObjectOutputStream" />
+ <method type ="java.lang.Object"
+ name ="writeReplace"
+ parameters="" />
+ <method type ="java.lang.Object"
+ name ="readResolve"
+ parameters="" />
+ </keepclassmembers>
+
+ <!-- Your application may contain more items that need to be preserved;
+ typically classes that are dynamically created using Class.forName -->
+
+ </proguard>
+</target>
+
+</project>
diff --git a/examples/ant/applications1.xml b/examples/ant/applications1.xml
new file mode 100644
index 0000000..12cf838
--- /dev/null
+++ b/examples/ant/applications1.xml
@@ -0,0 +1,15 @@
+<!-- This Ant build file illustrates how to process applications,
+ by including a ProGuard-style configuration file.
+ Usage: ant -f applications.xml -->
+
+<project name="Applications" default="obfuscate" basedir="../..">
+
+<target name="obfuscate">
+ <taskdef resource="proguard/ant/task.properties"
+ classpath="lib/proguard.jar" />
+
+ <proguard configuration="../applications.pro" />
+
+</target>
+
+</project>
diff --git a/examples/ant/applications2.xml b/examples/ant/applications2.xml
new file mode 100644
index 0000000..f887581
--- /dev/null
+++ b/examples/ant/applications2.xml
@@ -0,0 +1,66 @@
+<!-- This Ant build file illustrates how to process applications,
+ by including ProGuard-style configuration options.
+ Usage: ant -f applications.xml -->
+
+<project name="Applications" default="obfuscate" basedir="../..">
+
+<target name="obfuscate">
+ <taskdef resource="proguard/ant/task.properties"
+ classpath="lib/proguard.jar" />
+
+ <proguard>
+
+ <!-- Specify the input jars, output jars, and library jars. -->
+
+ -injars in.jar
+ -outjars out.jar
+
+ -libraryjars ${java.home}/lib/rt.jar
+ <!-- -libraryjars junit.jar -->
+ <!-- -libraryjars servlet.jar -->
+ <!-- -libraryjars jai_core.jar -->
+ <!-- ... -->
+
+ <!-- Preserve all public applications. -->
+
+ -keepclasseswithmembers public class * {
+ public static void main(java.lang.String[]);
+ }
+
+ <!-- Preserve all annotations. -->
+
+ -keepattributes *Annotation*
+
+ <!-- Preserve all native method names and the names of their classes. -->
+
+ -keepclasseswithmembernames class * {
+ native <methods>;
+ }
+
+ <!-- Preserve a method that is required in all enumeration classes. -->
+
+ -keepclassmembers class * extends java.lang.Enum {
+ public **[] values();
+ }
+
+ <!-- Explicitly preserve all serialization members. The Serializable
+ interface is only a marker interface, so it wouldn't save them.
+ You can comment this out if your library doesn't use serialization.
+ If your code contains serializable classes that have to be backward
+ compatible, please refer to the manual. -->
+
+ -keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+ }
+
+ <!-- Your application may contain more items that need to be preserved;
+ typically classes that are dynamically created using Class.forName -->
+
+ </proguard>
+</target>
+
+</project>
diff --git a/examples/ant/applications3.xml b/examples/ant/applications3.xml
new file mode 100644
index 0000000..9edc8db
--- /dev/null
+++ b/examples/ant/applications3.xml
@@ -0,0 +1,85 @@
+<!-- This Ant build file illustrates how to process applications,
+ using a full-blown XML configuration.
+ Usage: ant -f applications.xml -->
+
+<project name="Applications" default="obfuscate" basedir="../..">
+
+<target name="obfuscate">
+ <taskdef resource="proguard/ant/task.properties"
+ classpath="lib/proguard.jar" />
+
+ <proguard printseeds="on">
+
+ <!-- Specify the input jars, output jars, and library jars. -->
+
+ <injar file="in.jar" />
+ <outjar file="out.jar" />
+
+ <libraryjar file="${java.home}/lib/rt.jar" />
+ <!-- libraryjar file="junit.jar" / -->
+ <!-- libraryjar file="servlet.jar" / -->
+ <!-- libraryjar file="jai_core.jar" / -->
+ <!-- ... / -->
+
+
+ <!-- Preserve all public applications. -->
+
+ <keepclasseswithmembers access="public">
+ <method access ="public static"
+ type ="void"
+ name ="main"
+ parameters="java.lang.String[]" />
+ </keepclasseswithmembers>
+
+ <!-- Preserve all annotations. -->
+
+ <keepattribute name="*Annotation*" />
+
+ <!-- Preserve all native method names and the names of their classes. -->
+
+ <keepclasseswithmembernames>
+ <method access="native" />
+ </keepclasseswithmembernames>
+
+ <!-- Preserve a method that is required in all enumeration classes. -->
+
+ <keepclassmembers extends="java.lang.Enum">
+ <method access="public"
+ type="**[]"
+ name="values"
+ parameters="" />
+ </keepclassmembers>
+
+ <!-- Explicitly preserve all serialization members. The Serializable
+ interface is only a marker interface, so it wouldn't save them.
+ You can comment this out if your library doesn't use serialization.
+ If your code contains serializable classes that have to be backward
+ compatible, please refer to the manual. -->
+
+ <keepclassmembers implements="java.io.Serializable">
+ <field access ="final"
+ type ="long"
+ name ="serialVersionUID" />
+ <method access ="private"
+ type ="void"
+ name ="writeObject"
+ parameters="java.io.ObjectOutputStream" />
+ <method access ="private"
+ type ="void"
+ name ="readObject"
+ parameters="java.io.ObjectOutputStream" />
+ <method type ="java.lang.Object"
+ name ="writeReplace"
+ parameters="" />
+ <method type ="java.lang.Object"
+ name ="readResolve"
+ parameters="" />
+ </keepclassmembers>
+
+ <!-- Your application may contain more items that need to be preserved;
+ typically classes that are dynamically created using Class.forName -->
+
+ </proguard>
+</target>
+
+</project>
diff --git a/examples/ant/library.xml b/examples/ant/library.xml
new file mode 100644
index 0000000..cb88e03
--- /dev/null
+++ b/examples/ant/library.xml
@@ -0,0 +1,95 @@
+<!-- This Ant build file illustrates how to process a program library,
+ such that it remains usable as a library.
+ Usage: ant -f library.xml -->
+
+<project name="Library" default="obfuscate" basedir="../..">
+
+<target name="obfuscate">
+ <taskdef resource="proguard/ant/task.properties"
+ classpath="lib/proguard.jar" />
+
+ <proguard printmapping="out.map"
+ renamesourcefileattribute="SourceFile">
+
+ <!-- Specify the input jars, output jars, and library jars. -->
+
+ <injar file="library.jar" />
+ <outjar file="library_out.jar" />
+
+ <libraryjar file="${java.home}/lib/rt.jar" />
+
+ <!-- Keep some useful attributes. -->
+
+ <keepattribute name="InnerClasses" />
+ <keepattribute name="SourceFile" />
+ <keepattribute name="LineNumberTable" />
+ <keepattribute name="Deprecated" />
+ <keepattribute name="*Annotation*" />
+
+ <!-- Preserve all public classes, and their public and protected fields
+ and methods. -->
+
+ <keep access="public">
+ <field access="public protected" />
+ <method access="public protected" />
+ </keep>
+
+ <!-- Preserve all .class method names. -->
+
+ <keepclassmembernames access="public">
+ <method type ="java.lang.Class"
+ name ="class$"
+ parameters="java.lang.String" />
+ <method type ="java.lang.Class"
+ name ="class$"
+ parameters="java.lang.String,boolean" />
+ </keepclassmembernames>
+
+ <!-- Preserve all native method names and the names of their classes. -->
+
+ <keepclasseswithmembernames>
+ <method access="native" />
+ </keepclasseswithmembernames>
+
+ <!-- Preserve a method that is required in all enumeration classes. -->
+
+ <keepclassmembers extends="java.lang.Enum">
+ <method access="public"
+ type="**[]"
+ name="values"
+ parameters="" />
+ </keepclassmembers>
+
+ <!-- Explicitly preserve all serialization members. The Serializable
+ interface is only a marker interface, so it wouldn't save them.
+ You can comment this out if your library doesn't use serialization.
+ If your code contains serializable classes that have to be backward
+ compatible, please refer to the manual. -->
+
+ <keepclassmembers implements="java.io.Serializable">
+ <field access ="final"
+ type ="long"
+ name ="serialVersionUID" />
+ <method access ="private"
+ type ="void"
+ name ="writeObject"
+ parameters="java.io.ObjectOutputStream" />
+ <method access ="private"
+ type ="void"
+ name ="readObject"
+ parameters="java.io.ObjectOutputStream" />
+ <method type ="java.lang.Object"
+ name ="writeReplace"
+ parameters="" />
+ <method type ="java.lang.Object"
+ name ="readResolve"
+ parameters="" />
+ </keepclassmembers>
+
+ <!-- Your application may contain more items that need to be preserved;
+ typically classes that are dynamically created using Class.forName -->
+
+ </proguard>
+</target>
+
+</project>
diff --git a/examples/ant/midlets.xml b/examples/ant/midlets.xml
new file mode 100644
index 0000000..5b8643c
--- /dev/null
+++ b/examples/ant/midlets.xml
@@ -0,0 +1,44 @@
+<!-- This Ant build file illustrates how to process J2ME midlets.
+ Usage: ant -f midlets.xml -->
+
+<project name="Midlets" default="obfuscate" basedir="../..">
+
+<target name="obfuscate">
+ <taskdef resource="proguard/ant/task.properties"
+ classpath="lib/proguard.jar" />
+
+ <proguard overloadaggressively="on"
+ defaultpackage=""
+ allowaccessmodification="on"
+ printseeds="on">
+
+ <!-- On Windows, you can't use mixed case class names,
+ for the sake of the preverify tool.
+ usemixedcaseclassnames="false">
+ -->
+
+ <!-- Specify the input jars, output jars, and library jars. -->
+
+ <injar file="in.jar" />
+ <outjar file="out.jar" />
+
+ <libraryjar file="/usr/local/java/wtk2.1/lib/midpapi20.jar" />
+ <libraryjar file="/usr/local/java/wtk2.1/lib/cldcapi11.jar" />
+
+ <!-- Preserve all public midlets. -->
+
+ <keep access="public" extends="javax.microedition.midlet.MIDlet" />
+
+ <!-- Preserve all native method names and the names of their classes. -->
+
+ <keepclasseswithmembernames>
+ <method access="native" />
+ </keepclasseswithmembernames>
+
+ <!-- Your application may contain more items that need to be preserved;
+ typically classes that are dynamically created using Class.forName -->
+
+ </proguard>
+</target>
+
+</project>
diff --git a/examples/ant/proguard.xml b/examples/ant/proguard.xml
new file mode 100644
index 0000000..8cd44f0
--- /dev/null
+++ b/examples/ant/proguard.xml
@@ -0,0 +1,62 @@
+<!-- This Ant build file illustrates how to process ProGuard (including its
+ main application, its GUI, its Ant task, and its WTK plugin), and the
+ ReTrace tool, all in one go.
+ Usage: ant -f proguard.xml -->
+
+<project name="ProGuard" default="obfuscate" basedir="../..">
+
+<target name="obfuscate">
+ <taskdef resource="proguard/ant/task.properties"
+ classpath="lib/proguard.jar" />
+
+ <proguard printmapping="proguard.map"
+ overloadaggressively="on"
+ defaultpackage=""
+ allowaccessmodification="on">
+
+ <!-- Specify the input jars, output jars, and library jars. -->
+
+ <injar file="lib/proguard.jar" />
+ <outjar file="proguard_out.jar" />
+
+ <libraryjar file="${java.home}/lib/rt.jar" />
+ <libraryjar file="/usr/local/java/ant1.6.2/lib/ant.jar" />
+ <libraryjar file="/usr/local/java/wtk2.1/wtklib/kenv.zip" />
+
+ <!-- The main seeds: ProGuard and its companion tool ReTrace. -->
+
+ <keep access="public" name="proguard.ProGuard">
+ <method access ="public static"
+ type ="void"
+ name ="main"
+ parameters="java.lang.String[]" />
+ </keep>
+ <keep access="public" name="proguard.gui.ProGuardGUI">
+ <method access ="public static"
+ type ="void"
+ name ="main"
+ parameters="java.lang.String[]" />
+ </keep>
+ <keep access="public" name="proguard.retrace.ReTrace">
+ <method access ="public static"
+ type ="void"
+ name ="main"
+ parameters="java.lang.String[]" />
+ </keep>
+
+ <!-- If we have ant.jar, we can properly process the Ant task. -->
+
+ <keep access="public" name="proguard.ant.*">
+ <method access="public" type="void" name="set*" parameters="%" />
+ <method access="public" type="void" name="set*" parameters="**" />
+ <method access="public" type="void" name="add*" parameters="**" />
+ </keep>
+
+ <!-- If we have kenv.zip, we can process the J2ME WTK plugin. -->
+
+ <keep access="public" name="proguard.wtk.ProGuardObfuscator" />
+
+ </proguard>
+</target>
+
+</project>
diff --git a/examples/ant/servlets.xml b/examples/ant/servlets.xml
new file mode 100644
index 0000000..8aa43d7
--- /dev/null
+++ b/examples/ant/servlets.xml
@@ -0,0 +1,74 @@
+<!-- This Ant build file illustrates how to process servlets.
+ Usage: ant -f servlets.xml -->
+
+<project name="Servlets" default="obfuscate" basedir="../..">
+
+<target name="obfuscate">
+ <taskdef resource="proguard/ant/task.properties"
+ classpath="lib/proguard.jar" />
+
+ <proguard printseeds="on">
+
+ <!-- Specify the input jars, output jars, and library jars. -->
+
+ <injar file="in.jar" />
+ <outjar file="out.jar" />
+
+ <libraryjar file="${java.home}/lib/rt.jar" />
+
+ <!-- Keep all public servlets. -->
+
+ <keep access="public" implements="javax.servlet.Servlet" />
+
+ <!-- Preserve all annotations. -->
+
+ <keepattribute name="*Annotation*" />
+
+ <!-- Preserve all native method names and the names of their classes. -->
+
+ <keepclasseswithmembernames>
+ <method access="native" />
+ </keepclasseswithmembernames>
+
+ <!-- Preserve a method that is required in all enumeration classes. -->
+
+ <keepclassmembers extends="java.lang.Enum">
+ <method access="public"
+ type="**[]"
+ name="values"
+ parameters="" />
+ </keepclassmembers>
+
+ <!-- Explicitly preserve all serialization members. The Serializable
+ interface is only a marker interface, so it wouldn't save them.
+ You can comment this out if your library doesn't use serialization.
+ If your code contains serializable classes that have to be backward
+ compatible, please refer to the manual. -->
+
+ <keepclassmembers implements="java.io.Serializable">
+ <field access ="final"
+ type ="long"
+ name ="serialVersionUID" />
+ <method access ="private"
+ type ="void"
+ name ="writeObject"
+ parameters="java.io.ObjectOutputStream" />
+ <method access ="private"
+ type ="void"
+ name ="readObject"
+ parameters="java.io.ObjectOutputStream" />
+ <method type ="java.lang.Object"
+ name ="writeReplace"
+ parameters="" />
+ <method type ="java.lang.Object"
+ name ="readResolve"
+ parameters="" />
+ </keepclassmembers>
+
+ <!-- Your application may contain more items that need to be preserved;
+ typically classes that are dynamically created using Class.forName -->
+
+ </proguard>
+</target>
+
+</project>
diff --git a/examples/applets.pro b/examples/applets.pro
new file mode 100644
index 0000000..1005150
--- /dev/null
+++ b/examples/applets.pro
@@ -0,0 +1,57 @@
+#
+# This ProGuard configuration file illustrates how to process applets.
+# Usage:
+# java -jar proguard.jar @applets.pro
+#
+
+# Specify the input jars, output jars, and library jars.
+
+-injars in.jar
+-outjars out.jar
+
+-libraryjars <java.home>/lib/rt.jar
+
+# Preserve all public applets.
+
+-keep public class * extends java.applet.Applet
+
+# Print out a list of what we're preserving.
+
+-printseeds
+
+# Preserve all annotations.
+
+-keepattributes *Annotation*
+
+# Preserve all native method names and the names of their classes.
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# Preserve a method that is required in all enumeration classes.
+
+-keepclassmembers class * extends java.lang.Enum {
+ public **[] values();
+}
+
+# Explicitly preserve all serialization members. The Serializable interface
+# is only a marker interface, so it wouldn't save them.
+# You can comment this out if your library doesn't use serialization.
+# If your code contains serializable classes that have to be backward
+# compatible, please refer to the manual.
+
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+
+# Your application may contain more items that need to be preserved;
+# typically classes that are dynamically created using Class.forName:
+
+# -keep public class mypackage.MyClass
+# -keep public interface mypackage.MyInterface
+# -keep public class * implements mypackage.MyInterface
diff --git a/examples/applications.pro b/examples/applications.pro
new file mode 100644
index 0000000..1adf7b2
--- /dev/null
+++ b/examples/applications.pro
@@ -0,0 +1,63 @@
+#
+# This ProGuard configuration file illustrates how to process applications.
+# Usage:
+# java -jar proguard.jar @applications.pro
+#
+
+# Specify the input jars, output jars, and library jars.
+
+-injars in.jar
+-outjars out.jar
+
+-libraryjars <java.home>/lib/rt.jar
+#-libraryjars junit.jar
+#-libraryjars servlet.jar
+#-libraryjars jai_core.jar
+#...
+
+# Preserve all public applications.
+
+-keepclasseswithmembers public class * {
+ public static void main(java.lang.String[]);
+}
+
+# Print out a list of what we're preserving.
+
+-printseeds
+
+# Preserve all annotations.
+
+-keepattributes *Annotation*
+
+# Preserve all native method names and the names of their classes.
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# Preserve a method that is required in all enumeration classes.
+
+-keepclassmembers class * extends java.lang.Enum {
+ public **[] values();
+}
+
+# Explicitly preserve all serialization members. The Serializable interface
+# is only a marker interface, so it wouldn't save them.
+# You can comment this out if your application doesn't use serialization.
+# If your code contains serializable classes that have to be backward
+# compatible, please refer to the manual.
+
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+
+# Your application may contain more items that need to be preserved;
+# typically classes that are dynamically created using Class.forName:
+
+# -keep public class mypackage.MyClass
+# -keep public interface mypackage.MyInterface
+# -keep public class * implements mypackage.MyInterface
diff --git a/examples/dictionaries/compact.txt b/examples/dictionaries/compact.txt
new file mode 100644
index 0000000..c97bdd3
--- /dev/null
+++ b/examples/dictionaries/compact.txt
@@ -0,0 +1,19 @@
+#
+# This obfuscation dictionary contains strings that are already present
+# in many class files. Since these strings can be shared, the resulting
+# obfuscated class files will generally be a little bit more compact.
+# Usage:
+# java -jar proguard.jar ..... -obfuscationdictionary compact.txt
+#
+
+Code
+Exceptions
+V
+I
+Z
+B
+C
+S
+F
+D
+L
diff --git a/examples/dictionaries/keywords.txt b/examples/dictionaries/keywords.txt
new file mode 100644
index 0000000..76f5a7b
--- /dev/null
+++ b/examples/dictionaries/keywords.txt
@@ -0,0 +1,58 @@
+#
+# This obfuscation dictionary contains reserved Java keywords. They can't
+# be used in Java source files, but they can be used in compiled class files.
+# Note that this hardly improves the obfuscation. Decent decompilers can
+# automatically replace reserved keywords, and the effect can fairly simply be
+# undone by obfuscating again with simpler names.
+# Usage:
+# java -jar proguard.jar ..... -obfuscationdictionary keywords.txt
+#
+
+do
+if
+for
+int
+new
+try
+byte
+case
+char
+else
+goto
+long
+this
+void
+break
+catch
+class
+const
+final
+float
+short
+super
+throw
+while
+double
+import
+native
+public
+return
+static
+switch
+throws
+boolean
+default
+extends
+finally
+package
+private
+abstract
+continue
+strictfp
+volatile
+interface
+protected
+transient
+implements
+instanceof
+synchronized
diff --git a/examples/dictionaries/shakespeare.txt b/examples/dictionaries/shakespeare.txt
new file mode 100644
index 0000000..28b1cd8
--- /dev/null
+++ b/examples/dictionaries/shakespeare.txt
@@ -0,0 +1,23 @@
+#
+# This obfuscation dictionary contains quotes from plays by Shakespeare.
+# It illustrates that any text can be used, for whatever flippant reasons
+# one may have.
+# Usage:
+# java -jar proguard.jar ..... -obfuscationdictionary shakespeare.txt
+#
+
+
+"This thing of darkness I acknowledge mine."
+
+ --From The Tempest (V, i, 275-276)
+
+
+"Though this be madness, yet there is method in 't."
+
+ --From Hamlet (II, ii, 206)
+
+
+"What's in a name? That which we call a rose
+ By any other word would smell as sweet."
+
+ --From Romeo and Juliet (II, ii, 1-2)
diff --git a/examples/library.pro b/examples/library.pro
new file mode 100644
index 0000000..1a1a1fa
--- /dev/null
+++ b/examples/library.pro
@@ -0,0 +1,74 @@
+#
+# This ProGuard configuration file illustrates how to process a program
+# library, such that it remains usable as a library.
+# Usage:
+# java -jar proguard.jar @library.pro
+#
+
+# Specify the input jars, output jars, and library jars.
+# In this case, the input jar is the program library that we want to process.
+
+-injars in.jar
+-outjars out.jar
+
+-libraryjars <java.home>/lib/rt.jar
+
+# Save the obfuscation mapping to a file, so we can de-obfuscate any stack
+# traces later on. Keep a fixed source file attribute and all line number
+# tables to actually get these stack traces.
+# You can comment this out if you're not interested in stack traces.
+
+-printmapping out.map
+-renamesourcefileattribute SourceFile
+-keepattributes InnerClasses,SourceFile,LineNumberTable,Deprecated
+
+# Preserve all annotations.
+
+-keepattributes *Annotation*
+
+# Preserve all public classes, and their public and protected fields and
+# methods.
+
+-keep public class * {
+ public protected *;
+}
+
+# Preserve all .class method names.
+
+-keepclassmembernames class * {
+ java.lang.Class class$(java.lang.String);
+ java.lang.Class class$(java.lang.String, boolean);
+}
+
+# Preserve all native method names and the names of their classes.
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# Preserve a method that is required in all enumeration classes.
+
+-keepclassmembers class * extends java.lang.Enum {
+ public **[] values();
+}
+
+# Explicitly preserve all serialization members. The Serializable interface
+# is only a marker interface, so it wouldn't save them.
+# You can comment this out if your library doesn't use serialization.
+# If your code contains serializable classes that have to be backward
+# compatible, please refer to the manual.
+
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+
+# Your library may contain more items that need to be preserved;
+# typically classes that are dynamically created using Class.forName:
+
+# -keep public class mypackage.MyClass
+# -keep public interface mypackage.MyInterface
+# -keep public class * implements mypackage.MyInterface
diff --git a/examples/midlets.pro b/examples/midlets.pro
new file mode 100644
index 0000000..5ffb85b
--- /dev/null
+++ b/examples/midlets.pro
@@ -0,0 +1,53 @@
+#
+# This ProGuard configuration file illustrates how to process J2ME midlets.
+# Usage:
+# java -jar proguard.jar @midlets.pro
+#
+# You should still apply the preverify tool after having processed your code.
+
+# Specify the input jars, output jars, and library jars.
+
+-injars in.jar
+-outjars out.jar
+
+-libraryjars /usr/local/java/wtk2.1/lib/midpapi20.jar
+-libraryjars /usr/local/java/wtk2.1/lib/cldcapi11.jar
+
+# Allow methods with the same signature, except for the return type,
+# to get the same obfuscation name.
+
+-overloadaggressively
+
+# Put all obfuscated classes into the nameless root package.
+
+-defaultpackage ''
+
+# Allow classes and class members to be made public.
+
+-allowaccessmodification
+
+# On Windows, you can't use mixed case class names,
+# for the sake of the preverify tool.
+#
+# -dontusemixedcaseclassnames
+
+# Preserve all public midlets.
+
+-keep public class * extends javax.microedition.midlet.MIDlet
+
+# Print out a list of what we're preserving.
+
+-printseeds
+
+# Preserve all native method names and the names of their classes.
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# Your midlet may contain more items that need to be preserved;
+# typically classes that are dynamically created using Class.forName:
+
+# -keep public class mypackage.MyClass
+# -keep public interface mypackage.MyInterface
+# -keep public class * implements mypackage.MyInterface
diff --git a/examples/proguard.pro b/examples/proguard.pro
new file mode 100644
index 0000000..1a4a7b7
--- /dev/null
+++ b/examples/proguard.pro
@@ -0,0 +1,55 @@
+#
+# This ProGuard configuration file illustrates how to process ProGuard itself.
+# Configuration files for typical applications will be very similar.
+# Usage:
+# java -jar proguard.jar @proguard.pro
+#
+
+# Specify the input jars, output jars, and library jars.
+# We'll filter out the Ant and WTK classes, keeping everything else.
+
+-injars proguard.jar(!proguard/ant/**,!proguard/wtk/**)
+-outjars proguard_out.jar
+
+-libraryjars <java.home>/lib/rt.jar
+
+# Write out an obfuscation mapping file, for de-obfuscating any stack traces
+# later on, or for incremental obfuscation of extensions.
+
+-printmapping proguard.map
+
+# Allow methods with the same signature, except for the return type,
+# to get the same obfuscation name.
+
+-overloadaggressively
+
+# Put all obfuscated classes into the nameless root package.
+
+-defaultpackage ''
+
+# Allow classes and class members to be made public.
+
+-allowaccessmodification
+
+# The entry point: ProGuard and its main method.
+
+-keep public class proguard.ProGuard {
+ public static void main(java.lang.String[]);
+}
+
+# If you want to preserve the Ant task as well, you'll have to specify the
+# main ant.jar.
+
+#-libraryjars /usr/local/java/ant1.6.2/lib/ant.jar
+#-keep public class proguard.ant.* {
+# public void set*(%);
+# public void set*(**);
+# public void add*(**);
+#}
+
+
+# If you want to preserve the WTK obfuscation plug-in, you'll have to specify
+# the kenv.zip file.
+
+#-libraryjars /usr/local/java/wtk2.1/wtklib/kenv.zip
+#-keep public class proguard.wtk.ProGuardObfuscator
diff --git a/examples/proguardall.pro b/examples/proguardall.pro
new file mode 100644
index 0000000..b0e14e1
--- /dev/null
+++ b/examples/proguardall.pro
@@ -0,0 +1,67 @@
+#
+# This ProGuard configuration file illustrates how to process ProGuard
+# (including its main application, its GUI, its Ant task, and its WTK plugin),
+# and the ReTrace tool, all in one go.
+# Configuration files for typical applications will be very similar.
+# Usage:
+# java -jar proguard.jar @proguardall.pro
+#
+
+# Specify the input jars, output jars, and library jars.
+# We'll read all jars from the lib directory, process them, and write the
+# processed jars to a new out directory.
+
+-injars lib
+-outjars out
+
+# You may have to adapt the paths below.
+
+-libraryjars <java.home>/lib/rt.jar
+-libraryjars /usr/local/java/ant1.6.2/lib/ant.jar
+-libraryjars /usr/local/java/wtk2.1/wtklib/kenv.zip
+
+# Allow methods with the same signature, except for the return type,
+# to get the same obfuscation name.
+
+-overloadaggressively
+
+# Put all obfuscated classes into the nameless root package.
+
+-defaultpackage ''
+
+# Allow classes and class members to be made public.
+
+-allowaccessmodification
+
+# The main entry points.
+
+-keep public class proguard.ProGuard {
+ public static void main(java.lang.String[]);
+}
+
+-keep public class proguard.gui.ProGuardGUI {
+ public static void main(java.lang.String[]);
+}
+
+-keep public class proguard.retrace.ReTrace {
+ public static void main(java.lang.String[]);
+}
+
+# If we have ant.jar, we can properly process the Ant task.
+
+-keep public class proguard.ant.* {
+ public void set*(%);
+ public void set*(**);
+ public void add*(**);
+}
+
+# If we have kenv.zip, we can process the J2ME WTK plugin.
+
+-keep public class proguard.wtk.ProGuardObfuscator
+
+# In addition, the following classes load resource files, based on their class
+# names or package names, so we don't want them to be obfuscated or moved to
+# the default package.
+
+-keep class proguard.gui.GUIResources
+-keep class proguard.gui.ClassPathPanel$MyListCellRenderer
diff --git a/examples/proguardgui.pro b/examples/proguardgui.pro
new file mode 100644
index 0000000..1dca7bd
--- /dev/null
+++ b/examples/proguardgui.pro
@@ -0,0 +1,48 @@
+#
+# This ProGuard configuration file illustrates how to process the ProGuard GUI.
+# Configuration files for typical applications will be very similar.
+# Usage:
+# java -jar proguard.jar @proguardgui.pro
+#
+
+# Specify the input jars, output jars, and library jars.
+# We'll filter out the Ant and WTK classes, keeping everything else.
+
+-injars proguard.jar(!proguard/ant/**,!proguard/wtk/**)
+-injars proguardgui.jar
+-outjars proguardgui_out.jar
+
+-libraryjars <java.home>/lib/rt.jar
+
+# If we wanted to reuse the previously obfuscated proguard_out.jar, we could
+# perform incremental obfuscation based on its mapping file, and only keep the
+# additional GUI files instead of all files.
+
+#-applymapping proguard.map
+#-outjars proguardgui_out.jar(proguard/gui/**)
+
+# Allow methods with the same signature, except for the return type,
+# to get the same obfuscation name.
+
+-overloadaggressively
+
+# Put all obfuscated classes into the nameless root package.
+
+-defaultpackage ''
+
+# Allow classes and class members to be made public.
+
+-allowaccessmodification
+
+# The entry point: ProGuardGUI and its main method.
+
+-keep public class proguard.gui.ProGuardGUI {
+ public static void main(java.lang.String[]);
+}
+
+# In addition, the following classes load resource files, based on their class
+# names or package names, so we don't want them to be obfuscated or moved to
+# the default package.
+
+-keep class proguard.gui.GUIResources
+-keep class proguard.gui.ClassPathPanel$MyListCellRenderer
diff --git a/examples/retrace.pro b/examples/retrace.pro
new file mode 100644
index 0000000..b9aa0f6
--- /dev/null
+++ b/examples/retrace.pro
@@ -0,0 +1,41 @@
+#
+# This ProGuard configuration file illustrates how to process the ReTrace tool.
+# Configuration files for typical applications will be very similar.
+# Usage:
+# java -jar proguard.jar @retrace.pro
+#
+
+# Specify the input jars, output jars, and library jars.
+# We'll filter out the Ant and WTK classes, keeping everything else.
+
+-injars proguard.jar(!proguard/ant/**,!proguard/wtk/**)
+-injars retrace.jar
+-outjars retrace_out.jar
+
+-libraryjars <java.home>/lib/rt.jar
+
+# If we wanted to reuse the previously obfuscated proguard_out.jar, we could
+# perform incremental obfuscation based on its mapping file, and only keep the
+# additional ReTrace files instead of all files.
+
+#-applymapping proguard.map
+#-outjars retrace_out.jar(proguard/retrace/**)
+
+# Allow methods with the same signature, except for the return type,
+# to get the same obfuscation name.
+
+-overloadaggressively
+
+# Put all obfuscated classes into the nameless root package.
+
+-defaultpackage ''
+
+# Allow classes and class members to be made public.
+
+-allowaccessmodification
+
+# The entry point: ReTrace and its main method.
+
+-keep public class proguard.retrace.ReTrace {
+ public static void main(java.lang.String[]);
+}
diff --git a/examples/servlets.pro b/examples/servlets.pro
new file mode 100644
index 0000000..3e16c8c
--- /dev/null
+++ b/examples/servlets.pro
@@ -0,0 +1,58 @@
+#
+# This ProGuard configuration file illustrates how to process servlets.
+# Usage:
+# java -jar proguard.jar @servlets.pro
+#
+
+# Specify the input jars, output jars, and library jars.
+
+-injars in.jar
+-outjars out.jar
+
+-libraryjars <java.home>/lib/rt.jar
+-libraryjars /usr/local/java/servlet/servlet.jar
+
+# Preserve all public servlets.
+
+-keep public class * implements javax.servlet.Servlet
+
+# Print out a list of what we're preserving.
+
+-printseeds
+
+# Preserve all annotations.
+
+-keepattributes *Annotation*
+
+# Preserve all native method names and the names of their classes.
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# Preserve a method that is required in all enumeration classes.
+
+-keepclassmembers class * extends java.lang.Enum {
+ public **[] values();
+}
+
+# Explicitly preserve all serialization members. The Serializable interface
+# is only a marker interface, so it wouldn't save them.
+# You can comment this out if your library doesn't use serialization.
+# If your code contains serializable classes that have to be backward
+# compatible, please refer to the manual.
+
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+
+# Your application may contain more items that need to be preserved;
+# typically classes that are dynamically created using Class.forName:
+
+# -keep public class mypackage.MyClass
+# -keep public interface mypackage.MyInterface
+# -keep public class * implements mypackage.MyInterface
diff --git a/src/proguard/ArgumentWordReader.java b/src/proguard/ArgumentWordReader.java
new file mode 100644
index 0000000..7494205
--- /dev/null
+++ b/src/proguard/ArgumentWordReader.java
@@ -0,0 +1,83 @@
+/* $Id: ArgumentWordReader.java,v 1.11 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import java.io.*;
+
+
+/**
+ * A <code>WordReader</code> that returns words from an argument list.
+ * Single arguments are split into individual words if necessary.
+ *
+ * @author Eric Lafortune
+ */
+public class ArgumentWordReader extends WordReader
+{
+ private String[] arguments;
+ private int index = 0;
+
+
+ /**
+ * Creates a new ArgumentWordReader for the given arguments.
+ */
+ public ArgumentWordReader(String[] arguments)
+ {
+ this.arguments = arguments;
+ }
+
+
+ // Implementations for WordReader.
+
+ protected String nextLine() throws IOException
+ {
+ return index < arguments.length ?
+ arguments[index++] :
+ null;
+ }
+
+
+ protected String lineLocationDescription()
+ {
+ return "argument number " + index;
+ }
+
+
+ /**
+ * Test application that prints out the individual words of
+ * the argument list.
+ */
+ public static void main(String[] args) {
+ try
+ {
+ WordReader reader = new ArgumentWordReader(args);
+ while (true)
+ {
+ String word = reader.nextWord();
+ if (word == null)
+ System.exit(-1);
+
+ System.err.println("["+word+"]");
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/ClassMemberSpecification.java b/src/proguard/ClassMemberSpecification.java
new file mode 100644
index 0000000..45cfab1
--- /dev/null
+++ b/src/proguard/ClassMemberSpecification.java
@@ -0,0 +1,103 @@
+/* $Id: ClassMemberSpecification.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+
+/**
+ * This class stores a specification of class members. The specification is
+ * template-based: the class member names and descriptors can contain wildcards.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassMemberSpecification
+{
+ public int requiredSetAccessFlags;
+ public int requiredUnsetAccessFlags;
+ public String name;
+ public String descriptor;
+
+
+ /**
+ * Creates a new option to keep the specified class member(s).
+ */
+ public ClassMemberSpecification()
+ {
+ this(0,
+ 0,
+ null,
+ null);
+ }
+
+
+ /**
+ * Creates a new option to keep the specified class member(s).
+ *
+ * @param requiredSetAccessFlags the class access flags that must be set
+ * in order for the class to apply.
+ * @param requiredUnsetAccessFlags the class access flags that must be unset
+ * in order for the class to apply.
+ * @param name the class member name. The name may be
+ * null to specify any class member or it
+ * may contain "*" or "?" wildcards.
+ * @param descriptor the class member descriptor. The
+ * descriptor may be null to specify any
+ * class member or it may contain
+ * "**", "*", or "?" wildcards.
+ */
+ public ClassMemberSpecification(int requiredSetAccessFlags,
+ int requiredUnsetAccessFlags,
+ String name,
+ String descriptor)
+ {
+ this.requiredSetAccessFlags = requiredSetAccessFlags;
+ this.requiredUnsetAccessFlags = requiredUnsetAccessFlags;
+ this.name = name;
+ this.descriptor = descriptor;
+ }
+
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ ClassMemberSpecification other = (ClassMemberSpecification)object;
+ return
+ (this.requiredSetAccessFlags == other.requiredSetAccessFlags ) &&
+ (this.requiredUnsetAccessFlags == other.requiredUnsetAccessFlags) &&
+ (this.name == null ? other.name == null : this.name.equals(other.name) ) &&
+ (this.descriptor == null ? other.descriptor == null : this.descriptor.equals(other.descriptor));
+ }
+
+ public int hashCode()
+ {
+ return
+ requiredSetAccessFlags ^
+ requiredUnsetAccessFlags ^
+ (name == null ? 0 : name.hashCode() ) ^
+ (descriptor == null ? 0 : descriptor.hashCode());
+ }
+}
diff --git a/src/proguard/ClassPath.java b/src/proguard/ClassPath.java
new file mode 100644
index 0000000..4df62c6
--- /dev/null
+++ b/src/proguard/ClassPath.java
@@ -0,0 +1,94 @@
+/* $Id: ClassPath.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import java.util.*;
+
+
+/**
+ * This class represents a class path, as a list of ClassPathEntry objects.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassPath
+{
+ private List classPathEntries = new ArrayList();
+
+
+ /**
+ * Returns whether the class path contains any output entries.
+ */
+ public boolean hasOutput()
+ {
+ for (int index = 0; index < classPathEntries.size(); index++)
+ {
+ if (((ClassPathEntry)classPathEntries.get(index)).isOutput())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ // Delegates to List.
+
+ public void clear()
+ {
+ classPathEntries.clear();
+ }
+
+ public void add(int index, ClassPathEntry classPathEntry)
+ {
+ classPathEntries.add(index, classPathEntry);
+ }
+
+ public boolean add(ClassPathEntry classPathEntry)
+ {
+ return classPathEntries.add(classPathEntry);
+ }
+
+ public boolean addAll(ClassPath classPath)
+ {
+ return classPathEntries.addAll(classPath.classPathEntries);
+ }
+
+ public ClassPathEntry get(int index)
+ {
+ return (ClassPathEntry)classPathEntries.get(index);
+ }
+
+ public ClassPathEntry remove(int index)
+ {
+ return (ClassPathEntry)classPathEntries.remove(index);
+ }
+
+ public boolean isEmpty()
+ {
+ return classPathEntries.isEmpty();
+ }
+
+ public int size()
+ {
+ return classPathEntries.size();
+ }
+}
diff --git a/src/proguard/ClassPathEntry.java b/src/proguard/ClassPathEntry.java
new file mode 100644
index 0000000..808efbb
--- /dev/null
+++ b/src/proguard/ClassPathEntry.java
@@ -0,0 +1,157 @@
+/* $Id: ClassPathEntry.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+
+/**
+ * This class represents an entry from a class path: a jar, a war, a zip, an
+ * ear, or a directory, with a name and a flag to indicates whether the entry is
+ * an input entry or an output entry. Optional filters can be specified for the
+ * names of the contained resource/class files, jars, wars, ears, and zips.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassPathEntry
+{
+ private String name;
+ private boolean output;
+ private String filter;
+ private String jarFilter;
+ private String warFilter;
+ private String earFilter;
+ private String zipFilter;
+
+
+ /**
+ * Creates a new ClassPathEntry with the given name and type.
+ */
+ public ClassPathEntry(String name, boolean isOutput)
+ {
+ this.name = name;
+ this.output = isOutput;
+ }
+
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+
+ public boolean isOutput()
+ {
+ return output;
+ }
+
+
+ public void setOutput(boolean output)
+ {
+ this.output = output;
+ }
+
+
+ public String getFilter()
+ {
+ return filter;
+ }
+
+ public void setFilter(String filter)
+ {
+ this.filter = filter == null || filter.length() == 0 ? null : filter;
+ }
+
+
+ public String getJarFilter()
+ {
+ return jarFilter;
+ }
+
+ public void setJarFilter(String filter)
+ {
+ this.jarFilter = filter == null || filter.length() == 0 ? null : filter;
+ }
+
+
+ public String getWarFilter()
+ {
+ return warFilter;
+ }
+
+ public void setWarFilter(String filter)
+ {
+ this.warFilter = filter == null || filter.length() == 0 ? null : filter;
+ }
+
+
+ public String getEarFilter()
+ {
+ return earFilter;
+ }
+
+ public void setEarFilter(String filter)
+ {
+ this.earFilter = filter == null || filter.length() == 0 ? null : filter;
+ }
+
+
+ public String getZipFilter()
+ {
+ return zipFilter;
+ }
+
+ public void setZipFilter(String filter)
+ {
+ this.zipFilter = filter == null || filter.length() == 0 ? null : filter;
+ }
+
+
+ public String toString()
+ {
+ String string = name;
+
+ if (filter != null ||
+ jarFilter != null ||
+ warFilter != null ||
+ earFilter != null ||
+ zipFilter != null)
+ {
+ string +=
+ ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD +
+ (zipFilter != null ? zipFilter : "") +
+ ConfigurationConstants.SEPARATOR_KEYWORD +
+ (earFilter != null ? earFilter : "") +
+ ConfigurationConstants.SEPARATOR_KEYWORD +
+ (warFilter != null ? warFilter : "") +
+ ConfigurationConstants.SEPARATOR_KEYWORD +
+ (jarFilter != null ? jarFilter : "") +
+ ConfigurationConstants.SEPARATOR_KEYWORD +
+ (filter != null ? filter : "") +
+ ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD;
+ }
+
+ return string;
+ }
+}
diff --git a/src/proguard/ClassSpecification.java b/src/proguard/ClassSpecification.java
new file mode 100644
index 0000000..faeb157
--- /dev/null
+++ b/src/proguard/ClassSpecification.java
@@ -0,0 +1,224 @@
+/* $Id: ClassSpecification.java,v 1.3 2004/08/28 17:03:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import java.util.*;
+
+
+/**
+ * This class stores a specification of classes and possibly class members.
+ * The specification is template-based: the class names and class member names
+ * and descriptors can contain wildcards. Classes can be specified explicitly,
+ * or as extensions or implementations in the class hierarchy.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassSpecification implements Cloneable
+{
+ public int requiredSetAccessFlags;
+ public int requiredUnsetAccessFlags;
+ public String className;
+ public String extendsClassName;
+ public boolean markClassFiles;
+ public boolean markConditionally;
+ public String comments;
+
+ public List fieldSpecifications;
+ public List methodSpecifications;
+
+
+ /**
+ * Creates a new option to keep all possible class(es).
+ * The option doesn't have comments.
+ */
+ public ClassSpecification()
+ {
+ this(0,
+ 0,
+ null,
+ null,
+ true,
+ false);
+ }
+
+
+ /**
+ * Creates a new option to keep the specified class(es).
+ * The option doesn't have comments.
+ *
+ * @param requiredSetAccessFlags the class access flags that must be set
+ * in order for the class to apply.
+ * @param requiredUnsetAccessFlags the class access flags that must be unset
+ * in order for the class to apply.
+ * @param className the class name. The name may be null to
+ * specify any class, or it may contain
+ * "**", "*", or "?" wildcards.
+ * @param extendsClassName the name of the class that the class must
+ * extend or implement in order to apply.
+ * The name may be null to specify any class.
+ * @param markClassFiles specifies whether to mark the class files.
+ * If false, only class members are marked.
+ * If true, the class files are marked as
+ * well.
+ * @param markConditionally specifies whether to mark the class files
+ * and class members conditionally.
+ * If true, class files and class members
+ * are marked, on the condition that all
+ * specified class members are present.
+ */
+ public ClassSpecification(int requiredSetAccessFlags,
+ int requiredUnsetAccessFlags,
+ String className,
+ String extendsClassName,
+ boolean markClassFiles,
+ boolean markConditionally)
+ {
+ this(requiredSetAccessFlags,
+ requiredUnsetAccessFlags,
+ className,
+ extendsClassName,
+ markClassFiles,
+ markConditionally,
+ null);
+ }
+
+
+ /**
+ * Creates a new option to keep the specified class(es).
+ *
+ * @param requiredSetAccessFlags the class access flags that must be set
+ * in order for the class to apply.
+ * @param requiredUnsetAccessFlags the class access flags that must be unset
+ * in order for the class to apply.
+ * @param className the class name. The name may be null to
+ * specify any class, or it may contain
+ * "**", "*", or "?" wildcards.
+ * @param extendsClassName the name of the class that the class must
+ * extend or implement in order to apply.
+ * The name may be null to specify any class.
+ * @param markClassFiles specifies whether to mark the class files.
+ * If false, only class members are marked.
+ * If true, the class files are marked as
+ * well.
+ * @param markConditionally specifies whether to mark the class files
+ * and class members conditionally.
+ * If true, class files and class members
+ * are marked, on the condition that all
+ * specified class members are present.
+ * @param comments provides optional comments on this option.
+ */
+ public ClassSpecification(int requiredSetAccessFlags,
+ int requiredUnsetAccessFlags,
+ String className,
+ String extendsClassName,
+ boolean markClassFiles,
+ boolean markConditionally,
+ String comments)
+ {
+ this.requiredSetAccessFlags = requiredSetAccessFlags;
+ this.requiredUnsetAccessFlags = requiredUnsetAccessFlags;
+ this.className = className;
+ this.extendsClassName = extendsClassName;
+ this.markClassFiles = markClassFiles;
+ this.markConditionally = markConditionally;
+ this.comments = comments;
+ }
+
+
+ /**
+ * Specifies to keep the specified field(s) of this option's class(es).
+ *
+ * @param fieldSpecification the field specification.
+ */
+ public void addField(ClassMemberSpecification fieldSpecification)
+ {
+ if (fieldSpecifications == null)
+ {
+ fieldSpecifications = new ArrayList();
+ }
+
+ fieldSpecifications.add(fieldSpecification);
+ }
+
+
+ /**
+ * Specifies to keep the specified method(s) of this option's class(es).
+ *
+ * @param methodSpecification the method specification.
+ */
+ public void addMethod(ClassMemberSpecification methodSpecification)
+ {
+ if (methodSpecifications == null)
+ {
+ methodSpecifications = new ArrayList();
+ }
+
+ methodSpecifications.add(methodSpecification);
+ }
+
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ ClassSpecification other = (ClassSpecification)object;
+ return
+ (this.requiredSetAccessFlags == other.requiredSetAccessFlags ) &&
+ (this.requiredUnsetAccessFlags == other.requiredUnsetAccessFlags) &&
+ (this.markClassFiles == other.markClassFiles ) &&
+ (this.markConditionally == other.markConditionally ) &&
+ (this.className == null ? other.className == null : this.className.equals(other.className)) &&
+ (this.extendsClassName == null ? other.extendsClassName == null : this.extendsClassName.equals(other.extendsClassName)) &&
+ (this.fieldSpecifications == null ? other.fieldSpecifications == null : this.fieldSpecifications.equals(other.fieldSpecifications)) &&
+ (this.methodSpecifications == null ? other.methodSpecifications == null : this.methodSpecifications.equals(other.methodSpecifications));
+ }
+
+ public int hashCode()
+ {
+ return
+ requiredSetAccessFlags ^
+ requiredUnsetAccessFlags ^
+ (className == null ? 0 : className.hashCode() ) ^
+ (extendsClassName == null ? 0 : extendsClassName.hashCode() ) ^
+ (markClassFiles ? 0 : 1 ) ^
+ (markConditionally ? 0 : 2 ) ^
+ (fieldSpecifications == null ? 0 : fieldSpecifications.hashCode() ) ^
+ (methodSpecifications == null ? 0 : methodSpecifications.hashCode());
+ }
+
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ return null;
+ }
+ }
+}
diff --git a/src/proguard/ClassSpecificationVisitorFactory.java b/src/proguard/ClassSpecificationVisitorFactory.java
new file mode 100644
index 0000000..5094a99
--- /dev/null
+++ b/src/proguard/ClassSpecificationVisitorFactory.java
@@ -0,0 +1,358 @@
+/* $Id: ClassSpecificationVisitorFactory.java,v 1.5 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import proguard.classfile.visitor.*;
+
+import java.util.*;
+
+
+/**
+ * This factory creates visitors to efficiently travel to specified classes and
+ * class members.
+ *
+ * @author Eric Lafortune
+ */
+class ClassSpecificationVisitorFactory
+{
+ /**
+ * Creates a new ClassPoolVisitor to efficiently travel to the specified
+ * classes and class members.
+ *
+ * @param classSpecifications the specifications of the classes and class
+ * members to visit.
+ * @param classFileVisitor the ClassFileVisitor to be applied to matching
+ * classes.
+ * @param memberInfoVisitor the MemberInfoVisitor to be applied to matching
+ * class members.
+ */
+ public static ClassPoolVisitor createClassPoolVisitor(List classSpecifications,
+ ClassFileVisitor classFileVisitor,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ MultiClassPoolVisitor multiClassPoolVisitor = new MultiClassPoolVisitor();
+
+ if (classSpecifications != null)
+ {
+ addClassPoolVisitors(classSpecifications,
+ classFileVisitor,
+ memberInfoVisitor,
+ multiClassPoolVisitor);
+ }
+
+ return multiClassPoolVisitor;
+ }
+
+
+ /**
+ * Adds new ClassPoolVisitor instances to the given MultiClassPoolVisitor,
+ * to efficiently travel to the specified classes and class members.
+
+ * @param classSpecifications the specifications of the classes and class
+ * members to visit.
+ * @param classFileVisitor the ClassFileVisitor to be applied to matching
+ * classes.
+ * @param memberInfoVisitor the MemberInfoVisitor to be applied to matching
+ * class members.
+ * @param multiClassPoolVisitor the MultiClassPoolVisitor to which the new
+ * visitors will be added.
+ */
+ private static void addClassPoolVisitors(List classSpecifications,
+ ClassFileVisitor classFileVisitor,
+ MemberInfoVisitor memberInfoVisitor,
+ MultiClassPoolVisitor multiClassPoolVisitor)
+ {
+ for (int index = 0; index < classSpecifications.size(); index++)
+ {
+ multiClassPoolVisitor.addClassPoolVisitor(
+ createClassPoolVisitor((ClassSpecification)classSpecifications.get(index),
+ classFileVisitor,
+ memberInfoVisitor));
+ }
+ }
+
+
+ /**
+ * Creates a new ClassPoolVisitor to efficiently travel to the specified
+ * classes and class members.
+ *
+ * @param classSpecification the specifications of the class(es) and class
+ * members to visit.
+ * @param classFileVisitor the ClassFileVisitor to be applied to matching
+ * classes.
+ * @param memberInfoVisitor the MemberInfoVisitor to be applied to matching
+ * class members.
+ */
+ private static ClassPoolVisitor createClassPoolVisitor(ClassSpecification classSpecification,
+ ClassFileVisitor classFileVisitor,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ // The class file visitor for class files and their members.
+ MultiClassFileVisitor multiClassFileVisitor = new MultiClassFileVisitor();
+
+ // If specified, let the class file visitor visit the class file itself.
+ if ((classSpecification.markClassFiles ||
+ classSpecification.markConditionally) &&
+ classFileVisitor != null)
+ {
+ multiClassFileVisitor.addClassFileVisitor(classFileVisitor);
+ }
+
+ // If specified, let the member info visitor visit the class members.
+ if ((classSpecification.fieldSpecifications != null ||
+ classSpecification.methodSpecifications != null) &&
+ memberInfoVisitor != null)
+ {
+ multiClassFileVisitor.addClassFileVisitor(
+ createClassFileVisitor(classSpecification, memberInfoVisitor));
+ }
+
+ // This visitor is the starting point.
+ ClassFileVisitor composedClassFileVisitor = multiClassFileVisitor;
+
+ // If specified, let the marker visit the class file and its class
+ // members conditionally.
+ if (classSpecification.markConditionally)
+ {
+ composedClassFileVisitor =
+ createClassFileMemberInfoTester(classSpecification,
+ composedClassFileVisitor);
+ }
+
+ // By default, start visiting from the class name, if it's specified.
+ String className = classSpecification.className;
+
+ // If wildcarded, only visit class files with matching names.
+ if (className != null &&
+ containsWildCards(className))
+ {
+ composedClassFileVisitor =
+ new ClassFileNameFilter(composedClassFileVisitor,
+ className);
+
+ // We'll have to visit all classes now.
+ className = null;
+ }
+
+ // If specified, only visit class files with the right access flags.
+ if (classSpecification.requiredSetAccessFlags != 0 ||
+ classSpecification.requiredUnsetAccessFlags != 0)
+ {
+ composedClassFileVisitor =
+ new ClassFileAccessFilter(classSpecification.requiredSetAccessFlags,
+ classSpecification.requiredUnsetAccessFlags,
+ composedClassFileVisitor);
+ }
+
+ // If it's specified, start visiting from the extended class.
+ String extendsClassName = classSpecification.extendsClassName;
+
+ if (className == null &&
+ extendsClassName != null)
+ {
+ composedClassFileVisitor =
+ new ClassFileHierarchyTraveler(false, false, false, true,
+ composedClassFileVisitor);
+
+ // If wildcarded, only visit class files with matching names.
+ if (containsWildCards(extendsClassName))
+ {
+ composedClassFileVisitor =
+ new ClassFileNameFilter(composedClassFileVisitor,
+ extendsClassName);
+ }
+ else
+ {
+ // Start visiting from the extended class name.
+ className = extendsClassName;
+ }
+ }
+
+ // If specified, visit a single named class, otherwise visit all classes.
+ return className != null ?
+ (ClassPoolVisitor)new NamedClassFileVisitor(composedClassFileVisitor, className) :
+ (ClassPoolVisitor)new AllClassFileVisitor(composedClassFileVisitor);
+ }
+
+
+ /**
+ * Creates a new ClassPoolVisitor to efficiently travel to the specified class
+ * members.
+ *
+ * @param classSpecification the specifications of the class members to visit.
+ * @param memberInfoVisitor the MemberInfoVisitor to be applied to matching
+ * class members.
+ */
+ private static ClassFileVisitor createClassFileVisitor(ClassSpecification classSpecification,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ MultiClassFileVisitor multiClassFileVisitor = new MultiClassFileVisitor();
+
+ addMemberInfoVisitors(classSpecification.fieldSpecifications, true, multiClassFileVisitor, memberInfoVisitor);
+ addMemberInfoVisitors(classSpecification.methodSpecifications, false, multiClassFileVisitor, memberInfoVisitor);
+
+ // Mark the class member in this class and in super classes.
+ return new ClassFileHierarchyTraveler(true, true, false, false,
+ multiClassFileVisitor);
+ }
+
+
+ /**
+ * Adds elements to the given MultiClassFileVisitor, to apply the given
+ * MemberInfoVisitor to all class members that match the given List
+ * of options (of the given type).
+ */
+ private static void addMemberInfoVisitors(List classMemberSpecifications,
+ boolean isField,
+ MultiClassFileVisitor multiClassFileVisitor,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ if (classMemberSpecifications != null)
+ {
+ for (int index = 0; index < classMemberSpecifications.size(); index++)
+ {
+ ClassMemberSpecification classMemberSpecification =
+ (ClassMemberSpecification)classMemberSpecifications.get(index);
+
+ multiClassFileVisitor.addClassFileVisitor(
+ createClassFileVisitor(classMemberSpecification,
+ isField,
+ memberInfoVisitor));
+ }
+ }
+ }
+
+
+ /**
+ * Constructs a ClassFileVisitor that conditionally applies the given
+ * ClassFileVisitor to all classes that contain the given class members.
+ */
+ private static ClassFileVisitor createClassFileMemberInfoTester(ClassSpecification classSpecification,
+ ClassFileVisitor classFileVisitor)
+ {
+ // Create a linked list of conditional visitors, for fields and for
+ // methods.
+ return createClassFileMemberInfoTester(classSpecification.fieldSpecifications,
+ true,
+ createClassFileMemberInfoTester(classSpecification.methodSpecifications,
+ false,
+ classFileVisitor));
+ }
+
+
+ /**
+ * Constructs a ClassFileVisitor that conditionally applies the given
+ * ClassFileVisitor to all classes that contain the given List of class
+ * members (of the given type).
+ */
+ private static ClassFileVisitor createClassFileMemberInfoTester(List classMemberSpecifications,
+ boolean isField,
+ ClassFileVisitor classFileVisitor)
+ {
+ // Create a linked list of conditional visitors.
+ if (classMemberSpecifications != null)
+ {
+ for (int index = 0; index < classMemberSpecifications.size(); index++)
+ {
+ ClassMemberSpecification classMemberSpecification =
+ (ClassMemberSpecification)classMemberSpecifications.get(index);
+
+ classFileVisitor =
+ createClassFileVisitor(classMemberSpecification,
+ isField,
+ new ClassFileMemberInfoVisitor(classFileVisitor));
+ }
+ }
+
+ return classFileVisitor;
+ }
+
+
+ /**
+ * Creates a new ClassFileVisitor to efficiently travel to the specified class
+ * members.
+ *
+ * @param classMemberSpecification the specification of the class member(s)
+ * to visit.
+ * @param memberInfoVisitor the MemberInfoVisitor to be applied to
+ * matching class member(s).
+ */
+ private static ClassFileVisitor createClassFileVisitor(ClassMemberSpecification classMemberSpecification,
+ boolean isField,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ String name = classMemberSpecification.name;
+ String descriptor = classMemberSpecification.descriptor;
+
+ // If name or descriptor are not fully specified, only visit matching
+ // class members.
+ boolean fullySpecified =
+ name != null &&
+ descriptor != null &&
+ !containsWildCards(name) &&
+ !containsWildCards(descriptor);
+
+ if (!fullySpecified)
+ {
+ if (descriptor != null)
+ {
+ memberInfoVisitor =
+ new MemberInfoDescriptorFilter(descriptor, memberInfoVisitor);
+ }
+
+ if (name != null)
+ {
+ memberInfoVisitor =
+ new MemberInfoNameFilter(name, memberInfoVisitor);
+ }
+ }
+
+ // If any access flags are specified, only visit matching class members.
+ if (classMemberSpecification.requiredSetAccessFlags != 0 ||
+ classMemberSpecification.requiredUnsetAccessFlags != 0)
+ {
+ memberInfoVisitor =
+ new MemberInfoAccessFilter(classMemberSpecification.requiredSetAccessFlags,
+ classMemberSpecification.requiredUnsetAccessFlags,
+ memberInfoVisitor);
+ }
+
+ // Depending on what's specified, visit a single named class member,
+ // or all class members, filtering the matching ones.
+ return isField ?
+ fullySpecified ?
+ (ClassFileVisitor)new NamedFieldVisitor(name, descriptor, memberInfoVisitor) :
+ (ClassFileVisitor)new AllFieldVisitor(memberInfoVisitor) :
+ fullySpecified ?
+ (ClassFileVisitor)new NamedMethodVisitor(name, descriptor, memberInfoVisitor) :
+ (ClassFileVisitor)new AllMethodVisitor(memberInfoVisitor);
+ }
+
+
+ // Small utility methods.
+
+ private static boolean containsWildCards(String string)
+ {
+ return string != null &&
+ (string.indexOf('*') >= 0 ||
+ string.indexOf('?') >= 0);
+ }
+}
diff --git a/src/proguard/Configuration.java b/src/proguard/Configuration.java
new file mode 100644
index 0000000..7ebe8f1
--- /dev/null
+++ b/src/proguard/Configuration.java
@@ -0,0 +1,202 @@
+/* $Id: Configuration.java,v 1.14 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import java.util.*;
+
+
+/**
+ * The ProGuard configuration.
+ *
+ * @see ProGuard
+ *
+ * @author Eric Lafortune
+ */
+public class Configuration
+{
+ ///////////////////////////////////////////////////////////////////////////
+ // Input and output options.
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * A list of input and output entries (jars, wars, ears, zips, and directories).
+ */
+ public ClassPath programJars;
+
+ /**
+ * A list of library entries (jars, wars, ears, zips, and directories).
+ */
+ public ClassPath libraryJars;
+
+ /**
+ * Specifies whether to skip non-public library classes while reading
+ * library jars.
+ */
+ public boolean skipNonPublicLibraryClasses = true;
+
+ /**
+ * Specifies whether to skip non-public library class members while reading
+ * library classes.
+ */
+ public boolean skipNonPublicLibraryClassMembers = true;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Keep options.
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * A list of {@link ClassSpecification} instances, whose class names and
+ * class member names are to be kept from shrinking, optimization, and
+ * obfuscation.
+ */
+ public List keep;
+
+ /**
+ * A list of {@link ClassSpecification} instances, whose class names and
+ * class member names are to be kept from obfuscation.
+ */
+ public List keepNames;
+
+ /**
+ * An optional output file name for listing the kept seeds.
+ * An empty string means the standard output.
+ */
+ public String printSeeds;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Shrinking options.
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Specifies whether the code should be shrunk.
+ */
+ public boolean shrink = true;
+
+ /**
+ * An optional output file name for listing the unused classes and class
+ * members. An empty string means the standard output.
+ */
+ public String printUsage;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Optimization options.
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Specifies whether the code should be optimized.
+ */
+ public boolean optimize = true;
+
+ /**
+ * A list of {@link ClassSpecification} instances, whose methods are
+ * assumed to have no side effects.
+ */
+ public List assumeNoSideEffects;
+
+ /**
+ * Specifies whether the access of class members can be modified.
+ */
+ public boolean allowAccessModification = false;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Obfuscation options.
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Specifies whether the code should be obfuscated.
+ */
+ public boolean obfuscate = true;
+
+ /**
+ * An optional output file name for listing the obfuscation mapping.
+ * An empty string means the standard output.
+ */
+ public String printMapping;
+
+ /**
+ * An optional input file name for reading an obfuscation mapping.
+ */
+ public String applyMapping;
+
+ /**
+ * An optional name of a file containing obfuscated class member names.
+ */
+ public String obfuscationDictionary;
+
+ /**
+ * Specifies whether to apply aggressive name overloading on class members.
+ */
+ public boolean overloadAggressively = false;
+
+ /**
+ * An optional default package to which all classes whose name is obfuscated
+ * can be moved.
+ */
+ public String defaultPackage;
+
+ /**
+ * Specifies whether to use mixed case class names.
+ */
+ public boolean useMixedCaseClassNames = true;
+
+ /**
+ * A list of <code>String</code>s specifying optional attributes to be kept.
+ * A <code>null</code> list means no attributes. An empty list means all
+ * attributes. The attribute names may contain "*" or "?" wildcards, and
+ * they may be preceded by the "!" negator.
+ */
+ public List keepAttributes;
+
+ /**
+ * An optional replacement for all SourceFile attributes.
+ */
+ public String newSourceFileAttribute;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // General options.
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Specifies whether to print verbose messages.
+ */
+ public boolean verbose = false;
+
+ /**
+ * Specifies whether to print any notes.
+ */
+ public boolean note = true;
+
+ /**
+ * Specifies whether to print any warnings.
+ */
+ public boolean warn = true;
+
+ /**
+ * Specifies whether to ignore any warnings.
+ */
+ public boolean ignoreWarnings = false;
+
+ /**
+ * An optional output file name for printing out the processed code in a
+ * more or less readable form. An empty string means the standard output.
+ */
+ public String dump;
+}
diff --git a/src/proguard/ConfigurationConstants.java b/src/proguard/ConfigurationConstants.java
new file mode 100644
index 0000000..6b13a26
--- /dev/null
+++ b/src/proguard/ConfigurationConstants.java
@@ -0,0 +1,94 @@
+/* $Id: ConfigurationConstants.java,v 1.10 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+/**
+ * This class provides constants for parsing and writing ProGuard configurations.
+ *
+ * @author Eric Lafortune
+ */
+class ConfigurationConstants
+{
+ public static final String OPTION_PREFIX = "-";
+ public static final String AT_DIRECTIVE = "@";
+ public static final String INCLUDE_DIRECTIVE = "-include";
+
+ public static final String INJARS_OPTION = "-injars";
+ public static final String OUTJARS_OPTION = "-outjars";
+ public static final String LIBRARYJARS_OPTION = "-libraryjars";
+ public static final String RESOURCEJARS_OPTION = "-resourcejars";
+
+ public static final String KEEP_OPTION = "-keep";
+ public static final String KEEP_CLASS_MEMBERS_OPTION = "-keepclassmembers";
+ public static final String KEEP_CLASSES_WITH_MEMBERS_OPTION = "-keepclasseswithmembers";
+ public static final String KEEP_NAMES_OPTION = "-keepnames";
+ public static final String KEEP_CLASS_MEMBER_NAMES_OPTION = "-keepclassmembernames";
+ public static final String KEEP_CLASSES_WITH_MEMBER_NAMES_OPTION = "-keepclasseswithmembernames";
+ public static final String PRINT_SEEDS_OPTION = "-printseeds";
+
+ public static final String DONT_SHRINK_OPTION = "-dontshrink";
+ public static final String PRINT_USAGE_OPTION = "-printusage";
+
+ public static final String DONT_OPTIMIZE_OPTION = "-dontoptimize";
+ public static final String ASSUME_NO_SIDE_EFFECTS_OPTION = "-assumenosideeffects";
+ public static final String ALLOW_ACCESS_MODIFICATION_OPTION = "-allowaccessmodification";
+
+ public static final String DONT_OBFUSCATE_OPTION = "-dontobfuscate";
+ public static final String PRINT_MAPPING_OPTION = "-printmapping";
+ public static final String APPLY_MAPPING_OPTION = "-applymapping";
+ public static final String OBFUSCATION_DICTIONARY_OPTION = "-obfuscationdictionary";
+ public static final String OVERLOAD_AGGRESSIVELY_OPTION = "-overloadaggressively";
+ public static final String DEFAULT_PACKAGE_OPTION = "-defaultpackage";
+ public static final String DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION = "-dontusemixedcaseclassnames";
+ public static final String KEEP_ATTRIBUTES_OPTION = "-keepattributes";
+ public static final String RENAME_SOURCE_FILE_ATTRIBUTE_OPTION = "-renamesourcefileattribute";
+
+ public static final String VERBOSE_OPTION = "-verbose";
+ public static final String DONT_NOTE_OPTION = "-dontnote";
+ public static final String DONT_WARN_OPTION = "-dontwarn";
+ public static final String IGNORE_WARNINGS_OPTION = "-ignorewarnings";
+ public static final String DUMP_OPTION = "-dump";
+ public static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION = "-dontskipnonpubliclibraryclasses";
+ public static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION = "-dontskipnonpubliclibraryclassmembers";
+
+ public static final String ANY_ATTRIBUTE_KEYWORD = "*";
+ public static final String ATTRIBUTE_SEPARATOR_KEYWORD = ",";
+
+ public static final String JAR_SEPARATOR_KEYWORD = System.getProperty("path.separator");
+
+ public static final char OPEN_SYSTEM_PROPERTY = '<';
+ public static final char CLOSE_SYSTEM_PROPERTY = '>';
+
+ public static final String NEGATOR_KEYWORD = "!";
+ public static final String CLASS_KEYWORD = "class";
+ public static final String ANY_CLASS_KEYWORD = "*";
+ public static final String IMPLEMENTS_KEYWORD = "implements";
+ public static final String EXTENDS_KEYWORD = "extends";
+ public static final String OPEN_KEYWORD = "{";
+ public static final String ANY_CLASS_MEMBER_KEYWORD = "*";
+ public static final String ANY_FIELD_KEYWORD = "<fields>";
+ public static final String ANY_METHOD_KEYWORD = "<methods>";
+ public static final String OPEN_ARGUMENTS_KEYWORD = "(";
+ public static final String ARGUMENT_SEPARATOR_KEYWORD = ",";
+ public static final String CLOSE_ARGUMENTS_KEYWORD = ")";
+ public static final String SEPARATOR_KEYWORD = ";";
+ public static final String CLOSE_KEYWORD = "}";
+}
diff --git a/src/proguard/ConfigurationParser.java b/src/proguard/ConfigurationParser.java
new file mode 100644
index 0000000..63700e7
--- /dev/null
+++ b/src/proguard/ConfigurationParser.java
@@ -0,0 +1,919 @@
+/* $Id: ConfigurationParser.java,v 1.19 2004/12/18 20:22:13 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.util.*;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+
+
+/**
+ * This class parses ProGuard configurations. Configurations can be read from an
+ * array of arguments or from a configuration file or URL.
+ *
+ * @author Eric Lafortune
+ */
+public class ConfigurationParser
+{
+ private WordReader reader;
+ private String nextWord;
+ private String lastComments;
+
+
+ /**
+ * Creates a new ConfigurationParser for the given String arguments.
+ */
+ public ConfigurationParser(String[] args) throws IOException
+ {
+ reader = new ArgumentWordReader(args);
+ readNextWord();
+ }
+
+
+ /**
+ * Creates a new ConfigurationParser for the given file name.
+ */
+ public ConfigurationParser(String fileName) throws IOException
+ {
+ reader = new FileWordReader(fileName);
+ readNextWord();
+ }
+
+
+ /**
+ * Creates a new ConfigurationParser for the given URL.
+ */
+ public ConfigurationParser(URL url) throws IOException
+ {
+ reader = new FileWordReader(url);
+ readNextWord();
+ }
+
+
+ /**
+ * Parses and returns the configuration.
+ * @param configuration the configuration that is updated as a side-effect.
+ * @throws ParseException if the any of the configuration settings contains
+ * a syntax error.
+ * @throws IOException if an IO error occurs while reading a configuration.
+ */
+ public void parse(Configuration configuration) throws ParseException, IOException
+ {
+ while (nextWord != null)
+ {
+ lastComments = reader.lastComments();
+
+ // First include directives.
+ if (ConfigurationConstants.AT_DIRECTIVE .startsWith(nextWord) ||
+ ConfigurationConstants.INCLUDE_DIRECTIVE .startsWith(nextWord)) parseIncludeArgument();
+
+ // Then configuration options with or without arguments.
+ else if (ConfigurationConstants.INJARS_OPTION .startsWith(nextWord)) configuration.programJars = parseClassPathArgument(configuration.programJars, false);
+ else if (ConfigurationConstants.OUTJARS_OPTION .startsWith(nextWord)) configuration.programJars = parseClassPathArgument(configuration.programJars, true);
+ else if (ConfigurationConstants.LIBRARYJARS_OPTION .startsWith(nextWord)) configuration.libraryJars = parseClassPathArgument(configuration.libraryJars, false);
+ else if (ConfigurationConstants.RESOURCEJARS_OPTION .startsWith(nextWord)) throw new ParseException("The '-resourcejars' option is no longer supported. Please use the '-injars' option for all input");
+ else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION .startsWith(nextWord)) configuration.skipNonPublicLibraryClasses = parseNoArgument(false);
+ else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION.startsWith(nextWord)) configuration.skipNonPublicLibraryClassMembers = parseNoArgument(false);
+
+ else if (ConfigurationConstants.KEEP_OPTION .startsWith(nextWord)) configuration.keep = parseClassSpecificationArguments(configuration.keep, true, false);
+ else if (ConfigurationConstants.KEEP_CLASS_MEMBERS_OPTION .startsWith(nextWord)) configuration.keep = parseClassSpecificationArguments(configuration.keep, false, false);
+ else if (ConfigurationConstants.KEEP_CLASSES_WITH_MEMBERS_OPTION .startsWith(nextWord)) configuration.keep = parseClassSpecificationArguments(configuration.keep, false, true);
+ else if (ConfigurationConstants.KEEP_NAMES_OPTION .startsWith(nextWord)) configuration.keepNames = parseClassSpecificationArguments(configuration.keepNames, true, false);
+ else if (ConfigurationConstants.KEEP_CLASS_MEMBER_NAMES_OPTION .startsWith(nextWord)) configuration.keepNames = parseClassSpecificationArguments(configuration.keepNames, false, false);
+ else if (ConfigurationConstants.KEEP_CLASSES_WITH_MEMBER_NAMES_OPTION .startsWith(nextWord)) configuration.keepNames = parseClassSpecificationArguments(configuration.keepNames, false, true);
+ else if (ConfigurationConstants.PRINT_SEEDS_OPTION .startsWith(nextWord)) configuration.printSeeds = parseOptionalArgument();
+
+ else if (ConfigurationConstants.DONT_SHRINK_OPTION .startsWith(nextWord)) configuration.shrink = parseNoArgument(false);
+ else if (ConfigurationConstants.PRINT_USAGE_OPTION .startsWith(nextWord)) configuration.printUsage = parseOptionalArgument();
+
+ else if (ConfigurationConstants.DONT_OPTIMIZE_OPTION .startsWith(nextWord)) configuration.optimize = parseNoArgument(false);
+ else if (ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION .startsWith(nextWord)) configuration.assumeNoSideEffects = parseClassSpecificationArguments(configuration.assumeNoSideEffects, false, false);
+ else if (ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION .startsWith(nextWord)) configuration.allowAccessModification = parseNoArgument(true);
+
+ else if (ConfigurationConstants.DONT_OBFUSCATE_OPTION .startsWith(nextWord)) configuration.obfuscate = parseNoArgument(false);
+ else if (ConfigurationConstants.PRINT_MAPPING_OPTION .startsWith(nextWord)) configuration.printMapping = parseOptionalArgument();
+ else if (ConfigurationConstants.APPLY_MAPPING_OPTION .startsWith(nextWord)) configuration.applyMapping = parseOptionalArgument();
+ else if (ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION .startsWith(nextWord)) configuration.obfuscationDictionary = parseObfuscationDictionaryArgument();
+ else if (ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION .startsWith(nextWord)) configuration.overloadAggressively = parseNoArgument(true);
+ else if (ConfigurationConstants.DEFAULT_PACKAGE_OPTION .startsWith(nextWord)) configuration.defaultPackage = ClassUtil.internalClassName(parseOptionalArgument());
+ else if (ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION .startsWith(nextWord)) configuration.useMixedCaseClassNames = parseNoArgument(false);
+ else if (ConfigurationConstants.KEEP_ATTRIBUTES_OPTION .startsWith(nextWord)) configuration.keepAttributes = parseKeepAttributesArguments(configuration.keepAttributes);
+ else if (ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION .startsWith(nextWord)) configuration.newSourceFileAttribute = parseOptionalArgument();
+
+ else if (ConfigurationConstants.VERBOSE_OPTION .startsWith(nextWord)) configuration.verbose = parseNoArgument(true);
+ else if (ConfigurationConstants.DONT_NOTE_OPTION .startsWith(nextWord)) configuration.note = parseNoArgument(false);
+ else if (ConfigurationConstants.DONT_WARN_OPTION .startsWith(nextWord)) configuration.warn = parseNoArgument(false);
+ else if (ConfigurationConstants.IGNORE_WARNINGS_OPTION .startsWith(nextWord)) configuration.ignoreWarnings = parseNoArgument(true);
+ else if (ConfigurationConstants.DUMP_OPTION .startsWith(nextWord)) configuration.dump = parseOptionalArgument();
+ else
+ {
+ throw new ParseException("Unknown configuration " + reader.locationDescription());
+ }
+ }
+ }
+
+
+ private void parseIncludeArgument()
+ throws ParseException, IOException
+ {
+ // Read the configuation file name.
+ readNextWord("configuration file name");
+
+ reader.includeWordReader(new FileWordReader(replaceSystemProperties(nextWord)));
+
+ readNextWord();
+ }
+
+
+ private ClassPath parseClassPathArgument(ClassPath classPath,
+ boolean isOutput)
+ throws ParseException, IOException
+ {
+ // Create a new List if necessary.
+ if (classPath == null)
+ {
+ classPath = new ClassPath();
+ }
+
+ while (true)
+ {
+ // Read the next jar name.
+ readNextWord("jar or directory name");
+
+ // Create a new class path entry.
+ ClassPathEntry entry = new ClassPathEntry(replaceSystemProperties(nextWord),
+ isOutput);
+
+ // Read the opening parenthesis or the separator, if any.
+ readNextWord();
+
+ // Read the optional filters.
+ if (!configurationEnd() &&
+ ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(nextWord))
+ {
+ // Read all filters in an array.
+ String[] filters = new String[5];
+
+ int counter = 0;
+ do
+ {
+ // Read the filter.
+ filters[counter++] = ListUtil.commaSeparatedString(parseCommaSeparatedList(false, true));
+ }
+ while (counter < filters.length &&
+ ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord));
+
+ // Make sure there is a closing parenthesis.
+ if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord))
+ {
+ throw new ParseException("Expecting separating '" + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD +
+ "' or '" + ConfigurationConstants.SEPARATOR_KEYWORD +
+ "', or closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD +
+ "' before " + reader.locationDescription());
+ }
+
+ // Set all filters from the array on the entry.
+ entry.setFilter(filters[--counter]);
+ if (counter > 0)
+ {
+ entry.setJarFilter(filters[--counter]);
+ if (counter > 0)
+ {
+ entry.setWarFilter(filters[--counter]);
+ if (counter > 0)
+ {
+ entry.setEarFilter(filters[--counter]);
+ if (counter > 0)
+ {
+ entry.setZipFilter(filters[--counter]);
+ }
+ }
+ }
+ }
+
+ // Read the separator, if any.
+ readNextWord();
+ }
+
+ // Add the entry to the list.
+ classPath.add(entry);
+
+ if (configurationEnd())
+ {
+ return classPath;
+ }
+
+ if (!nextWord.equals(ConfigurationConstants.JAR_SEPARATOR_KEYWORD))
+ {
+ throw new ParseException("Expecting class path separator '" + ConfigurationConstants.JAR_SEPARATOR_KEYWORD +
+ "' before " + reader.locationDescription());
+ }
+ }
+ }
+
+
+ private List parseKeepAttributesArguments(List keepAttributes)
+ throws ParseException, IOException
+ {
+ // Create a new List if necessary.
+ if (keepAttributes == null)
+ {
+ keepAttributes = new ArrayList();
+ }
+
+ // Read the first attribute name.
+ readNextWord();
+
+ // Should we keep all attributes?
+ if (configurationEnd())
+ {
+ keepAttributes.clear();
+ return keepAttributes;
+ }
+
+ if (nextWord.equals(ConfigurationConstants.ANY_ATTRIBUTE_KEYWORD))
+ {
+ keepAttributes.clear();
+ readNextWord();
+ return keepAttributes;
+ }
+
+ while (true)
+ {
+ // Add the attribute name to the list.
+ keepAttributes.add(nextWord);
+
+ // Read the separator, if any.
+ readNextWord();
+ if (configurationEnd())
+ {
+ break;
+ }
+
+ if (!nextWord.equals(ConfigurationConstants.ATTRIBUTE_SEPARATOR_KEYWORD))
+ {
+ throw new ParseException("Expecting attribute name separator '" + ConfigurationConstants.ATTRIBUTE_SEPARATOR_KEYWORD +
+ "' before " + reader.locationDescription());
+ }
+
+ // Read the next attribute name.
+ readNextWord("attribute name");
+ }
+
+ return keepAttributes;
+ }
+
+
+ private String parseObfuscationDictionaryArgument()
+ throws ParseException, IOException
+ {
+ // Read the obfsucation dictionary name.
+ readNextWord("obfuscation dictionary name");
+
+ String obfuscationDictionary = replaceSystemProperties(nextWord);
+
+ readNextWord();
+
+ return obfuscationDictionary;
+ }
+
+
+ private String parseOptionalArgument()
+ throws IOException
+ {
+ readNextWord();
+
+ // Didn't the user specify a file name?
+ if (configurationEnd())
+ {
+ return "";
+ }
+
+ String fileName = nextWord;
+
+ readNextWord();
+
+ return fileName;
+ }
+
+
+ private boolean parseNoArgument(boolean value)
+ throws IOException
+ {
+ readNextWord();
+
+ return value;
+ }
+
+
+ private List parseClassSpecificationArguments(List classSpecifications,
+ boolean markClassFiles,
+ boolean markConditionally)
+ throws ParseException, IOException
+ {
+ // Create a new List if necessary.
+ if (classSpecifications == null)
+ {
+ classSpecifications = new ArrayList();
+ }
+
+ // Read and add the keep configuration.
+ classSpecifications.add(parseClassSpecificationArguments(markClassFiles,
+ markConditionally));
+
+ return classSpecifications;
+ }
+
+
+ private ClassSpecification parseClassSpecificationArguments(boolean markClassFiles,
+ boolean markConditionally)
+ throws ParseException, IOException
+ {
+ // Remember the comments preceeding this option.
+ String comments = lastComments;
+
+ // Parse the class access modifiers, if any.
+ int requiredSetClassAccessFlags = 0;
+ int requiredUnsetClassAccessFlags = 0;
+
+ while (true)
+ {
+ readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD + "'" +
+ " or '" + ClassConstants.EXTERNAL_ACC_INTERFACE + "'");
+
+ if (ConfigurationConstants.CLASS_KEYWORD.equals(nextWord))
+ {
+ // The class keyword. Stop parsing the class access modifiers.
+ break;
+ }
+
+ // Strip the negating sign, if any.
+ String strippedWord = nextWord.startsWith(ConfigurationConstants.NEGATOR_KEYWORD) ?
+ nextWord.substring(1) :
+ nextWord;
+
+ int accessFlag =
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_INTERFACE) ? ClassConstants.INTERNAL_ACC_INTERFACE :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT :
+ unknownAccessFlag();
+ if (strippedWord == nextWord)
+ {
+ requiredSetClassAccessFlags |= accessFlag;
+ }
+ else
+ {
+ requiredUnsetClassAccessFlags |= accessFlag;
+ }
+
+
+ if ((requiredSetClassAccessFlags &
+ requiredUnsetClassAccessFlags) != 0)
+ {
+ throw new ParseException("Conflicting class access modifiers for '" + strippedWord +
+ "' before " + reader.locationDescription());
+ }
+
+ if (ClassConstants.EXTERNAL_ACC_INTERFACE.equals(strippedWord))
+ {
+ // The interface keyword. Stop parsing the class flags.
+ break;
+ }
+ }
+
+ readNextWord("class name or interface name");
+ checkJavaIdentifier("class name or interface name");
+
+ // Parse the class name part. For backward compatibility, allow a
+ // single "*" wildcard to match any class.
+ String externalClassName = nextWord;
+ String className = ConfigurationConstants.ANY_CLASS_KEYWORD.equals(externalClassName) ?
+ null :
+ ClassUtil.internalClassName(externalClassName);
+
+ readNextWord();
+
+ String extendsClassName = null;
+
+ if (!configurationEnd())
+ {
+ // Parse 'implements ...' or 'extends ...' part, if any.
+ if (ConfigurationConstants.IMPLEMENTS_KEYWORD.equals(nextWord) ||
+ ConfigurationConstants.EXTENDS_KEYWORD.equals(nextWord))
+ {
+ readNextWord("class name or interface name");
+ checkJavaIdentifier("class name or interface name");
+ extendsClassName = ClassUtil.internalClassName(nextWord);
+
+ readNextWord();
+ }
+ }
+
+ // Create the basic class specification.
+ ClassSpecification classSpecification =
+ new ClassSpecification(requiredSetClassAccessFlags,
+ requiredUnsetClassAccessFlags,
+ className,
+ extendsClassName,
+ markClassFiles,
+ markConditionally,
+ comments);
+
+
+ // Now modify this ClassSpecification, adding any class members.
+ if (!configurationEnd())
+ {
+ // Check the class member opening part.
+ if (!ConfigurationConstants.OPEN_KEYWORD.equals(nextWord))
+ {
+ throw new ParseException("Expecting opening '" + ConfigurationConstants.OPEN_KEYWORD +
+ "' at " + reader.locationDescription());
+ }
+
+ // Parse all class members.
+ while (parseClassMemberSpecificationArguments(externalClassName,
+ classSpecification));
+ }
+
+ return classSpecification;
+ }
+
+
+ private boolean parseClassMemberSpecificationArguments(String externalClassName,
+ ClassSpecification classSpecification) throws ParseException, IOException
+ {
+ // Parse the class member access modifiers, if any.
+ int requiredSetMemberAccessFlags = 0;
+ int requiredUnsetMemberAccessFlags = 0;
+
+ while (true)
+ {
+ readNextWord("class member description" +
+ " or closing '" + ConfigurationConstants.CLOSE_KEYWORD + "'");
+
+ if (requiredSetMemberAccessFlags == 0 &&
+ requiredUnsetMemberAccessFlags == 0 &&
+ ConfigurationConstants.CLOSE_KEYWORD.equals(nextWord))
+ {
+ // The closing brace. Stop parsing the class members.
+ readNextWord();
+
+ return false;
+ }
+
+ String strippedWord = nextWord.startsWith("!") ?
+ nextWord.substring(1) :
+ nextWord;
+
+ int accessFlag =
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_PRIVATE) ? ClassConstants.INTERNAL_ACC_PRIVATE :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_PROTECTED) ? ClassConstants.INTERNAL_ACC_PROTECTED :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_STATIC) ? ClassConstants.INTERNAL_ACC_STATIC :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT :
+ strippedWord.equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT :
+ 0;
+ if (accessFlag == 0)
+ {
+ // Not a class member access modifier. Stop parsing them.
+ break;
+ }
+
+ if (strippedWord == nextWord)
+ {
+ requiredSetMemberAccessFlags |= accessFlag;
+ }
+ else
+ {
+ requiredUnsetMemberAccessFlags |= accessFlag;
+ }
+
+ // Make sure the user doesn't try to set and unset the same
+ // access flags simultaneously.
+ if ((requiredSetMemberAccessFlags &
+ requiredUnsetMemberAccessFlags) != 0)
+ {
+ throw new ParseException("Conflicting class member access modifiers for " +
+ reader.locationDescription());
+ }
+ }
+
+ // Parse the class member type and name part.
+
+ // Did we get a special wildcard?
+ if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD.equals(nextWord) ||
+ ConfigurationConstants.ANY_FIELD_KEYWORD .equals(nextWord) ||
+ ConfigurationConstants.ANY_METHOD_KEYWORD .equals(nextWord))
+ {
+ // Act according to the type of wildcard..
+ if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD.equals(nextWord))
+ {
+ checkFieldAccessFlags(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags);
+ checkMethodAccessFlags(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags);
+
+ classSpecification.addField(
+ new ClassMemberSpecification(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags,
+ null,
+ null));
+ classSpecification.addMethod(
+ new ClassMemberSpecification(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags,
+ null,
+ null));
+ }
+ else if (ConfigurationConstants.ANY_FIELD_KEYWORD.equals(nextWord))
+ {
+ checkFieldAccessFlags(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags);
+
+ classSpecification.addField(
+ new ClassMemberSpecification(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags,
+ null,
+ null));
+ }
+ else if (ConfigurationConstants.ANY_METHOD_KEYWORD.equals(nextWord))
+ {
+ checkMethodAccessFlags(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags);
+
+ classSpecification.addMethod(
+ new ClassMemberSpecification(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags,
+ null,
+ null));
+ }
+
+ // We still have to read the closing separator.
+ readNextWord("separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'");
+
+ if (!ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord))
+ {
+ throw new ParseException("Expecting separator '" + ConfigurationConstants.SEPARATOR_KEYWORD +
+ "' before " + reader.locationDescription());
+ }
+ }
+ else
+ {
+ // Make sure we have a proper type.
+ checkJavaIdentifier("class member type");
+ String type = nextWord;
+
+ readNextWord("class member name");
+ String name = nextWord;
+
+ // Did we get just one word before the opening parenthesis?
+ if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(name))
+ {
+ // This must be a constructor then.
+ // Make sure the type is a proper constructor name.
+ if (!(type.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ||
+ type.equals(externalClassName) ||
+ type.equals(ClassUtil.externalShortClassName(externalClassName))))
+ {
+ throw new ParseException("Expecting type and name " +
+ "instead of just '" + type +
+ "' before " + reader.locationDescription());
+ }
+
+ // Assign the fixed constructor type and name.
+ type = ClassConstants.EXTERNAL_TYPE_VOID;
+ name = ClassConstants.INTERNAL_METHOD_NAME_INIT;
+ }
+ else
+ {
+ // It's not a constructor.
+ // Make sure we have a proper name.
+ checkJavaIdentifier("class member name");
+
+ // Read the opening parenthesis or the separating
+ // semi-colon.
+ readNextWord("opening '" + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD +
+ "' or separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'");
+ }
+
+ // Are we looking at a field, a method, or something else?
+ if (ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord))
+ {
+ // It's a field.
+ checkFieldAccessFlags(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags);
+
+ // We already have a field descriptor.
+ String descriptor = ClassUtil.internalType(type);
+
+ // Add the field.
+ classSpecification.addField(
+ new ClassMemberSpecification(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags,
+ name,
+ descriptor));
+ }
+ else if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(nextWord))
+ {
+ // It's a method.
+ checkMethodAccessFlags(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags);
+
+ // Parse the method arguments.
+ String descriptor =
+ ClassUtil.internalMethodDescriptor(type,
+ parseCommaSeparatedList(true, false));
+
+ if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord))
+ {
+ throw new ParseException("Expecting separating '" + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD +
+ "' or closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD +
+ "' before " + reader.locationDescription());
+ }
+
+ // Read the separator after the closing parenthesis.
+ readNextWord("separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'");
+
+ if (!ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord))
+ {
+ throw new ParseException("Expecting separator '" + ConfigurationConstants.SEPARATOR_KEYWORD +
+ "' before " + reader.locationDescription());
+ }
+
+ // Add the method.
+ classSpecification.addMethod(
+ new ClassMemberSpecification(requiredSetMemberAccessFlags,
+ requiredUnsetMemberAccessFlags,
+ name,
+ descriptor));
+ }
+ else
+ {
+ // It doesn't look like a field or a method.
+ throw new ParseException("Expecting opening '" + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD +
+ "' or separator '" + ConfigurationConstants.SEPARATOR_KEYWORD +
+ "' before " + reader.locationDescription());
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Reads a comma-separated list of java identifiers or of file names,
+ * optionally ending after the closing parenthesis.
+ */
+ private List parseCommaSeparatedList(boolean checkJavaIdentifiers,
+ boolean replaceSystemProperties)
+ throws ParseException, IOException
+ {
+ List arguments = new ArrayList();
+
+ while (true)
+ {
+ // Read an argument.
+ readNextWord("argument");
+
+ if (arguments.size() == 0 &&
+ (ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD.equals(nextWord) ||
+ ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)))
+ {
+ break;
+ }
+
+ if (checkJavaIdentifiers)
+ {
+ checkJavaIdentifier("argument type");
+ }
+
+ if (replaceSystemProperties)
+ {
+ nextWord = replaceSystemProperties(nextWord);
+ }
+
+ arguments.add(nextWord);
+
+ // Read a comma (or a closing parenthesis, or a different word).
+ readNextWord("separating '" + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD +
+ "' or closing '" + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD +
+ "'");
+
+ if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD.equals(nextWord))
+ {
+ break;
+ }
+ }
+
+ return arguments;
+ }
+
+
+ /**
+ * Throws a ParseException for an unexpected keyword.
+ */
+ private int unknownAccessFlag() throws ParseException
+ {
+ throw new ParseException("Unexpected keyword " + reader.locationDescription());
+ }
+
+
+ /**
+ * Replaces any system properties in the given word by their values
+ * (e.g. the substring "<java.home>" is replaced by its value).
+ */
+ private String replaceSystemProperties(String word)
+ throws ParseException
+ {
+ int fromIndex = 0;
+ while (true)
+ {
+ fromIndex = word.indexOf(ConfigurationConstants.OPEN_SYSTEM_PROPERTY, fromIndex);
+ if (fromIndex < 0)
+ {
+ break;
+ }
+
+ int toIndex = word.indexOf(ConfigurationConstants.CLOSE_SYSTEM_PROPERTY, fromIndex+1);
+ if (toIndex < 0)
+ {
+ throw new ParseException("Expecting closing '" + ConfigurationConstants.CLOSE_SYSTEM_PROPERTY +
+ "' after opening '" + ConfigurationConstants.OPEN_SYSTEM_PROPERTY +
+ "' in " + reader.locationDescription());
+ }
+
+ String propertyName = word.substring(fromIndex+1, toIndex);
+ String propertyValue = System.getProperty(propertyName);
+ if (propertyValue == null)
+ {
+ throw new ParseException("Value of system property '" + propertyName +
+ "' is undefined in " + reader.locationDescription());
+ }
+
+ word = word.substring(0, fromIndex) +
+ propertyValue +
+ word.substring(toIndex+1);
+ }
+
+ return word;
+ }
+
+
+ /**
+ * Reads the next word of the configuration in the 'nextWord' field,
+ * throwing an exception if there is no next word.
+ */
+ private void readNextWord(String expectedDescription)
+ throws ParseException, IOException
+ {
+ readNextWord();
+ if (configurationEnd())
+ {
+ throw new ParseException("Expecting " + expectedDescription +
+ " before " + reader.locationDescription());
+ }
+ }
+
+
+ /**
+ * Reads the next word of the configuration in the 'nextWord' field.
+ */
+ private void readNextWord()
+ throws IOException
+ {
+ nextWord = reader.nextWord();
+ }
+
+
+ /**
+ * Returns whether the end of the configuration has been reached.
+ */
+ private boolean configurationEnd()
+ {
+ return nextWord == null ||
+ nextWord.startsWith(ConfigurationConstants.OPTION_PREFIX) ||
+ nextWord.equals(ConfigurationConstants.AT_DIRECTIVE);
+ }
+
+
+ /**
+ * Checks whether the given word is a valid Java identifier and throws
+ * a ParseException if it isn't. Wildcard characters are accepted.
+ */
+ private void checkJavaIdentifier(String expectedDescription)
+ throws ParseException
+ {
+ if (!isJavaIdentifier(nextWord))
+ {
+ throw new ParseException("Expecting " + expectedDescription +
+ " before " + reader.locationDescription());
+ }
+ }
+
+
+ /**
+ * Returns whether the given word is a valid Java identifier.
+ * Wildcard characters are accepted.
+ */
+ private boolean isJavaIdentifier(String aWord)
+ {
+ for (int index = 0; index < aWord.length(); index++)
+ {
+ char c = aWord.charAt(index);
+ if (!(Character.isJavaIdentifierPart(c) ||
+ c == '.' ||
+ c == '[' ||
+ c == ']' ||
+ c == '<' ||
+ c == '>' ||
+ c == '*' ||
+ c == '?' ||
+ c == '%'))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Checks whether the given access flags are valid field access flags,
+ * throwing a ParseException if they aren't.
+ */
+ private void checkFieldAccessFlags(int requiredSetMemberAccessFlags,
+ int requiredUnsetMemberAccessFlags)
+ throws ParseException
+ {
+ if (((requiredSetMemberAccessFlags |
+ requiredUnsetMemberAccessFlags) &
+ ~ClassConstants.VALID_INTERNAL_ACC_FIELD) != 0)
+ {
+ throw new ParseException("Invalid method access modifier for field before " +
+ reader.locationDescription());
+ }
+ }
+
+
+ /**
+ * Checks whether the given access flags are valid method access flags,
+ * throwing a ParseException if they aren't.
+ */
+ private void checkMethodAccessFlags(int requiredSetMemberAccessFlags,
+ int requiredUnsetMemberAccessFlags)
+ throws ParseException
+ {
+ if (((requiredSetMemberAccessFlags |
+ requiredUnsetMemberAccessFlags) &
+ ~ClassConstants.VALID_INTERNAL_ACC_METHOD) != 0)
+ {
+ throw new ParseException("Invalid field access modifier for method before " +
+ reader.locationDescription());
+ }
+ }
+
+
+ /**
+ * A main method for testing configuration parsing.
+ */
+ public static void main(String[] args) {
+ try
+ {
+ ConfigurationParser parser = new ConfigurationParser(args);
+
+ parser.parse(new Configuration());
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/ConfigurationWriter.java b/src/proguard/ConfigurationWriter.java
new file mode 100644
index 0000000..2c3a447
--- /dev/null
+++ b/src/proguard/ConfigurationWriter.java
@@ -0,0 +1,418 @@
+/* $Id: ConfigurationWriter.java,v 1.13 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.util.*;
+
+import java.io.*;
+import java.util.*;
+
+
+/**
+ * This class writes ProGuard configurations to a file.
+ *
+ * @author Eric Lafortune
+ */
+public class ConfigurationWriter
+{
+ private static final String[] KEEP_NAMES_OPTIONS = new String[]
+ {
+ ConfigurationConstants.KEEP_NAMES_OPTION,
+ ConfigurationConstants.KEEP_CLASS_MEMBER_NAMES_OPTION,
+ ConfigurationConstants.KEEP_CLASSES_WITH_MEMBER_NAMES_OPTION
+ };
+
+ private static final String[] KEEP_OPTIONS = new String[]
+ {
+ ConfigurationConstants.KEEP_OPTION,
+ ConfigurationConstants.KEEP_CLASS_MEMBERS_OPTION,
+ ConfigurationConstants.KEEP_CLASSES_WITH_MEMBERS_OPTION
+ };
+
+ private static final String[] ASSUME_NO_SIDE_EFFECT_OPTIONS = new String[]
+ {
+ ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION,
+ ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION,
+ ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION
+ };
+
+
+ private PrintWriter writer;
+
+
+ /**
+ * Creates a new ConfigurationWriter for the given file name.
+ */
+ public ConfigurationWriter(String configurationFile) throws IOException
+ {
+ this(new PrintWriter(new FileWriter(configurationFile)));
+ }
+
+
+ /**
+ * Creates a new ConfigurationWriter for the given OutputStream.
+ */
+ public ConfigurationWriter(OutputStream outputStream) throws IOException
+ {
+ this(new PrintWriter(outputStream));
+ }
+
+
+ /**
+ * Creates a new ConfigurationWriter for the given PrintWriter.
+ */
+ public ConfigurationWriter(PrintWriter writer) throws IOException
+ {
+ this.writer = writer;
+ }
+
+
+ /**
+ * Closes this ConfigurationWriter.
+ */
+ public void close() throws IOException
+ {
+ writer.close();
+ }
+
+
+ /**
+ * Writes the given configuration.
+ * @param configuration the configuration that is to be written out.
+ * @throws IOException if an IO error occurs while writing the configuration.
+ */
+ public void write(Configuration configuration) throws IOException
+ {
+ // Write the program class path (input and output entries).
+ writeJarOptions(ConfigurationConstants.INJARS_OPTION,
+ ConfigurationConstants.OUTJARS_OPTION,
+ configuration.programJars);
+ writer.println();
+
+ // Write the library class path (output entries only).
+ writeJarOptions(ConfigurationConstants.LIBRARYJARS_OPTION,
+ ConfigurationConstants.LIBRARYJARS_OPTION,
+ configuration.libraryJars);
+ writer.println();
+
+ // Write the other options.
+ writeOption(ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION, !configuration.skipNonPublicLibraryClasses);
+ writeOption(ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION, !configuration.skipNonPublicLibraryClassMembers);
+
+ writeOption(ConfigurationConstants.DONT_SHRINK_OPTION, !configuration.shrink);
+ writeOption(ConfigurationConstants.PRINT_USAGE_OPTION, configuration.printUsage);
+
+ writeOption(ConfigurationConstants.DONT_OPTIMIZE_OPTION , !configuration.optimize);
+ writeOption(ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION, configuration.allowAccessModification);
+
+ writeOption(ConfigurationConstants.DONT_OBFUSCATE_OPTION, !configuration.obfuscate);
+ writeOption(ConfigurationConstants.PRINT_MAPPING_OPTION, configuration.printMapping);
+ writeOption(ConfigurationConstants.APPLY_MAPPING_OPTION, configuration.applyMapping);
+ writeOption(ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION, configuration.obfuscationDictionary);
+ writeOption(ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION, configuration.overloadAggressively);
+ writeOption(ConfigurationConstants.DEFAULT_PACKAGE_OPTION, configuration.defaultPackage);
+ writeOption(ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION, !configuration.useMixedCaseClassNames);
+ writeOption(ConfigurationConstants.KEEP_ATTRIBUTES_OPTION, ListUtil.commaSeparatedString(configuration.keepAttributes));
+ writeOption(ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION, configuration.newSourceFileAttribute);
+
+ writeOption(ConfigurationConstants.VERBOSE_OPTION, configuration.verbose);
+ writeOption(ConfigurationConstants.DONT_NOTE_OPTION, !configuration.note);
+ writeOption(ConfigurationConstants.DONT_WARN_OPTION, !configuration.warn);
+ writeOption(ConfigurationConstants.IGNORE_WARNINGS_OPTION, configuration.ignoreWarnings);
+
+ writeOption(ConfigurationConstants.PRINT_SEEDS_OPTION, configuration.printSeeds);
+ writer.println();
+
+ // Write the keep options.
+ writeOptions(KEEP_OPTIONS, configuration.keep);
+
+ // Write the keep names options.
+ writeOptions(KEEP_NAMES_OPTIONS, configuration.keepNames);
+
+ // Write the "no side effect methods" options.
+ writeOptions(ASSUME_NO_SIDE_EFFECT_OPTIONS, configuration.assumeNoSideEffects);
+}
+
+
+ private void writeJarOptions(String inputEntryOptionName,
+ String outputEntryOptionName,
+ ClassPath classPath)
+ {
+ if (classPath != null)
+ {
+ for (int index = 0; index < classPath.size(); index++)
+ {
+ ClassPathEntry entry = classPath.get(index);
+ String optionName = entry.isOutput() ?
+ outputEntryOptionName :
+ inputEntryOptionName;
+
+ writer.print(optionName + " " + quotedString(entry.getName()));
+
+ // Append the filters, if any.
+ boolean filtered = false;
+
+ filtered = writeFilter(filtered, entry.getZipFilter());
+ filtered = writeFilter(filtered, entry.getEarFilter());
+ filtered = writeFilter(filtered, entry.getWarFilter());
+ filtered = writeFilter(filtered, entry.getJarFilter());
+ filtered = writeFilter(filtered, entry.getFilter());
+
+ if (filtered)
+ {
+ writer.print(ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD);
+ }
+
+ writer.println();
+ }
+ }
+ }
+
+
+ private boolean writeFilter(boolean filtered, String filter)
+ {
+ if (filtered)
+ {
+ writer.print(ConfigurationConstants.SEPARATOR_KEYWORD);
+ }
+
+ if (filter != null)
+ {
+ if (!filtered)
+ {
+ writer.print(ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD);
+ }
+
+ writer.print(quotedString(filter));
+
+ filtered = true;
+ }
+
+ return filtered;
+ }
+
+
+ private void writeOption(String optionName, boolean flag)
+ {
+ if (flag)
+ {
+ writer.println(optionName);
+ }
+ }
+
+
+ private void writeOption(String optionName, String arguments)
+ {
+ if (arguments != null)
+ {
+ writer.println(optionName + " " + quotedString(arguments));
+ }
+ }
+
+
+ private void writeOptions(String[] optionNames,
+ List classSpecifications)
+ {
+ if (classSpecifications != null)
+ {
+ for (int index = 0; index < classSpecifications.size(); index++)
+ {
+ writeOption(optionNames,
+ (ClassSpecification)classSpecifications.get(index));
+ }
+ }
+ }
+
+
+ private void writeOption(String[] optionNames,
+ ClassSpecification classSpecification)
+ {
+ writer.println();
+
+ // Write out the comments for this option.
+ writeComments(classSpecification.comments);
+
+ // Write out the proper class specification option name.
+ writer.print(optionNames[classSpecification.markConditionally ? 2 :
+ classSpecification.markClassFiles ? 0 :
+ 1]);
+
+ writer.print(" ");
+
+ // Write out the class access flags.
+ writer.print(ClassUtil.externalClassAccessFlags(classSpecification.requiredUnsetAccessFlags,
+ ConfigurationConstants.NEGATOR_KEYWORD));
+
+ writer.print(ClassUtil.externalClassAccessFlags(classSpecification.requiredSetAccessFlags));
+
+ // Write out the class keyword, if we didn't write the interface
+ // keyword earlier.
+ if (((classSpecification.requiredSetAccessFlags |
+ classSpecification.requiredUnsetAccessFlags) &
+ ClassConstants.INTERNAL_ACC_INTERFACE) == 0)
+ {
+ writer.print("class");
+ }
+
+ writer.print(" ");
+
+ // Write out the class name.
+ writer.print(classSpecification.className != null ?
+ ClassUtil.externalClassName(classSpecification.className) :
+ "*");
+
+ // Write out the extends template, if any.
+ if (classSpecification.extendsClassName != null)
+ {
+ writer.print(" extends " + ClassUtil.externalClassName(classSpecification.extendsClassName));
+ }
+
+ // Write out the keep field and keep method options, if any.
+ if (classSpecification.fieldSpecifications != null ||
+ classSpecification.methodSpecifications != null)
+ {
+ writer.println(" {");
+
+ writeFieldSpecification( classSpecification.fieldSpecifications);
+ writeMethodSpecification(classSpecification.methodSpecifications,
+ classSpecification.className);
+ writer.println("}");
+ }
+ else
+ {
+ writer.println();
+ }
+ }
+
+
+
+ private void writeComments(String comments)
+ {
+ if (comments != null)
+ {
+ int index = 0;
+ while (index < comments.length())
+ {
+ int breakIndex = comments.indexOf('\n', index);
+ if (breakIndex < 0)
+ {
+ breakIndex = comments.length();
+ }
+
+ writer.print('#');
+ writer.println(comments.substring(index, breakIndex));
+
+ index = breakIndex + 1;
+ }
+ }
+ }
+
+
+ private void writeFieldSpecification(List classMemberSpecifications)
+ {
+ if (classMemberSpecifications != null)
+ {
+ for (int index = 0; index < classMemberSpecifications.size(); index++)
+ {
+ ClassMemberSpecification classMemberSpecification =
+ (ClassMemberSpecification)classMemberSpecifications.get(index);
+
+ writer.print(" ");
+
+ // Write out the field access flags.
+ writer.print(ClassUtil.externalFieldAccessFlags(classMemberSpecification.requiredUnsetAccessFlags,
+ ConfigurationConstants.NEGATOR_KEYWORD));
+
+ writer.print(ClassUtil.externalFieldAccessFlags(classMemberSpecification.requiredSetAccessFlags));
+
+ // Write out the field name and descriptor.
+ writer.print(classMemberSpecification.name != null ||
+ classMemberSpecification.descriptor != null ?
+ ClassUtil.externalFullFieldDescription(0,
+ classMemberSpecification.name,
+ classMemberSpecification.descriptor) :
+ ConfigurationConstants.ANY_FIELD_KEYWORD);
+
+ writer.println(";");
+ }
+ }
+ }
+
+
+ private void writeMethodSpecification(List classMemberSpecifications, String className)
+ {
+ if (classMemberSpecifications != null)
+ {
+ for (int index = 0; index < classMemberSpecifications.size(); index++)
+ {
+ ClassMemberSpecification classMemberSpecification =
+ (ClassMemberSpecification)classMemberSpecifications.get(index);
+
+ writer.print(" ");
+
+ // Write out the method access flags.
+ writer.print(ClassUtil.externalMethodAccessFlags(classMemberSpecification.requiredUnsetAccessFlags,
+ ConfigurationConstants.NEGATOR_KEYWORD));
+
+ writer.print(ClassUtil.externalMethodAccessFlags(classMemberSpecification.requiredSetAccessFlags));
+
+ // Write out the method name and descriptor.
+ writer.print(classMemberSpecification.name != null ||
+ classMemberSpecification.descriptor != null ?
+ ClassUtil.externalFullMethodDescription(className,
+ 0,
+ classMemberSpecification.name,
+ classMemberSpecification.descriptor) :
+ ConfigurationConstants.ANY_METHOD_KEYWORD);
+
+ writer.println(";");
+ }
+ }
+ }
+
+
+ private String quotedString(String string)
+ {
+ return
+ string.length() == 0 ||
+ string.indexOf(' ') >= 0 ? ("'" + string + "'") :
+ ( string );
+ }
+
+
+ /**
+ * A main method for testing configuration writing.
+ */
+ public static void main(String[] args) {
+ try
+ {
+ ConfigurationWriter writer = new ConfigurationWriter(args[0]);
+
+ writer.write(new Configuration());
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/DataEntryReaderFactory.java b/src/proguard/DataEntryReaderFactory.java
new file mode 100644
index 0000000..e4258d4
--- /dev/null
+++ b/src/proguard/DataEntryReaderFactory.java
@@ -0,0 +1,138 @@
+/* $Id: DataEntryReaderFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import proguard.io.*;
+import proguard.util.*;
+
+
+/**
+ * This class can create DataEntryReader instances based on class path entries.
+ * The readers will unwrap the input data entries from any jars, wars, ears,
+ * and zips, before passing them to a given reader.
+ *
+ * @author Eric Lafortune
+ */
+public class DataEntryReaderFactory
+{
+ /**
+ * Creates a DataEntryReader that can read the given class path entry.
+ *
+ * @param messagePrefix a prefix for messages that are printed out.
+ * @param classPathEntry the input class path entry.
+ * @param reader a data entry reader to which the reading of actual
+ * class files and resource files can be delegated.
+ * @return a DataEntryReader for reading the given class path entry.
+ */
+ public static DataEntryReader createDataEntryReader(String messagePrefix,
+ ClassPathEntry classPathEntry,
+ DataEntryReader reader)
+ {
+ String entryName = classPathEntry.getName();
+ boolean isJar = entryName.endsWith(".jar");
+ boolean isWar = entryName.endsWith(".war");
+ boolean isEar = entryName.endsWith(".ear");
+ boolean isZip = entryName.endsWith(".zip");
+
+ String filter = classPathEntry.getFilter();
+ String jarFilter = classPathEntry.getJarFilter();
+ String warFilter = classPathEntry.getWarFilter();
+ String earFilter = classPathEntry.getEarFilter();
+ String zipFilter = classPathEntry.getZipFilter();
+
+ System.out.println(messagePrefix +
+ (isJar ? "jar" :
+ isWar ? "war" :
+ isEar ? "ear" :
+ isZip ? "zip" :
+ "directory") +
+ " [" + classPathEntry.getName() + "]" +
+ (filter != null ||
+ jarFilter != null ||
+ warFilter != null ||
+ earFilter != null ||
+ zipFilter != null ? " (filtered)" : ""));
+
+ // Add a filter, if specified.
+ if (filter != null)
+ {
+ reader = new FilteredDataEntryReader(new DataEntryNameFilter(new FileNameListMatcher(filter)),
+ reader);
+ }
+
+ // Unzip any jars, if necessary.
+ reader = wrapInJarReader(reader, isJar, jarFilter, ".jar");
+ if (!isJar)
+ {
+ // Unzip any wars, if necessary.
+ reader = wrapInJarReader(reader, isWar, warFilter, ".war");
+ if (!isWar)
+ {
+ // Unzip any ears, if necessary.
+ reader = wrapInJarReader(reader, isEar, earFilter, ".ear");
+ if (!isEar)
+ {
+ // Unzip any zips, if necessary.
+ reader = wrapInJarReader(reader, isZip, zipFilter, ".zip");
+ }
+ }
+ }
+
+ return reader;
+ }
+
+
+ /**
+ * Wraps the given DataEntryReader in a JarReader, filtering it if necessary.
+ */
+ private static DataEntryReader wrapInJarReader(DataEntryReader reader,
+ boolean isJar,
+ String jarFilter,
+ String jarExtension)
+ {
+ // Unzip any jars, if necessary.
+ DataEntryReader jarReader = new JarReader(reader);
+
+ if (isJar)
+ {
+ // Always unzip.
+ return jarReader;
+ }
+ else
+ {
+ // Add a filter, if specified.
+ if (jarFilter != null)
+ {
+ jarReader = new FilteredDataEntryReader(
+ new DataEntryNameFilter(
+ new FileNameListMatcher(jarFilter)),
+ jarReader);
+ }
+
+ // Only unzip the right type of jars.
+ return new FilteredDataEntryReader(
+ new DataEntryNameFilter(
+ new ExtensionMatcher(jarExtension)),
+ jarReader,
+ reader);
+ }
+ }
+}
diff --git a/src/proguard/DataEntryWriterFactory.java b/src/proguard/DataEntryWriterFactory.java
new file mode 100644
index 0000000..318afe7
--- /dev/null
+++ b/src/proguard/DataEntryWriterFactory.java
@@ -0,0 +1,152 @@
+/* $Id: DataEntryWriterFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import proguard.io.*;
+import proguard.util.*;
+
+import java.io.*;
+
+
+/**
+ * This class can create DataEntryWriter instances based on class paths. The
+ * writers will wrap the output in the proper jars, wars, ears, and zips.
+ *
+ * @author Eric Lafortune
+ */
+public class DataEntryWriterFactory
+{
+ /**
+ * Creates a DataEntryWriter that can write to the given class path entries.
+ *
+ * @param classPath the output class path.
+ * @param fromIndex the start index in the class path.
+ * @param toIndex the end index in the class path.
+ * @return a DataEntryWriter for writing to the given class path entries.
+ */
+ public static DataEntryWriter createDataEntryWriter(ClassPath classPath,
+ int fromIndex,
+ int toIndex)
+ {
+ DataEntryWriter writer = null;
+
+ // Create a chain of writers, one for each class path entry.
+ for (int index = toIndex - 1; index >= fromIndex; index--)
+ {
+ ClassPathEntry entry = classPath.get(index);
+ writer = createClassPathEntryWriter(entry, writer);
+ }
+
+ return writer;
+ }
+
+
+ /**
+ * Creates a DataEntryWriter that can write to the given class path entry,
+ * or delegate to another DataEntryWriter if its filters don't match.
+ */
+ private static DataEntryWriter createClassPathEntryWriter(ClassPathEntry classPathEntry,
+ DataEntryWriter alternativeWriter)
+ {
+ String entryName = classPathEntry.getName();
+ boolean isJar = entryName.endsWith(".jar");
+ boolean isWar = entryName.endsWith(".war");
+ boolean isEar = entryName.endsWith(".ear");
+ boolean isZip = entryName.endsWith(".zip");
+
+ String filter = classPathEntry.getFilter();
+ String jarFilter = classPathEntry.getJarFilter();
+ String warFilter = classPathEntry.getWarFilter();
+ String earFilter = classPathEntry.getEarFilter();
+ String zipFilter = classPathEntry.getZipFilter();
+
+ System.out.println("Preparing output " +
+ (isJar ? "jar" :
+ isWar ? "war" :
+ isWar ? "ear" :
+ isZip ? "zip" :
+ "directory") +
+ " [" + classPathEntry.getName() + "]" +
+ (filter != null ||
+ jarFilter != null ||
+ warFilter != null ||
+ earFilter != null ||
+ zipFilter != null ? " (filtered)" : ""));
+
+ DataEntryWriter writer = new DirectoryWriter(new File(entryName),
+ isJar ||
+ isWar ||
+ isEar ||
+ isZip);
+
+ // Set up the filtered jar writers.
+ writer = wrapInJarWriter(writer, isZip, zipFilter, ".zip", isJar || isWar || isEar);
+ writer = wrapInJarWriter(writer, isEar, earFilter, ".ear", isJar || isWar);
+ writer = wrapInJarWriter(writer, isWar, warFilter, ".war", isJar);
+ writer = wrapInJarWriter(writer, isJar, jarFilter, ".jar", false);
+
+ // Add a filter, if specified.
+ writer = filter != null?
+ new FilteredDataEntryWriter(
+ new DataEntryNameFilter(
+ new FileNameListMatcher(filter)),
+ writer) :
+ writer;
+
+ // Let the writer cascade, if specified.
+ return alternativeWriter != null ?
+ new CascadingDataEntryWriter(writer, alternativeWriter) :
+ writer;
+ }
+
+
+ /**
+ * Wraps the given DataEntryWriter in a JarWriter, filtering if necessary.
+ */
+ private static DataEntryWriter wrapInJarWriter(DataEntryWriter writer,
+ boolean isJar,
+ String jarFilter,
+ String jarExtension,
+ boolean dontWrap)
+ {
+ // Zip up jars, if necessary.
+ DataEntryWriter jarWriter = dontWrap ?
+ (DataEntryWriter)new ParentDataEntryWriter(writer) :
+ (DataEntryWriter)new JarWriter(writer, null, ProGuard.VERSION);
+
+ // Add a filter, if specified.
+ DataEntryWriter filteredJarWriter = jarFilter != null?
+ new FilteredDataEntryWriter(
+ new DataEntryParentFilter(
+ new DataEntryNameFilter(
+ new FileNameListMatcher(jarFilter))),
+ jarWriter) :
+ jarWriter;
+
+ // Only zip up jars, unless the output is a jar file itself.
+ return new FilteredDataEntryWriter(
+ new DataEntryParentFilter(
+ new DataEntryNameFilter(
+ new ExtensionMatcher(jarExtension))),
+ filteredJarWriter,
+ isJar ? jarWriter : writer);
+ }
+}
diff --git a/src/proguard/FileWordReader.java b/src/proguard/FileWordReader.java
new file mode 100644
index 0000000..6e2a5c6
--- /dev/null
+++ b/src/proguard/FileWordReader.java
@@ -0,0 +1,87 @@
+/* $Id: FileWordReader.java,v 1.9 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import java.io.*;
+import java.net.URL;
+
+
+/**
+ * A <code>WordReader</code> that returns words from a file or a URL.
+ *
+ * @author Eric Lafortune
+ */
+public class FileWordReader extends WordReader
+{
+ private String fileName;
+ private LineNumberReader reader;
+
+
+ /**
+ * Creates a new FileWordReader for the given file name.
+ */
+ public FileWordReader(String fileName) throws IOException
+ {
+ this.fileName = fileName;
+ this.reader = new LineNumberReader(
+ new BufferedReader(
+ new FileReader(fileName)));
+ }
+
+
+ /**
+ * Creates a new FileWordReader for the given URL.
+ */
+ public FileWordReader(URL url) throws IOException
+ {
+ this.fileName = url.getPath();
+ this.reader = new LineNumberReader(
+ new BufferedReader(
+ new InputStreamReader(
+ url.openStream())));
+ }
+
+
+ /**
+ * Closes the FileWordReader.
+ */
+ public void close() throws IOException
+ {
+ if (reader != null)
+ {
+ reader.close();
+ }
+ }
+
+
+ // Implementations for WordReader.
+
+ protected String nextLine() throws IOException
+ {
+ return reader.readLine();
+ }
+
+
+ protected String lineLocationDescription()
+ {
+ return "line " + reader.getLineNumber() + " of file '" + fileName + "'";
+ }
+}
diff --git a/src/proguard/ParseException.java b/src/proguard/ParseException.java
new file mode 100644
index 0000000..82e61a3
--- /dev/null
+++ b/src/proguard/ParseException.java
@@ -0,0 +1,51 @@
+/* $Id: ParseException.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+
+/**
+ * This <code>Exception</code> signals that a parse exception of some
+ * sort has occurred.
+ *
+ * @author Eric Lafortune
+ */
+public class ParseException extends Exception {
+
+ /**
+ * Constructs a <code>ParseException</code> with <code>null</code>
+ * as its error detail message.
+ */
+ public ParseException() {
+ super();
+ }
+
+ /**
+ * Constructs a <code>ParseException</code> with the specified detail
+ * message. The error message string <code>s</code> can later be
+ * retrieved by the <code>{@link java.lang.Throwable#getMessage}</code>
+ * method of class <code>java.lang.Throwable</code>.
+ *
+ * @param s the detail message.
+ */
+ public ParseException(String s) {
+ super(s);
+ }
+}
diff --git a/src/proguard/ProGuard.java b/src/proguard/ProGuard.java
new file mode 100644
index 0000000..33d76b3
--- /dev/null
+++ b/src/proguard/ProGuard.java
@@ -0,0 +1,936 @@
+/* $Id: ProGuard.java,v 1.84 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.io.*;
+import proguard.obfuscate.*;
+import proguard.optimize.*;
+import proguard.optimize.evaluation.*;
+import proguard.optimize.peephole.*;
+import proguard.shrink.*;
+
+import java.io.*;
+
+
+/**
+ * Tool for shrinking, optimizing, and obfuscating Java class files.
+ *
+ * @author Eric Lafortune
+ */
+public class ProGuard
+{
+ public static final String VERSION = "ProGuard, version 3.2";
+
+ private Configuration configuration;
+ private ClassPool programClassPool = new ClassPool();
+ private ClassPool libraryClassPool = new ClassPool();
+
+
+ /**
+ * Creates a new ProGuard object to process jars as specified by the given
+ * configuration.
+ */
+ public ProGuard(Configuration configuration)
+ {
+ this.configuration = configuration;
+ }
+
+
+ /**
+ * Performs all subsequent ProGuard operations.
+ */
+ public void execute() throws IOException
+ {
+ System.out.println(VERSION);
+
+ readInput();
+
+ if (configuration.shrink ||
+ configuration.optimize ||
+ configuration.obfuscate)
+ {
+ initialize();
+ }
+
+ if (configuration.printSeeds != null)
+ {
+ printSeeds();
+ }
+
+ if (configuration.shrink)
+ {
+ shrink();
+ }
+
+ if (configuration.optimize)
+ {
+ optimize();
+
+ // Shrink again, if we may.
+ if (configuration.shrink)
+ {
+ configuration.printUsage = null;
+
+ shrink();
+ }
+ }
+
+ if (configuration.obfuscate)
+ {
+ obfuscate();
+ }
+
+ if (configuration.shrink ||
+ configuration.optimize ||
+ configuration.obfuscate)
+ {
+ sortConstantPools();
+ }
+
+ if (configuration.programJars.hasOutput())
+ {
+ writeOutput();
+ }
+
+ if (configuration.dump != null)
+ {
+ dump();
+ }
+ }
+
+
+ /**
+ * Reads the input jars (or directories).
+ */
+ private void readInput() throws IOException
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Reading jars...");
+ }
+
+ // Check if we have at least some program jars.
+ if (configuration.programJars == null)
+ {
+ throw new IOException("The input is empty. You have to specify one or more '-injars' options.");
+ }
+
+ // Read the input program jars.
+ readInput("Reading program ",
+ configuration.programJars,
+ createDataEntryClassPoolFiller(false));
+
+ // Check if we have at least some input class files.
+ if (programClassPool.size() == 0)
+ {
+ throw new IOException("The input doesn't contain any class files. Did you specify the proper '-injars' options?");
+ }
+
+ // Read all library jars.
+ if (configuration.libraryJars != null)
+ {
+ readInput("Reading library ",
+ configuration.libraryJars,
+ createDataEntryClassPoolFiller(true));
+ }
+
+ // The defaultPackage option implies the allowAccessModification option.
+ if (configuration.defaultPackage != null)
+ {
+ configuration.allowAccessModification = true;
+ }
+ }
+
+
+ /**
+ * Creates a DataEntryReader that will decode class files and put them in
+ * the proper class pool.
+ */
+ private DataEntryReader createDataEntryClassPoolFiller(boolean isLibrary)
+ {
+ // Get the proper class pool.
+ ClassPool classPool = isLibrary ?
+ libraryClassPool :
+ programClassPool;
+
+ // Prepare a data entry reader to filter all class files,
+ // which are then decoded to class files by a class file reader,
+ // which are then put in the class pool by a class pool filler.
+ return
+ new ClassFileFilter(
+ new ClassFileReader(isLibrary,
+ configuration.skipNonPublicLibraryClasses,
+ configuration.skipNonPublicLibraryClassMembers,
+ new ClassPoolFiller(classPool, configuration.note)));
+ }
+
+
+ /**
+ * Reads all input entries from the given class path.
+ */
+ private void readInput(String messagePrefix,
+ ClassPath classPath,
+ DataEntryReader reader) throws IOException
+ {
+ readInput(messagePrefix,
+ classPath,
+ 0,
+ classPath.size(),
+ reader);
+ }
+
+
+ /**
+ * Reads all input entries from the given section of the given class path.
+ */
+ private void readInput(String messagePrefix,
+ ClassPath classPath,
+ int fromIndex,
+ int toIndex,
+ DataEntryReader reader) throws IOException
+ {
+ for (int index = fromIndex; index < toIndex; index++)
+ {
+ ClassPathEntry entry = classPath.get(index);
+ if (!entry.isOutput())
+ {
+ readInput(messagePrefix, entry, reader);
+ }
+ }
+ }
+
+
+ /**
+ * Reads the given input class path entry.
+ */
+ private void readInput(String messagePrefix,
+ ClassPathEntry classPathEntry,
+ DataEntryReader dataEntryReader) throws IOException
+ {
+ try
+ {
+ // Create a reader that can unwrap jars, wars, ears, and zips.
+ DataEntryReader reader =
+ DataEntryReaderFactory.createDataEntryReader(messagePrefix,
+ classPathEntry,
+ dataEntryReader);
+
+ // Create the data entry pump.
+ DirectoryPump directoryPump =
+ new DirectoryPump(new File(classPathEntry.getName()));
+
+ // Pump the data entries into the reader.
+ directoryPump.pumpDataEntries(reader);
+ }
+ catch (IOException ex)
+ {
+ throw new IOException("Can't read [" + classPathEntry + "] (" + ex.getMessage() + ")");
+ }
+ }
+
+
+ /**
+ * Initializes the cross-references between all class files.
+ */
+ private void initialize() throws IOException
+ {
+ // Initialize the class hierarchy for program class files.
+ ClassFileHierarchyInitializer classFileHierarchyInitializer =
+ new ClassFileHierarchyInitializer(programClassPool,
+ libraryClassPool,
+ configuration.warn);
+
+ programClassPool.classFilesAccept(classFileHierarchyInitializer);
+
+ // Initialize the rest of the class hierarchy.
+ ClassFileHierarchyInitializer classFileHierarchyInitializer2 =
+ new ClassFileHierarchyInitializer(programClassPool,
+ libraryClassPool,
+ false);
+
+ libraryClassPool.classFilesAccept(classFileHierarchyInitializer2);
+
+ // Initialize the other class references.
+ ClassFileReferenceInitializer classFileReferenceInitializer =
+ new ClassFileReferenceInitializer(programClassPool,
+ libraryClassPool,
+ configuration.warn,
+ configuration.note);
+
+ programClassPool.classFilesAccept(classFileReferenceInitializer);
+
+ int noteCount = classFileReferenceInitializer.getNoteCount();
+ if (noteCount > 0)
+ {
+ System.err.println("Note: there were " + noteCount +
+ " class casts of dynamically created class instances.");
+ System.err.println(" You might consider explicitly keeping the mentioned classes and/or");
+ System.err.println(" their implementations (using '-keep').");
+ }
+
+ int hierarchyWarningCount = classFileHierarchyInitializer.getWarningCount();
+ if (hierarchyWarningCount > 0)
+ {
+ System.err.println("Warning: there were " + hierarchyWarningCount +
+ " unresolved references to superclasses or interfaces.");
+ System.err.println(" You may need to specify additional library jars (using '-libraryjars'),");
+ System.err.println(" or perhaps the '-dontskipnonpubliclibraryclasses' option.");
+ }
+
+ int referenceWarningCount = classFileReferenceInitializer.getWarningCount();
+ if (referenceWarningCount > 0)
+ {
+ System.err.println("Warning: there were " + referenceWarningCount +
+ " unresolved references to program class members.");
+ System.err.println(" Your input class files appear to be inconsistent.");
+ System.err.println(" You may need to recompile them and try again.");
+ }
+
+ if ((hierarchyWarningCount > 0 ||
+ referenceWarningCount > 0) &&
+ !configuration.ignoreWarnings)
+ {
+ System.err.println(" If you are sure the mentioned classes are not used anyway,");
+ System.err.println(" you could try your luck using the '-ignorewarnings' option.");
+ throw new IOException("Please correct the above warnings first.");
+ }
+
+ // Discard unused library classes.
+ if (configuration.verbose)
+ {
+ System.out.println("Removing unused library classes...");
+ System.out.println(" Original number of library classes: " + libraryClassPool.size());
+ }
+
+ // Reinitialize the library class pool with only those library classes
+ // whose hierarchies are referenced by the program classes.
+ ClassPool newLibraryClassPool = new ClassPool();
+ programClassPool.classFilesAccept(
+ new AllCpInfoVisitor(
+ new ReferencedClassFileVisitor(
+ new LibraryClassFileFilter(
+ new ClassFileHierarchyTraveler(true, true, true, false,
+ new LibraryClassFileFilter(
+ new ClassPoolFiller(newLibraryClassPool, false)))))));
+
+ libraryClassPool = newLibraryClassPool;
+
+ if (configuration.verbose)
+ {
+ System.out.println(" Final number of library classes: " + libraryClassPool.size());
+ }
+ }
+
+
+ /**
+ * Prints out classes and class members that are used as seeds in the
+ * shrinking and obfuscation steps.
+ */
+ private void printSeeds() throws IOException
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Printing kept classes, fields, and methods...");
+ }
+
+ // Check if we have at least some keep commands.
+ if (configuration.keep == null)
+ {
+ throw new IOException("You have to specify '-keep' options for the shrinking step.");
+ }
+
+ PrintStream ps = configuration.printSeeds.length() > 0 ?
+ new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printSeeds))) :
+ System.out;
+
+ // Create a visitor for printing out the seeds. Note that we're only
+ // printing out the program elements that are preserved against shrinking.
+ SimpleClassFilePrinter printer = new SimpleClassFilePrinter(false, ps);
+ ClassPoolVisitor classPoolvisitor =
+ ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
+ new ProgramClassFileFilter(printer),
+ new ProgramMemberInfoFilter(printer));
+
+ // Print out the seeds.
+ programClassPool.accept(classPoolvisitor);
+ libraryClassPool.accept(classPoolvisitor);
+
+ if (ps != System.out)
+ {
+ ps.close();
+ }
+ }
+
+
+ /**
+ * Performs the shrinking step.
+ */
+ private void shrink() throws IOException
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Shrinking...");
+ }
+
+ // Check if we have at least some keep commands.
+ if (configuration.keep == null)
+ {
+ throw new IOException("You have to specify '-keep' options for the shrinking step.");
+ }
+
+ // Clean up any old visitor info.
+ ClassFileCleaner classFileCleaner = new ClassFileCleaner();
+ programClassPool.classFilesAccept(classFileCleaner);
+ libraryClassPool.classFilesAccept(classFileCleaner);
+
+ // Create a visitor for marking the seeds.
+ UsageMarker usageMarker = new UsageMarker();
+ ClassPoolVisitor classPoolvisitor =
+ ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
+ usageMarker,
+ usageMarker);
+ // Mark the seeds.
+ programClassPool.accept(classPoolvisitor);
+ libraryClassPool.accept(classPoolvisitor);
+
+ // Mark interfaces that have to be kept.
+ programClassPool.classFilesAccept(new InterfaceUsageMarker());
+
+ // Mark the inner class information that has to be kept.
+ programClassPool.classFilesAccept(new InnerUsageMarker());
+
+ if (configuration.printUsage != null)
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Printing usage" +
+ (configuration.printUsage.length() > 0 ?
+ " to [" + configuration.printUsage + "]" :
+ "..."));
+ }
+
+ PrintStream ps = configuration.printUsage.length() > 0 ?
+ new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printUsage))) :
+ System.out;
+
+ // Print out items that will be removed.
+ programClassPool.classFilesAcceptAlphabetically(new UsagePrinter(true, ps));
+
+ if (ps != System.out)
+ {
+ ps.close();
+ }
+ }
+
+ // Discard unused program classes.
+ if (configuration.verbose)
+ {
+ System.out.println("Removing unused program classes and class elements...");
+ System.out.println(" Original number of program classes: " + programClassPool.size());
+ }
+
+ ClassPool newProgramClassPool = new ClassPool();
+ programClassPool.classFilesAccept(
+ new UsedClassFileFilter(
+ new MultiClassFileVisitor(
+ new ClassFileVisitor[] {
+ new ClassFileShrinker(1024),
+ new ClassPoolFiller(newProgramClassPool, false)
+ })));
+ programClassPool = newProgramClassPool;
+
+ if (configuration.verbose)
+ {
+ System.out.println(" Final number of program classes: " + programClassPool.size());
+ }
+
+ // Check if we have at least some output class files.
+ if (programClassPool.size() == 0)
+ {
+ throw new IOException("The output jar is empty. Did you specify the proper '-keep' options?");
+ }
+ }
+
+
+ /**
+ * Performs the optimization step.
+ */
+ private void optimize() throws IOException
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Optimizing...");
+ }
+
+ // Clean up any old visitor info.
+ ClassFileCleaner classFileCleaner = new ClassFileCleaner();
+ programClassPool.classFilesAccept(classFileCleaner);
+ libraryClassPool.classFilesAccept(classFileCleaner);
+
+ // Check if we have at least some keep commands.
+ if (configuration.keep == null)
+ {
+ throw new IOException("You have to specify '-keep' options for the optimization step.");
+ }
+
+ // Create a visitor for marking the seeds.
+ KeepMarker keepMarker = new KeepMarker();
+ ClassPoolVisitor classPoolvisitor =
+ ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
+ keepMarker,
+ keepMarker);
+
+ // Mark the seeds.
+ programClassPool.accept(classPoolvisitor);
+ libraryClassPool.accept(classPoolvisitor);
+
+ // Make class files and methods final, as far as possible.
+ programClassPool.classFilesAccept(new ClassFileFinalizer());
+
+ // Mark all fields that are write-only.
+ programClassPool.classFilesAccept(
+ new AllMethodVisitor(
+ new AllAttrInfoVisitor(
+ new AllInstructionVisitor(
+ new WriteOnlyFieldMarker()))));
+
+ if (configuration.assumeNoSideEffects != null)
+ {
+ // Create a visitor for marking methods that don't have any side effects.
+ NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker();
+ ClassPoolVisitor noClassPoolvisitor =
+ ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.assumeNoSideEffects,
+ null,
+ noSideEffectMethodMarker);
+
+ // Mark the seeds.
+ programClassPool.accept(noClassPoolvisitor);
+ libraryClassPool.accept(noClassPoolvisitor);
+ }
+
+ // Mark all methods that have side effects.
+ programClassPool.accept(new SideEffectMethodMarker());
+
+ // Mark all interfaces that have single implementations.
+ programClassPool.classFilesAccept(new SingleImplementationMarker(configuration.allowAccessModification));
+
+ // Inline interfaces with single implementations.
+ // First update the references to classes and class members.
+ // Then update the class member descriptors.
+ programClassPool.classFilesAccept(new AllMethodVisitor(
+ new AllAttrInfoVisitor(
+ new SingleImplementationInliner())));
+ programClassPool.classFilesAccept(new AllMemberInfoVisitor(
+ new SingleImplementationInliner()));
+
+ // Perform partial evaluation.
+ programClassPool.classFilesAccept(new AllMethodVisitor(
+ new PartialEvaluator()));
+
+ // Create a branch target marker and a code attribute editor that can
+ // be reused for all code attributes.
+ BranchTargetFinder branchTargetFinder = new BranchTargetFinder(1024);
+ CodeAttrInfoEditor codeAttrInfoEditor = new CodeAttrInfoEditor(1024);
+
+ // Visit all code attributes.
+ // First let the branch marker mark all branch targets.
+ // Then perform peephole optimisations on the instructions:
+ // - Remove push/pop instruction pairs.
+ // - Remove load/store instruction pairs.
+ // - Replace store/load instruction pairs by dup/store instructions.
+ // - Replace branches to return instructions by return instructions.
+ // - Remove nop instructions.
+ // - Inline simple getters and setters.
+ // Finally apply all changes to the code.
+ programClassPool.classFilesAccept(
+ new AllMethodVisitor(
+ new AllAttrInfoVisitor(
+ new MultiAttrInfoVisitor(
+ new AttrInfoVisitor[]
+ {
+ branchTargetFinder,
+ new CodeAttrInfoEditorResetter(codeAttrInfoEditor),
+ new AllInstructionVisitor(
+ new MultiInstructionVisitor(
+ new InstructionVisitor[]
+ {
+ new PushPopRemover(branchTargetFinder, codeAttrInfoEditor),
+ new LoadStoreRemover(branchTargetFinder, codeAttrInfoEditor),
+ new StoreLoadReplacer(branchTargetFinder, codeAttrInfoEditor),
+ new GotoReturnReplacer(codeAttrInfoEditor),
+ new NopRemover(codeAttrInfoEditor),
+ new GetterSetterInliner(codeAttrInfoEditor, configuration.allowAccessModification),
+ })),
+ codeAttrInfoEditor
+ }))));
+ }
+
+
+ /**
+ * Performs the obfuscation step.
+ */
+ private void obfuscate() throws IOException
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Obfuscating...");
+ }
+
+ // Check if we have at least some keep commands.
+ if (configuration.keep == null &&
+ configuration.keepNames == null)
+ {
+ throw new IOException("You have to specify '-keep' options for the obfuscation step.");
+ }
+
+ // Clean up any old visitor info.
+ ClassFileCleaner classFileCleaner = new ClassFileCleaner();
+ programClassPool.classFilesAccept(classFileCleaner);
+ libraryClassPool.classFilesAccept(classFileCleaner);
+
+ // Link all class members that should get the same names.
+ programClassPool.classFilesAccept(new BottomClassFileFilter(
+ new MemberInfoLinker()));
+
+ // Create a visitor for marking the seeds.
+ NameMarker nameMarker = new NameMarker();
+ ClassPoolVisitor classPoolvisitor =
+ new MultiClassPoolVisitor(new ClassPoolVisitor[]
+ {
+ ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
+ nameMarker,
+ nameMarker),
+ ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keepNames,
+ nameMarker,
+ nameMarker)
+ });
+
+ // Mark the seeds.
+ programClassPool.accept(classPoolvisitor);
+ libraryClassPool.accept(classPoolvisitor);
+
+ // Apply the mapping, if one has been specified.
+ if (configuration.applyMapping != null)
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Applying mapping [" + configuration.applyMapping + "]");
+ }
+
+ MappingReader reader = new MappingReader(configuration.applyMapping);
+ MappingProcessor keeper =
+ new MultiMappingProcessor(new MappingProcessor[]
+ {
+ new MappingKeeper(programClassPool),
+ new MappingKeeper(libraryClassPool),
+ });
+
+ reader.pump(keeper);
+ }
+
+ // Mark attributes that have to be kept.
+ AttributeUsageMarker attributeUsageMarker = new AttributeUsageMarker();
+ if (configuration.keepAttributes != null)
+ {
+ if (configuration.keepAttributes.size() != 0)
+ {
+ attributeUsageMarker.setKeepAttributes(configuration.keepAttributes);
+ }
+ else
+ {
+ attributeUsageMarker.setKeepAllAttributes();
+ }
+ }
+ programClassPool.classFilesAccept(attributeUsageMarker);
+
+ // Remove the attributes that can be discarded.
+ programClassPool.classFilesAccept(new AttributeShrinker());
+
+ if (configuration.verbose)
+ {
+ System.out.println("Renaming program classes and class elements...");
+ }
+
+ // Come up with new names for all class files.
+ programClassPool.classFilesAccept(new ClassFileObfuscator(programClassPool,
+ configuration.defaultPackage,
+ configuration.useMixedCaseClassNames));
+
+ // Come up with new names for all class members.
+ programClassPool.classFilesAccept(new BottomClassFileFilter(
+ new MemberInfoObfuscator(configuration.overloadAggressively,
+ configuration.obfuscationDictionary)));
+
+ // Print out the mapping, if requested.
+ if (configuration.printMapping != null)
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Printing mapping" +
+ (configuration.printMapping.length() > 0 ?
+ " to [" + configuration.printMapping + "]" :
+ "..."));
+ }
+
+ PrintStream ps = configuration.printMapping.length() > 0 ?
+ new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printMapping))) :
+ System.out;
+
+ // Print out items that will be removed.
+ programClassPool.classFilesAcceptAlphabetically(new MappingPrinter(ps));
+
+ if (ps != System.out)
+ {
+ ps.close();
+ }
+ }
+
+ // Actually apply these new names.
+ programClassPool.classFilesAccept(new ClassFileRenamer(configuration.defaultPackage != null,
+ configuration.newSourceFileAttribute));
+
+ // Mark NameAndType constant pool entries that have to be kept
+ // and remove the other ones.
+ programClassPool.classFilesAccept(new NameAndTypeUsageMarker());
+ programClassPool.classFilesAccept(new NameAndTypeShrinker(1024));
+
+ // Mark Utf8 constant pool entries that have to be kept
+ // and remove the other ones.
+ programClassPool.classFilesAccept(new Utf8UsageMarker());
+ programClassPool.classFilesAccept(new Utf8Shrinker(1024));
+ }
+
+
+ /**
+ * Sorts the constant pools of all program class files.
+ */
+ private void sortConstantPools()
+ {
+ programClassPool.classFilesAccept(new ConstantPoolSorter(1024));
+ }
+
+
+ /**
+ * Writes the output jars.
+ */
+ private void writeOutput() throws IOException
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Writing jars...");
+ }
+
+ ClassPath programJars = configuration.programJars;
+
+ // Perform a check on the first jar.
+ ClassPathEntry firstEntry = programJars.get(0);
+ if (firstEntry.isOutput())
+ {
+ throw new IOException("The output jar [" + firstEntry.getName() +
+ "] must be specified after an input jar, or it will be empty.");
+ }
+
+ // Perform some checks on the output jars.
+ for (int index = 0; index < programJars.size() - 1; index++)
+ {
+ ClassPathEntry entry = programJars.get(index);
+ if (entry.isOutput())
+ {
+ // Check if all but the last output jars have filters.
+ if (entry.getFilter() == null &&
+ entry.getJarFilter() == null &&
+ entry.getWarFilter() == null &&
+ entry.getEarFilter() == null &&
+ entry.getZipFilter() == null &&
+ programJars.get(index + 1).isOutput())
+ {
+ throw new IOException("The output jar [" + entry.getName() +
+ "] must have a filter, or all subsequent jars will be empty.");
+ }
+
+ // Check if the output jar name is different from the input jar names.
+ for (int inIndex = 0; inIndex < programJars.size(); inIndex++)
+ {
+ ClassPathEntry otherEntry = programJars.get(inIndex);
+
+ if (!otherEntry.isOutput() &&
+ entry.getName().equals(otherEntry.getName()))
+ {
+ throw new IOException("The output jar [" + entry.getName() +
+ "] must be different from all input jars.");
+ }
+ }
+ }
+ }
+
+ int firstInputIndex = 0;
+ int lastInputIndex = 0;
+
+ // Go over all program class path entries.
+ for (int index = 0; index < programJars.size(); index++)
+ {
+ // Is it an input entry?
+ ClassPathEntry entry = programJars.get(index);
+ if (!entry.isOutput())
+ {
+ // Remember the index of the last input entry.
+ lastInputIndex = index;
+ }
+ else
+ {
+ // Check if this the last output entry in a series.
+ int nextIndex = index + 1;
+ if (nextIndex == programJars.size() ||
+ !programJars.get(nextIndex).isOutput())
+ {
+ // Write the processed input entries to the output entries.
+ writeOutput(programJars,
+ firstInputIndex,
+ lastInputIndex + 1,
+ nextIndex);
+
+ // Start with the next series of input entries.
+ firstInputIndex = nextIndex;
+ }
+ }
+ }
+ }
+
+
+
+
+ /**
+ * Transfers the specified input jars to the specified output jars.
+ */
+ private void writeOutput(ClassPath classPath,
+ int fromInputIndex,
+ int fromOutputIndex,
+ int toOutputIndex)
+ throws IOException
+ {
+ try
+ {
+ // Construct the writer that can write jars, wars, ears, zips, and
+ // directories, cascading over the specified output entries.
+ DataEntryWriter writer =
+ DataEntryWriterFactory.createDataEntryWriter(classPath,
+ fromOutputIndex,
+ toOutputIndex);
+
+ // Create the reader that can write class files and copy resource
+ // files to the above writer.
+ DataEntryReader reader =
+ new ClassFileFilter(new ClassFileRewriter(programClassPool,
+ writer),
+ new DataEntryCopier(writer));
+
+ // Read and handle the specified input entries.
+ readInput("Copying resources from program ",
+ classPath,
+ fromInputIndex,
+ fromOutputIndex,
+ reader);
+
+ // Close all output entries.
+ writer.close();
+ }
+ catch (IOException ex)
+ {
+ throw new IOException("Can't write [" + classPath.get(fromOutputIndex).getName() + "] (" + ex.getMessage() + ")");
+ }
+ }
+
+
+ /**
+ * Prints out the contents of the program class files.
+ */
+ private void dump() throws IOException
+ {
+ if (configuration.verbose)
+ {
+ System.out.println("Printing classes" +
+ (configuration.dump.length() > 0 ?
+ " to [" + configuration.dump + "]" :
+ "..."));
+ }
+
+ PrintStream ps = configuration.dump.length() > 0 ?
+ new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.dump))) :
+ System.out;
+
+ programClassPool.classFilesAccept(new ClassFilePrinter(ps));
+
+ if (configuration.dump.length() > 0)
+ {
+ ps.close();
+ }
+ }
+
+
+ /**
+ * The main method for ProGuard.
+ */
+ public static void main(String[] args)
+ {
+ if (args.length == 0)
+ {
+ System.out.println("Usage: java proguard.ProGuard [options ...]");
+ System.exit(1);
+ }
+
+ // Create the default options.
+ Configuration configuration = new Configuration();
+
+ try
+ {
+ // Parse the options specified in the command line arguments.
+ ConfigurationParser parser = new ConfigurationParser(args);
+ parser.parse(configuration);
+
+ // Execute ProGuard with these options.
+ ProGuard proGuard = new ProGuard(configuration);
+ proGuard.execute();
+ }
+ catch (Exception ex)
+ {
+ if (configuration.verbose)
+ {
+ // Print a verbose stack trace.
+ ex.printStackTrace();
+ }
+ else
+ {
+ // Print just the stack trace message.
+ System.err.println("Error: "+ex.getMessage());
+ }
+
+ System.exit(1);
+ }
+
+ System.exit(0);
+ }
+}
diff --git a/src/proguard/SubclassedClassFileFilter.java b/src/proguard/SubclassedClassFileFilter.java
new file mode 100644
index 0000000..128bd84
--- /dev/null
+++ b/src/proguard/SubclassedClassFileFilter.java
@@ -0,0 +1,63 @@
+/* $Id: SubclassedClassFileFilter.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor delegates all its method calls to another
+ * ClassFileVisitor, but only for ClassFile objects that are being subclassed.
+ *
+ * @author Eric Lafortune
+ */
+class SubclassedClassFileFilter
+implements ClassFileVisitor
+{
+ ClassFileVisitor classFileVisitor;
+
+
+ public SubclassedClassFileFilter(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ if (programClassFile.subClasses != null)
+ {
+ classFileVisitor.visitProgramClassFile(programClassFile);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ if (libraryClassFile.subClasses != null)
+ {
+ classFileVisitor.visitLibraryClassFile(libraryClassFile);
+ }
+ }
+}
diff --git a/src/proguard/WordReader.java b/src/proguard/WordReader.java
new file mode 100644
index 0000000..4827335
--- /dev/null
+++ b/src/proguard/WordReader.java
@@ -0,0 +1,271 @@
+/* $Id: WordReader.java,v 1.15 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import java.io.*;
+
+
+/**
+ * An abstract reader of words, with the possibility to include other readers.
+ * Words are separated by spaces or broken off at delimiters. Words containing
+ * spaces or delimiters can be quoted with single or double quotes.
+ * Comments (everything starting with '#' on a single line) are ignored.
+ *
+ * @author Eric Lafortune
+ */
+public abstract class WordReader
+{
+ private static final char COMMENT_CHARACTER = '#';
+
+
+ private WordReader includeWordReader;
+ private String currentLine;
+ private int currentLineLength;
+ private int currentIndex;
+ private String currentWord;
+ private String currentComments;
+
+
+ /**
+ * Specifies to start reading words from the given WordReader. When it is
+ * exhausted, this WordReader will continue to provide its own words.
+ *
+ * @param newIncludeWordReader the WordReader that will start reading words.
+ */
+ public void includeWordReader(WordReader newIncludeWordReader)
+ {
+ if (includeWordReader == null)
+ {
+ includeWordReader = newIncludeWordReader;
+ }
+ else
+ {
+ includeWordReader.includeWordReader(newIncludeWordReader);
+ }
+ }
+
+
+ /**
+ * Reads a word from this WordReader, or from one of its active included
+ * WordReader objects.
+ *
+ * @return the read word.
+ */
+ public String nextWord() throws IOException
+ {
+ currentWord = null;
+
+ // See if we have an included reader to produce a word.
+ if (includeWordReader != null)
+ {
+ // Does the included word reader still produce a word?
+ currentWord = includeWordReader.nextWord();
+ if (currentWord != null)
+ {
+ // Return it if so.
+ return currentWord;
+ }
+
+ // Otherwise ditch the word reader.
+ includeWordReader = null;
+ }
+
+ // Get a word from this reader.
+
+ // Skip leading whitespace.
+ while (currentLine != null &&
+ currentIndex < currentLineLength &&
+ Character.isWhitespace(currentLine.charAt(currentIndex)))
+ {
+ currentIndex++;
+ }
+
+ // Make sure we have a non-blank line.
+ while (currentLine == null || currentIndex == currentLineLength)
+ {
+ currentLine = nextLine();
+ if (currentLine == null)
+ {
+ return null;
+ }
+
+ // Trim off any comments.
+ int comments_start = currentLine.indexOf(COMMENT_CHARACTER);
+ if (comments_start >= 0)
+ {
+ currentLineLength = comments_start;
+
+ // Remember the comments.
+ String comment = currentLine.substring(comments_start + 1);
+ currentComments = currentComments == null ?
+ comment :
+ currentComments + '\n' + comment;
+ }
+ else
+ {
+ currentLineLength = currentLine.length();
+ }
+
+ // Skip leading whitespace.
+ currentIndex = 0;
+ while (currentIndex < currentLineLength &&
+ Character.isWhitespace(currentLine.charAt(currentIndex)))
+ {
+ currentIndex++;
+ }
+ }
+
+ // Find the word starting at the current index.
+ int startIndex = currentIndex;
+ int endIndex;
+
+ char startChar = currentLine.charAt(startIndex);
+
+ if (isDelimiter(startChar))
+ {
+ // The next word is a single delimiting character.
+ endIndex = ++currentIndex;
+ }
+ else if (isQuote(startChar))
+ {
+ // The next word is starting with a quote character.
+ // Skip the opening quote.
+ startIndex++;
+
+ // The next word is a quoted character string.
+ // Find the closing quote.
+ do
+ {
+ currentIndex++;
+
+ if (currentIndex == currentLineLength)
+ {
+ currentWord = currentLine.substring(startIndex-1, currentIndex);
+ throw new IOException("Missing closing quote for "+locationDescription());
+ }
+ }
+ while (currentLine.charAt(currentIndex) != startChar);
+
+ endIndex = currentIndex++;
+ }
+ else
+ {
+ // The next word is a simple character string.
+ // Find the end of the line, the first delimiter, or the first
+ // white space.
+ while (currentIndex < currentLineLength)
+ {
+ char currentCharacter = currentLine.charAt(currentIndex);
+ if (isDelimiter(currentCharacter) ||
+ Character.isWhitespace(currentCharacter))
+ {
+ break;
+ }
+
+ currentIndex++;
+ }
+
+ endIndex = currentIndex;
+ }
+
+ // Remember and return the parsed word.
+ currentWord = currentLine.substring(startIndex, endIndex);
+
+ return currentWord;
+ }
+
+
+ /**
+ * Returns the comments collected before returning the last word.
+ * Starts collecting new comments.
+ *
+ * @return the collected comments, or <code>null</code> if there weren't any.
+ */
+ public String lastComments() throws IOException
+ {
+ if (includeWordReader == null)
+ {
+ String comments = currentComments;
+ currentComments = null;
+ return comments;
+ }
+ else
+ {
+ return includeWordReader.lastComments();
+ }
+ }
+
+
+ /**
+ * Constructs a readable description of the current position in this
+ * WordReader and its included WordReader objects.
+ *
+ * @return the description.
+ */
+ public String locationDescription()
+ {
+ return
+ (includeWordReader == null ?
+ (currentWord == null ?
+ "end of " :
+ "'" + currentWord + "' in " ) :
+ (includeWordReader.locationDescription() + ",\n" +
+ " included from ")) +
+ lineLocationDescription();
+ }
+
+
+ /**
+ * Reads a line from this WordReader, or from one of its active included
+ * WordReader objects.
+ *
+ * @return the read line.
+ */
+ protected abstract String nextLine() throws IOException;
+
+
+ /**
+ * Constructs a readable description of the current WordReader position.
+ *
+ * @return the description.
+ */
+ protected abstract String lineLocationDescription();
+
+
+ private boolean isDelimiter(char character)
+ {
+ return character == '@' ||
+ character == '{' ||
+ character == '}' ||
+ character == '(' ||
+ character == ')' ||
+ character == ',' ||
+ character == ';' ||
+ character == File.pathSeparatorChar;
+ }
+
+
+ private boolean isQuote(char character)
+ {
+ return character == '\'' ||
+ character == '"';
+ }
+}
diff --git a/src/proguard/ant/ClassMemberSpecificationElement.java b/src/proguard/ant/ClassMemberSpecificationElement.java
new file mode 100644
index 0000000..062fe62
--- /dev/null
+++ b/src/proguard/ant/ClassMemberSpecificationElement.java
@@ -0,0 +1,201 @@
+/* $Id: ClassMemberSpecificationElement.java,v 1.4 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.ant;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+import proguard.*;
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.util.*;
+
+import java.util.*;
+
+/**
+ * This DataType represents a class member specification in Ant.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassMemberSpecificationElement extends DataType
+{
+ private String access;
+ private String type;
+ private String name;
+ private String parameters;
+
+
+ /**
+ * Adds the contents of this class member specification element to the given
+ * list.
+ * @param classMemberSpecifications the class member specifications to be
+ * extended.
+ * @param isMethod specifies whether this specification
+ * refers to a method.
+ * @param isConstructor specifies whether this specification
+ * refers to a constructor.
+ */
+ public void appendTo(List classMemberSpecifications,
+ boolean isMethod,
+ boolean isConstructor)
+ {
+ // Get the referenced file set, or else this one.
+ ClassMemberSpecificationElement classSpecificationElement = isReference() ?
+ (ClassMemberSpecificationElement)getCheckedRef(this.getClass(),
+ this.getClass().getName()) :
+ this;
+
+ // Create a new class specification.
+ String access = classSpecificationElement.access;
+ String type = classSpecificationElement.type;
+ String name = classSpecificationElement.name;
+ String parameters = classSpecificationElement.parameters;
+
+ // Perform some basic checks on the attributes.
+ if (isMethod)
+ {
+ if (isConstructor)
+ {
+ if (type != null)
+ {
+ throw new BuildException("Type attribute not allowed in constructor specification ["+type+"]");
+ }
+
+ if (parameters != null)
+ {
+ type = ClassConstants.EXTERNAL_TYPE_VOID;
+ }
+
+ name = ClassConstants.INTERNAL_METHOD_NAME_INIT;
+ }
+ else if ((type != null) ^ (parameters != null))
+ {
+ throw new BuildException("Type and parameters attributes must always be present in combination in method specification");
+ }
+ }
+ else
+ {
+ if (parameters != null)
+ {
+ throw new BuildException("Parameters attribute not allowed in field specification ["+parameters+"]");
+ }
+ }
+
+ List parameterList = ListUtil.commaSeparatedList(parameters);
+
+ String descriptor =
+ parameters != null ? ClassUtil.internalMethodDescriptor(type, parameterList) :
+ type != null ? ClassUtil.internalType(type) :
+ null;
+
+ ClassMemberSpecification classMemberSpecification =
+ new ClassMemberSpecification(requiredAccessFlags(true, access),
+ requiredAccessFlags(false, access),
+ name,
+ descriptor);
+
+ // Add it to the list.
+ classMemberSpecifications.add(classMemberSpecification);
+ }
+
+
+ // Ant task attributes.
+
+ public void setAccess(String access)
+ {
+ this.access = access;
+ }
+
+
+ public void setType(String type)
+ {
+ this.type = type;
+ }
+
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+
+ public void setParameters(String parameters)
+ {
+ this.parameters = parameters;
+ }
+
+
+ /**
+ * @deprecated Use {@link #setParameters(String)} instead.
+ */
+ public void setParam(String parameters)
+ {
+ this.parameters = parameters;
+ }
+
+
+ // Small utility methods.
+
+ private int requiredAccessFlags(boolean set,
+ String access)
+ throws BuildException
+ {
+ int accessFlags = 0;
+
+ if (access != null)
+ {
+ StringTokenizer tokenizer = new StringTokenizer(access, " ,");
+ while (tokenizer.hasMoreTokens())
+ {
+ String token = tokenizer.nextToken();
+
+ if (token.startsWith("!") ^ set)
+ {
+ String strippedToken = token.startsWith("!") ?
+ token.substring(1) :
+ token;
+
+ int accessFlag =
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_PRIVATE) ? ClassConstants.INTERNAL_ACC_PRIVATE :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_PROTECTED) ? ClassConstants.INTERNAL_ACC_PROTECTED :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_STATIC) ? ClassConstants.INTERNAL_ACC_STATIC :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT :
+ 0;
+
+ if (accessFlag == 0)
+ {
+ throw new BuildException("Incorrect class member access modifier ["+strippedToken+"]");
+ }
+
+ accessFlags |= accessFlag;
+ }
+ }
+ }
+
+ return accessFlags;
+ }
+}
diff --git a/src/proguard/ant/ClassPathElement.java b/src/proguard/ant/ClassPathElement.java
new file mode 100644
index 0000000..e1d687a
--- /dev/null
+++ b/src/proguard/ant/ClassPathElement.java
@@ -0,0 +1,173 @@
+/* $Id: ClassPathElement.java,v 1.7 2004/12/18 20:21:11 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.ant;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+
+import proguard.*;
+
+import java.io.*;
+import java.lang.ref.Reference;
+import java.util.Stack;
+
+/**
+ * This FileSet represents a class path entry (or a set of class path entries)
+ * in Ant.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassPathElement extends Path
+{
+ private String filter;
+ private String jarFilter;
+ private String warFilter;
+ private String earFilter;
+ private String zipFilter;
+
+
+ /**
+ * @see Path#Path(Project)
+ */
+ public ClassPathElement(Project project)
+ {
+ super(project);
+ }
+
+
+ /**
+ * Adds the contents of this class path element to the given class path.
+ * @param classPath the class path to be extended.
+ * @param output specifies whether this is an output entry or not.
+ */
+ public void appendClassPathEntriesTo(ClassPath classPath, boolean output)
+ {
+ String basePath = "";
+ String[] files;
+
+ if (isReference())
+ {
+ // Get the referenced path or file set.
+ Object referencedObject = getCheckedRef(DataType.class,
+ DataType.class.getName());
+
+ if (referencedObject instanceof Path)
+ {
+ Path path = (Path)referencedObject;
+
+ // Get the names of the files in the referenced path.
+ files = path.list();
+ }
+ else if (referencedObject instanceof AbstractFileSet)
+ {
+ AbstractFileSet fileSet = (AbstractFileSet)referencedObject;
+
+ // Get the names of the existing input files in the referenced file set.
+ DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject());
+ basePath = scanner.getBasedir().getPath() + File.separator;
+ files = scanner.getIncludedFiles();
+ }
+ else
+ {
+ throw new BuildException("The refid attribute doesn't point to a <path> element or a <fileset> element");
+ }
+ }
+ else
+ {
+ // Get the names of the files in this path.
+ files = list();
+ }
+
+ for (int index = 0; index < files.length; index++)
+ {
+ // Create a new class path entry, with the proper file name and
+ // any filters.
+ ClassPathEntry entry = new ClassPathEntry(basePath + files[index], output);
+ entry.setFilter(filter);
+ entry.setJarFilter(jarFilter);
+ entry.setWarFilter(warFilter);
+ entry.setEarFilter(earFilter);
+ entry.setZipFilter(zipFilter);
+
+ // Add it to the class path.
+ classPath.add(entry);
+ }
+ }
+
+
+ // Ant task attributes.
+
+ /**
+ * @deprecated Use {@link #setLocation(File)} instead.
+ */
+ public void setFile(File file)
+ {
+ setLocation(file);
+ }
+
+
+ /**
+ * @deprecated Use {@link #setLocation(File)} instead.
+ */
+ public void setDir(File file)
+ {
+ setLocation(file);
+ }
+
+
+ /**
+ * @deprecated Use {@link #setLocation(File)} instead.
+ */
+ public void setName(File file)
+ {
+ setLocation(file);
+ }
+
+
+ public void setFilter(String filter)
+ {
+ this.filter = filter;
+ }
+
+
+ public void setJarFilter(String jarFilter)
+ {
+ this.jarFilter = jarFilter;
+ }
+
+
+ public void setWarFilter(String warFilter)
+ {
+ this.warFilter = warFilter;
+ }
+
+
+ public void setEarFilter(String earFilter)
+ {
+ this.earFilter = earFilter;
+ }
+
+
+ public void setZipFilter(String zipFilter)
+ {
+ this.zipFilter = zipFilter;
+ }
+}
diff --git a/src/proguard/ant/ClassSpecificationElement.java b/src/proguard/ant/ClassSpecificationElement.java
new file mode 100644
index 0000000..7da58af
--- /dev/null
+++ b/src/proguard/ant/ClassSpecificationElement.java
@@ -0,0 +1,230 @@
+/* $Id: ClassSpecificationElement.java,v 1.3 2004/12/18 20:21:43 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.ant;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+import proguard.*;
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+
+import java.util.*;
+
+/**
+ * This DataType represents a class specification in Ant.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassSpecificationElement extends DataType
+{
+ private static final String ANY_CLASS_KEYWORD = "*";
+
+ private String access;
+ private String type;
+ private String name;
+ private String extends_;
+ private List fieldSpecifications = new ArrayList();
+ private List methodSpecifications = new ArrayList();
+
+
+ /**
+ * Adds the contents of this class specification element to the given list.
+ * @param classSpecifications the class specifications to be extended.
+ * @param markClassFiles specifies whether to mark the class files.
+ * @param markConditionally specifies whether to mark the class files
+ * and class members conditionally.
+ */
+ public void appendTo(List classSpecifications,
+ boolean markClassFiles,
+ boolean markConditionally)
+ {
+ // Get the referenced file set, or else this one.
+ ClassSpecificationElement classSpecificationElement = isReference() ?
+ (ClassSpecificationElement)getCheckedRef(this.getClass(),
+ this.getClass().getName()) :
+ this;
+
+ // Create a new class specification.
+ String access = classSpecificationElement.access;
+ String type = classSpecificationElement.type;
+ String name = classSpecificationElement.name;
+ String extends_ = classSpecificationElement.extends_;
+
+ // For backward compatibility, allow a single "*" wildcard to match
+ // any class.
+ if (name != null &&
+ name.equals(ANY_CLASS_KEYWORD))
+ {
+ name = null;
+ }
+
+ ClassSpecification classSpecification =
+ new ClassSpecification(requiredAccessFlags(true, access, type),
+ requiredAccessFlags(false, access, type),
+ name != null ? ClassUtil.internalClassName(name) : null,
+ extends_ != null ? ClassUtil.internalClassName(extends_) : null,
+ markClassFiles,
+ markConditionally);
+
+ for (int index = 0; index < fieldSpecifications.size(); index++)
+ {
+ classSpecification.addField((ClassMemberSpecification)fieldSpecifications.get(index));
+ }
+
+ for (int index = 0; index < methodSpecifications.size(); index++)
+ {
+ classSpecification.addMethod((ClassMemberSpecification)methodSpecifications.get(index));
+ }
+
+ // Add it to the list.
+ classSpecifications.add(classSpecification);
+ }
+
+
+ // Ant task attributes.
+
+ public void setAccess(String access)
+ {
+ this.access = access;
+ }
+
+
+ public void setType(String type)
+ {
+ this.type = type;
+ }
+
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+
+ public void setExtends(String extends_)
+ {
+ this.extends_ = extends_;
+ }
+
+
+ public void setImplements(String implements_)
+ {
+ this.extends_ = implements_;
+ }
+
+
+ // Ant task nested elements.
+
+ public void addConfiguredField(ClassMemberSpecificationElement classMemberSpecificationElement)
+ {
+ if (fieldSpecifications == null)
+ {
+ fieldSpecifications = new ArrayList();
+ }
+
+ classMemberSpecificationElement.appendTo(fieldSpecifications,
+ false,
+ false);
+ }
+
+
+ public void addConfiguredMethod(ClassMemberSpecificationElement classMemberSpecificationElement)
+ {
+ if (methodSpecifications == null)
+ {
+ methodSpecifications = new ArrayList();
+ }
+
+ classMemberSpecificationElement.appendTo(methodSpecifications,
+ true,
+ false);
+ }
+
+
+ public void addConfiguredConstructor(ClassMemberSpecificationElement classMemberSpecificationElement)
+ {
+ if (methodSpecifications == null)
+ {
+ methodSpecifications = new ArrayList();
+ }
+
+ classMemberSpecificationElement.appendTo(methodSpecifications,
+ true,
+ true);
+ }
+
+
+ // Small utility methods.
+
+ private int requiredAccessFlags(boolean set,
+ String access,
+ String type)
+ throws BuildException
+ {
+ int accessFlags = 0;
+
+ if (access != null)
+ {
+ StringTokenizer tokenizer = new StringTokenizer(access, " ,");
+ while (tokenizer.hasMoreTokens())
+ {
+ String token = tokenizer.nextToken();
+
+ if (token.startsWith("!") ^ set)
+ {
+ String strippedToken = token.startsWith("!") ?
+ token.substring(1) :
+ token;
+
+ int accessFlag =
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL :
+ strippedToken.equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT :
+ 0;
+
+ if (accessFlag == 0)
+ {
+ throw new BuildException("Incorrect class access modifier ["+strippedToken+"]");
+ }
+
+ accessFlags |= accessFlag;
+ }
+ }
+ }
+
+ if (type != null && (type.startsWith("!") ^ set))
+ {
+ int accessFlag =
+ type.equals( ClassConstants.EXTERNAL_ACC_INTERFACE) ||
+ type.equals("!" + ClassConstants.EXTERNAL_ACC_INTERFACE) ? ClassConstants.INTERNAL_ACC_INTERFACE :
+ type.equals("class") ? 0 :
+ -1;
+ if (accessFlag == -1)
+ {
+ throw new BuildException("Incorrect class type ["+type+"]");
+ }
+
+ accessFlags |= accessFlag;
+ }
+
+ return accessFlags;
+ }
+}
diff --git a/src/proguard/ant/ConfigurationElement.java b/src/proguard/ant/ConfigurationElement.java
new file mode 100644
index 0000000..e0ff9b1
--- /dev/null
+++ b/src/proguard/ant/ConfigurationElement.java
@@ -0,0 +1,59 @@
+/* $Id: ConfigurationElement.java,v 1.1 2004/08/28 16:37:12 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.ant;
+
+import proguard.*;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+
+import java.util.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This DataType represents a reference to a ProGuard configuration in Ant.
+ *
+ * @author Eric Lafortune
+ */
+public class ConfigurationElement extends DataType
+{
+ /**
+ * Adds the contents of this configuration task to the given configuration.
+ * @param configuration the configuration to be extended.
+ */
+ public void appendTo(Configuration configuration)
+ {
+ // Get the referenced element.
+ if (!isReference())
+ {
+ throw new BuildException("Nested element <configuration> must have a refid attribute");
+ }
+
+ ConfigurationTask configurationTask =
+ (ConfigurationTask)getCheckedRef(ConfigurationTask.class,
+ ConfigurationTask.class.getName());
+
+ // Append the referenced configuration entries to the given configuration.
+ configurationTask.appendTo(configuration);
+ }
+}
diff --git a/src/proguard/ant/ConfigurationTask.java b/src/proguard/ant/ConfigurationTask.java
new file mode 100644
index 0000000..8ddbc96
--- /dev/null
+++ b/src/proguard/ant/ConfigurationTask.java
@@ -0,0 +1,290 @@
+/* $Id: ConfigurationTask.java,v 1.3 2004/10/31 16:28:32 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.ant;
+
+import proguard.*;
+
+import org.apache.tools.ant.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This Task allows to define a ProGuard configuration from Ant.
+ *
+ * @author Eric Lafortune
+ */
+public class ConfigurationTask extends Task
+{
+ protected Configuration configuration = new Configuration();
+
+
+ /**
+ * Adds the contents of this configuration task to the given configuration.
+ * @param configuration the configuration to be extended.
+ */
+ public void appendTo(Configuration configuration)
+ {
+ // Append all of these configuration entries to the given configuration.
+ configuration.programJars = extendClassPath(configuration.programJars,
+ this.configuration.programJars);
+
+ configuration.libraryJars = extendClassPath(configuration.libraryJars,
+ this.configuration.libraryJars);
+
+ configuration.keep = extendClassSpecifications(configuration.keep,
+ this.configuration.keep);
+
+ configuration.keepNames = extendClassSpecifications(configuration.keepNames,
+ this.configuration.keepNames);
+
+ configuration.keepAttributes = extendAttributes(configuration.keepAttributes,
+ this.configuration.keepAttributes);
+ }
+
+
+ // Ant task nested elements.
+
+ public void addConfiguredInjar(ClassPathElement classPathElement)
+ {
+ configuration.programJars = extendClassPath(configuration.programJars,
+ classPathElement,
+ false);
+ }
+
+
+ public void addConfiguredOutjar(ClassPathElement classPathElement)
+ {
+ configuration.programJars = extendClassPath(configuration.programJars,
+ classPathElement,
+ true);
+ }
+
+
+ public void addConfiguredLibraryjar(ClassPathElement classPathElement)
+ {
+ configuration.libraryJars = extendClassPath(configuration.libraryJars,
+ classPathElement,
+ false);
+ }
+
+
+ public void addConfiguredKeep(ClassSpecificationElement classSpecificationElement)
+ {
+ configuration.keep = extendClassSpecifications(configuration.keep,
+ classSpecificationElement,
+ true,
+ false);
+ }
+
+
+ public void addConfiguredKeepclassmembers(ClassSpecificationElement classSpecificationElement)
+ {
+ configuration.keep = extendClassSpecifications(configuration.keep,
+ classSpecificationElement,
+ false,
+ false);
+ }
+
+
+ public void addConfiguredKeepclasseswithmembers(ClassSpecificationElement classSpecificationElement)
+ {
+ configuration.keep = extendClassSpecifications(configuration.keep,
+ classSpecificationElement,
+ true,
+ true);
+ }
+
+
+ public void addConfiguredKeepnames(ClassSpecificationElement classSpecificationElement)
+ {
+ configuration.keepNames = extendClassSpecifications(configuration.keepNames,
+ classSpecificationElement,
+ true,
+ false);
+ }
+
+
+ public void addConfiguredKeepclassmembernames(ClassSpecificationElement classSpecificationElement)
+ {
+ configuration.keepNames = extendClassSpecifications(configuration.keepNames,
+ classSpecificationElement,
+ false,
+ false);
+ }
+
+
+ public void addConfiguredKeepclasseswithmembernames(ClassSpecificationElement classSpecificationElement)
+ {
+ configuration.keepNames = extendClassSpecifications(configuration.keepNames,
+ classSpecificationElement,
+ true,
+ true);
+ }
+
+
+ public void addConfiguredKeepattribute(KeepAttributeElement keepAttributeElement)
+ {
+ configuration.keepAttributes = extendAttributes(configuration.keepAttributes,
+ keepAttributeElement);
+ }
+
+
+ public void addConfiguredConfiguration(ConfigurationElement configurationElement)
+ {
+ configurationElement.appendTo(configuration);
+ }
+
+
+ // Implementations for Task.
+
+ public void addText(String text) throws BuildException
+ {
+ try
+ {
+ String arg = getProject().replaceProperties(text);
+ ConfigurationParser parser = new ConfigurationParser(new String[] { arg });
+ parser.parse(configuration);
+ }
+ catch (IOException ex)
+ {
+ throw new BuildException(ex.getMessage());
+ }
+ catch (ParseException ex)
+ {
+ throw new BuildException(ex.getMessage());
+ }
+ }
+
+
+ // Small utility methods.
+
+ private String optionalFileName(String fileName)
+ {
+ return
+ fileName.equalsIgnoreCase("false") ||
+ fileName.equalsIgnoreCase("no") ||
+ fileName.equalsIgnoreCase("off") ? null :
+ fileName.equalsIgnoreCase("true") ||
+ fileName.equalsIgnoreCase("yes") ||
+ fileName.equalsIgnoreCase("on") ? "" :
+ fileName;
+ }
+
+
+ private ClassPath extendClassPath(ClassPath classPath,
+ ClassPathElement classPathElement,
+ boolean output)
+ {
+ if (classPath == null)
+ {
+ classPath = new ClassPath();
+ }
+
+ classPathElement.appendClassPathEntriesTo(classPath,
+ output);
+
+ return classPath;
+ }
+
+
+ private ClassPath extendClassPath(ClassPath classPath,
+ ClassPath additionalClassPath)
+ {
+ if (additionalClassPath != null)
+ {
+ if (classPath == null)
+ {
+ classPath = new ClassPath();
+ }
+
+ classPath.addAll(additionalClassPath);
+ }
+
+ return classPath;
+ }
+
+
+ private List extendClassSpecifications(List classSpecifications,
+ ClassSpecificationElement classSpecificationElement,
+ boolean markClassFiles,
+ boolean markClassFilesConditionally)
+ {
+ if (classSpecifications == null)
+ {
+ classSpecifications = new ArrayList();
+ }
+
+ classSpecificationElement.appendTo(classSpecifications,
+ markClassFiles,
+ markClassFilesConditionally);
+
+ return classSpecifications;
+ }
+
+
+ private List extendClassSpecifications(List classSpecifications,
+ List additionalClassSpecifications)
+ {
+ if (additionalClassSpecifications != null)
+ {
+ if (classSpecifications == null)
+ {
+ classSpecifications = new ArrayList();
+ }
+
+ classSpecifications.addAll(additionalClassSpecifications);
+ }
+
+ return classSpecifications;
+ }
+
+
+ private List extendAttributes(List attributes,
+ KeepAttributeElement keepAttributeElement)
+ {
+ if (attributes == null)
+ {
+ attributes = new ArrayList();
+ }
+
+ keepAttributeElement.appendTo(attributes);
+
+ return attributes;
+ }
+
+
+ private List extendAttributes(List attributes,
+ List additionalAttributes)
+ {
+ if (additionalAttributes != null)
+ {
+ if (attributes == null)
+ {
+ attributes = new ArrayList();
+ }
+
+ attributes.addAll(additionalAttributes);
+ }
+
+ return attributes;
+ }
+}
diff --git a/src/proguard/ant/KeepAttributeElement.java b/src/proguard/ant/KeepAttributeElement.java
new file mode 100644
index 0000000..1ce0041
--- /dev/null
+++ b/src/proguard/ant/KeepAttributeElement.java
@@ -0,0 +1,70 @@
+/* $Id: KeepAttributeElement.java,v 1.2 2004/08/28 20:55:21 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.ant;
+
+import org.apache.tools.ant.types.*;
+
+import java.util.*;
+
+/**
+ * This DataType represents a named attribute in Ant.
+ *
+ * @author Eric Lafortune
+ */
+public class KeepAttributeElement extends DataType
+{
+ private String name;
+
+
+ /**
+ * Adds the contents of this element to the given list of attributes.
+ * @param keepAttributes the list of attributes to be extended.
+ */
+ public void appendTo(List keepAttributes)
+ {
+ // Get the referenced element, or else this one.
+ KeepAttributeElement keepAttributeElement = isReference() ?
+ (KeepAttributeElement)getCheckedRef(this.getClass(),
+ this.getClass().getName()) :
+ this;
+
+ String name = keepAttributeElement.name;
+
+ if (name == null)
+ {
+ // Clear the list to keep all attributes.
+ keepAttributes.clear();
+ }
+ else
+ {
+ // Add the attibute name to the list.
+ keepAttributes.add(name);
+ }
+ }
+
+
+ // Ant task attributes.
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+}
diff --git a/src/proguard/ant/ProGuardTask.java b/src/proguard/ant/ProGuardTask.java
new file mode 100644
index 0000000..a88fc2e
--- /dev/null
+++ b/src/proguard/ant/ProGuardTask.java
@@ -0,0 +1,216 @@
+/* $Id: ProGuardTask.java,v 1.28 2004/11/20 15:08:57 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.ant;
+
+import org.apache.tools.ant.*;
+import proguard.*;
+import proguard.classfile.util.*;
+
+import java.io.*;
+
+/**
+ * This Task allows to configure and run ProGuard from Ant.
+ *
+ * @author Eric Lafortune
+ */
+public class ProGuardTask extends ConfigurationTask
+{
+ // Ant task attributes.
+
+ public void setConfiguration(File configurationFile) throws BuildException
+ {
+ try
+ {
+ ConfigurationParser parser = new ConfigurationParser(configurationFile.getPath());
+ parser.parse(configuration);
+ }
+ catch (IOException ex)
+ {
+ throw new BuildException(ex.getMessage());
+ }
+ catch (ParseException ex)
+ {
+ throw new BuildException(ex.getMessage());
+ }
+ }
+
+
+ /**
+ * @deprecated Use the nested outjar element instead.
+ */
+ public void setOutjar(String parameters)
+ {
+ throw new BuildException("Use the <outjar> nested element instead of the 'outjar' attribute");
+ }
+
+
+ public void setSkipnonpubliclibraryclasses(boolean skipNonPublicLibraryClasses)
+ {
+ configuration.skipNonPublicLibraryClasses = skipNonPublicLibraryClasses;
+ }
+
+
+ public void setSkipnonpubliclibraryclassmembers(boolean skipNonPublicLibraryClassMembers)
+ {
+ configuration.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembers;
+ }
+
+
+ public void setPrintseeds(File printSeeds)
+ {
+ configuration.printSeeds = optionalFileName(printSeeds);
+ }
+
+
+ public void setShrink(boolean shrink)
+ {
+ configuration.shrink = shrink;
+ }
+
+
+ public void setPrintusage(File printUsage)
+ {
+ configuration.printUsage = optionalFileName(printUsage);
+ }
+
+
+ public void setOptimize(boolean optimize)
+ {
+ configuration.optimize = optimize;
+ }
+
+
+ public void setAllowaccessmodification(boolean allowAccessModification)
+ {
+ configuration.allowAccessModification = allowAccessModification;
+ }
+
+
+ public void setObfuscate(boolean obfuscate)
+ {
+ configuration.obfuscate = obfuscate;
+ }
+
+
+ public void setPrintmapping(File printMapping)
+ {
+ configuration.printMapping = optionalFileName(printMapping);
+ }
+
+
+ public void setApplymapping(String applyMapping)
+ {
+ configuration.applyMapping = applyMapping;
+ }
+
+
+ public void setObfuscationdictionary(File obfuscationDictionary)
+ {
+ configuration.obfuscationDictionary = obfuscationDictionary.getName();
+ }
+
+
+ public void setOverloadaggressively(boolean overloadAggressively)
+ {
+ configuration.overloadAggressively = overloadAggressively;
+ }
+
+
+ public void setDefaultpackage(String defaultPackage)
+ {
+ configuration.defaultPackage = ClassUtil.internalClassName(defaultPackage);
+ }
+
+
+ public void setUsemixedcaseclassnames(boolean useMixedCaseClassNames)
+ {
+ configuration.useMixedCaseClassNames = useMixedCaseClassNames;
+ }
+
+
+ public void setRenamesourcefileattribute(String newSourceFileAttribute)
+ {
+ configuration.newSourceFileAttribute = newSourceFileAttribute;
+ }
+
+
+ public void setVerbose(boolean verbose)
+ {
+ configuration.verbose = verbose;
+ }
+
+
+ public void setNote(boolean note)
+ {
+ configuration.note = note;
+ }
+
+
+ public void setWarn(boolean warn)
+ {
+ configuration.warn = warn;
+ }
+
+
+ public void setIgnorewarnings(boolean ignoreWarnings)
+ {
+ configuration.ignoreWarnings = ignoreWarnings;
+ }
+
+
+ public void setDump(File dump)
+ {
+ configuration.dump = optionalFileName(dump);
+ }
+
+
+ // Implementations for Task.
+
+ public void execute() throws BuildException
+ {
+ try
+ {
+ ProGuard proGuard = new ProGuard(configuration);
+ proGuard.execute();
+ }
+ catch (IOException ex)
+ {
+ throw new BuildException(ex.getMessage());
+ }
+ }
+
+
+ // Small utility methods.
+
+ private String optionalFileName(File file)
+ {
+ String fileName = file.getName();
+
+ return
+ fileName.equalsIgnoreCase("false") ||
+ fileName.equalsIgnoreCase("no") ||
+ fileName.equalsIgnoreCase("off") ? null :
+ fileName.equalsIgnoreCase("true") ||
+ fileName.equalsIgnoreCase("yes") ||
+ fileName.equalsIgnoreCase("on") ? "" :
+ file.getPath();
+ }
+}
diff --git a/src/proguard/ant/package.html b/src/proguard/ant/package.html
new file mode 100644
index 0000000..75e0466
--- /dev/null
+++ b/src/proguard/ant/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains the Ant task for ProGuard.
+</body>
diff --git a/src/proguard/ant/task.properties b/src/proguard/ant/task.properties
new file mode 100644
index 0000000..b676db7
--- /dev/null
+++ b/src/proguard/ant/task.properties
@@ -0,0 +1,2 @@
+proguard = proguard.ant.ProGuardTask
+proguardconfiguration = proguard.ant.ConfigurationTask
diff --git a/src/proguard/classfile/ClassConstants.java b/src/proguard/classfile/ClassConstants.java
new file mode 100644
index 0000000..844d616
--- /dev/null
+++ b/src/proguard/classfile/ClassConstants.java
@@ -0,0 +1,203 @@
+/* $Id: ClassConstants.java,v 1.24 2004/12/19 21:03:54 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+
+/**
+ * Constants used in representing a Java class file (*.class).
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public interface ClassConstants
+{
+ public static final String CLASS_FILE_EXTENSION = ".class";
+
+ public static final int MAGIC = 0xCAFEBABE;
+
+ public static final int MAJOR_VERSION_MIN = 45;
+ public static final int MINOR_VERSION_MIN = 3;
+ public static final int MAJOR_VERSION_MAX = 49;
+ public static final int MINOR_VERSION_MAX = 0;
+
+ public static final int INTERNAL_ACC_PUBLIC = 0x0001;
+ public static final int INTERNAL_ACC_PRIVATE = 0x0002;
+ public static final int INTERNAL_ACC_PROTECTED = 0x0004;
+ public static final int INTERNAL_ACC_STATIC = 0x0008;
+ public static final int INTERNAL_ACC_FINAL = 0x0010;
+ public static final int INTERNAL_ACC_SUPER = 0x0020;
+ public static final int INTERNAL_ACC_SYNCHRONIZED = 0x0020;
+ public static final int INTERNAL_ACC_VOLATILE = 0x0040;
+ public static final int INTERNAL_ACC_TRANSIENT = 0x0080;
+ public static final int INTERNAL_ACC_BRIDGE = 0x0040;
+ public static final int INTERNAL_ACC_VARARGS = 0x0080;
+ public static final int INTERNAL_ACC_NATIVE = 0x0100;
+ public static final int INTERNAL_ACC_INTERFACE = 0x0200;
+ public static final int INTERNAL_ACC_ABSTRACT = 0x0400;
+ public static final int INTERNAL_ACC_STRICT = 0x0800;
+ public static final int INTERNAL_ACC_SYNTHETIC = 0x1000;
+ public static final int INTERNAL_ACC_ANNOTATTION = 0x2000;
+ public static final int INTERNAL_ACC_ENUM = 0x4000;
+
+ public static final int VALID_INTERNAL_ACC_CLASS = INTERNAL_ACC_PUBLIC |
+ INTERNAL_ACC_FINAL |
+ INTERNAL_ACC_SUPER |
+ INTERNAL_ACC_INTERFACE |
+ INTERNAL_ACC_ABSTRACT |
+ INTERNAL_ACC_SYNTHETIC |
+ INTERNAL_ACC_ANNOTATTION |
+ INTERNAL_ACC_ENUM;
+ public static final int VALID_INTERNAL_ACC_FIELD = INTERNAL_ACC_PUBLIC |
+ INTERNAL_ACC_PRIVATE |
+ INTERNAL_ACC_PROTECTED |
+ INTERNAL_ACC_STATIC |
+ INTERNAL_ACC_FINAL |
+ INTERNAL_ACC_VOLATILE |
+ INTERNAL_ACC_TRANSIENT |
+ INTERNAL_ACC_SYNTHETIC |
+ INTERNAL_ACC_ENUM;
+ public static final int VALID_INTERNAL_ACC_METHOD = INTERNAL_ACC_PUBLIC |
+ INTERNAL_ACC_PRIVATE |
+ INTERNAL_ACC_PROTECTED |
+ INTERNAL_ACC_STATIC |
+ INTERNAL_ACC_FINAL |
+ INTERNAL_ACC_SYNCHRONIZED |
+ INTERNAL_ACC_BRIDGE |
+ INTERNAL_ACC_VARARGS |
+ INTERNAL_ACC_NATIVE |
+ INTERNAL_ACC_ABSTRACT |
+ INTERNAL_ACC_STRICT |
+ INTERNAL_ACC_SYNTHETIC;
+
+ public static final String EXTERNAL_ACC_PUBLIC = "public";
+ public static final String EXTERNAL_ACC_PRIVATE = "private";
+ public static final String EXTERNAL_ACC_PROTECTED = "protected";
+ public static final String EXTERNAL_ACC_STATIC = "static";
+ public static final String EXTERNAL_ACC_FINAL = "final";
+ public static final String EXTERNAL_ACC_SUPER = "super";
+ public static final String EXTERNAL_ACC_SYNCHRONIZED = "synchronized";
+ public static final String EXTERNAL_ACC_VOLATILE = "volatile";
+ public static final String EXTERNAL_ACC_TRANSIENT = "transient";
+ public static final String EXTERNAL_ACC_NATIVE = "native";
+ public static final String EXTERNAL_ACC_INTERFACE = "interface";
+ public static final String EXTERNAL_ACC_ABSTRACT = "abstract";
+ public static final String EXTERNAL_ACC_STRICT = "strictfp";
+
+ public static final int CONSTANT_Utf8 = 1;
+ public static final int CONSTANT_Integer = 3;
+ public static final int CONSTANT_Float = 4;
+ public static final int CONSTANT_Long = 5;
+ public static final int CONSTANT_Double = 6;
+ public static final int CONSTANT_Class = 7;
+ public static final int CONSTANT_String = 8;
+ public static final int CONSTANT_Fieldref = 9;
+ public static final int CONSTANT_Methodref = 10;
+ public static final int CONSTANT_InterfaceMethodref = 11;
+ public static final int CONSTANT_NameAndType = 12;
+
+ public static final String ATTR_InnerClasses = "InnerClasses";
+ public static final String ATTR_EnclosingMethod = "EnclosingMethod";
+ public static final String ATTR_ConstantValue = "ConstantValue";
+ public static final String ATTR_Exceptions = "Exceptions";
+ public static final String ATTR_Code = "Code";
+ public static final String ATTR_LineNumberTable = "LineNumberTable";
+ public static final String ATTR_LocalVariableTable = "LocalVariableTable";
+ public static final String ATTR_LocalVariableTypeTable = "LocalVariableTypeTable";
+ public static final String ATTR_SourceFile = "SourceFile";
+ public static final String ATTR_SourceDir = "SourceDir";
+ public static final String ATTR_Deprecated = "Deprecated";
+ public static final String ATTR_Synthetic = "Synthetic";
+ public static final String ATTR_Signature = "Signature";
+ public static final String ATTR_RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations";
+ public static final String ATTR_RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations";
+ public static final String ATTR_RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations";
+ public static final String ATTR_RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations";
+ public static final String ATTR_AnnotationDefault = "AnnotationDefault";
+
+ public static final int ELEMENT_VALUE_STRING_CONSTANT = 's';
+ public static final int ELEMENT_VALUE_ENUM_CONSTANT = 'e';
+ public static final int ELEMENT_VALUE_CLASS = 'c';
+ public static final int ELEMENT_VALUE_ANNOTATION = '@';
+ public static final int ELEMENT_VALUE_ARRAY = '[';
+
+ public static final char EXTERNAL_PACKAGE_SEPARATOR = '.';
+ public static final char INTERNAL_PACKAGE_SEPARATOR = '/';
+
+ public static final char EXTERNAL_METHOD_ARGUMENTS_OPEN = '(';
+ public static final char EXTERNAL_METHOD_ARGUMENTS_CLOSE = ')';
+ public static final char EXTERNAL_METHOD_ARGUMENTS_SEPARATOR = ',';
+
+ public static final char INTERNAL_METHOD_ARGUMENTS_OPEN = '(';
+ public static final char INTERNAL_METHOD_ARGUMENTS_CLOSE = ')';
+
+ public static final String INTERNAL_NAME_JAVA_LANG_OBJECT = "java/lang/Object";
+ public static final String INTERNAL_TYPE_JAVA_LANG_OBJECT = "Ljava/lang/Object;";
+ public static final String INTERNAL_PACKAGE_JAVA_LANG = "java/lang/";
+
+ public static final String INTERNAL_NAME_JAVA_LANG_CLONEABLE = "java/lang/Cloneable";
+ public static final String INTERNAL_NAME_JAVA_IO_SERIALIZABLE = "java/io/Serializable";
+
+ public static final String INTERNAL_METHOD_NAME_INIT = "<init>";
+ public static final String INTERNAL_METHOD_TYPE_INIT = "()V";
+ public static final String INTERNAL_METHOD_NAME_CLINIT = "<clinit>";
+ public static final String INTERNAL_METHOD_TYPE_CLINIT = "()V";
+
+ public static final String INTERNAL_CLASS_NAME_JAVA_LANG_CLASS = "java/lang/Class";
+ public static final String INTERNAL_METHOD_NAME_CLASS_FOR_NAME = "forName";
+ public static final String INTERNAL_METHOD_TYPE_CLASS_FOR_NAME = "(Ljava/lang/String;)Ljava/lang/Class;";
+
+ public static final String INTERNAL_METHOD_NAME_DOT_CLASS = "class$";
+ public static final String INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC = "(Ljava/lang/String;)Ljava/lang/Class;";
+ public static final String INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES = "(Ljava/lang/String;Z)Ljava/lang/Class;";
+
+ public static final String INTERNAL_METHOD_NAME_NEW_INSTANCE = "newInstance";
+ public static final String INTERNAL_METHOD_TYPE_NEW_INSTANCE = "()Ljava/lang/Object;";
+
+ public static final char INTERNAL_TYPE_VOID = 'V';
+ public static final char INTERNAL_TYPE_BOOLEAN = 'Z';
+ public static final char INTERNAL_TYPE_BYTE = 'B';
+ public static final char INTERNAL_TYPE_CHAR = 'C';
+ public static final char INTERNAL_TYPE_SHORT = 'S';
+ public static final char INTERNAL_TYPE_INT = 'I';
+ public static final char INTERNAL_TYPE_FLOAT = 'F';
+ public static final char INTERNAL_TYPE_LONG = 'J';
+ public static final char INTERNAL_TYPE_DOUBLE = 'D';
+ public static final char INTERNAL_TYPE_CLASS_START = 'L';
+ public static final char INTERNAL_TYPE_CLASS_END = ';';
+ public static final char INTERNAL_TYPE_ARRAY = '[';
+ public static final char INTERNAL_TYPE_GENERIC_START = '<';
+ public static final char INTERNAL_TYPE_GENERIC_END = '>';
+
+ public static final String EXTERNAL_TYPE_JAVA_LANG_OBJECT = "java.lang.Object";
+ public static final String EXTERNAL_PACKAGE_JAVA_LANG = "java.lang.";
+
+ public static final String EXTERNAL_TYPE_VOID = "void";
+ public static final String EXTERNAL_TYPE_BOOLEAN = "boolean";
+ public static final String EXTERNAL_TYPE_BYTE = "byte";
+ public static final String EXTERNAL_TYPE_CHAR = "char";
+ public static final String EXTERNAL_TYPE_SHORT = "short";
+ public static final String EXTERNAL_TYPE_INT = "int";
+ public static final String EXTERNAL_TYPE_FLOAT = "float";
+ public static final String EXTERNAL_TYPE_LONG = "long";
+ public static final String EXTERNAL_TYPE_DOUBLE = "double";
+ public static final String EXTERNAL_TYPE_ARRAY = "[]";
+}
diff --git a/src/proguard/classfile/ClassCpInfo.java b/src/proguard/classfile/ClassCpInfo.java
new file mode 100644
index 0000000..3c8c573
--- /dev/null
+++ b/src/proguard/classfile/ClassCpInfo.java
@@ -0,0 +1,123 @@
+/* $Id: ClassCpInfo.java,v 1.20 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a 'class' entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class ClassCpInfo extends CpInfo
+{
+ public int u2nameIndex;
+
+ /**
+ * An extra field pointing to the referenced ClassFile object.
+ * This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ */
+ public ClassFile referencedClassFile;
+
+
+ protected ClassCpInfo()
+ {
+ }
+
+
+ /**
+ * Creates a new ClassCpInfo with the given name index.
+ * @param u2nameIndex the index of the name in the constant pool.
+ * @param referencedClassFile the referenced class file.
+ */
+ public ClassCpInfo(int u2nameIndex,
+ ClassFile referencedClassFile)
+ {
+ this.u2nameIndex = u2nameIndex;
+ this.referencedClassFile = referencedClassFile;
+ }
+
+
+ /**
+ * Returns the name index.
+ */
+ protected int getNameIndex()
+ {
+ return u2nameIndex;
+ }
+
+ /**
+ * Sets the name index.
+ */
+ protected void setNameIndex(int index)
+ {
+ u2nameIndex = index;
+ }
+
+
+ /**
+ * Returns the name.
+ */
+ public String getName(ClassFile classFile)
+ {
+ return classFile.getCpString(u2nameIndex);
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Class;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u2nameIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2nameIndex);
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitClassCpInfo(classFile, this);
+ }
+
+
+ /**
+ * Lets the referenced class file accept the given visitor.
+ */
+ public void referencedClassAccept(ClassFileVisitor classFileVisitor)
+ {
+ if (referencedClassFile != null)
+ {
+ referencedClassFile.accept(classFileVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/ClassFile.java b/src/proguard/classfile/ClassFile.java
new file mode 100644
index 0000000..e9f6b7e
--- /dev/null
+++ b/src/proguard/classfile/ClassFile.java
@@ -0,0 +1,188 @@
+/* $Id: ClassFile.java,v 1.20 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+
+
+/**
+ * This interface provides access to the data in a Java class file (*.class).
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public interface ClassFile extends VisitorAccepter
+{
+ /**
+ * Returns the access flags of this class.
+ * @see ClassConstants
+ */
+ public int getAccessFlags();
+
+ /**
+ * Returns the full internal name of this class.
+ */
+ public String getName();
+
+ /**
+ * Returns the full internal name of the super class of this class, or
+ * null if this class represents java.lang.Object.
+ */
+ public String getSuperName();
+
+ /**
+ * Returns the full internal name of the interface at the given index of
+ * this class.
+ */
+ public String getInterfaceName(int index);
+
+ /**
+ * Returns the tag value of the CpEntry at the specified index.
+ */
+ public int getCpTag(int cpIndex);
+
+ /**
+ * Returns the String value of the Utf8CpEntry at the specified index.
+ */
+ public String getCpString(int cpIndex);
+
+ /**
+ * Returns the class name of ClassCpEntry at the specified index.
+ */
+ public String getCpClassNameString(int cpIndex);
+
+ /**
+ * Returns the name of the NameAndTypeCpEntry at the specified index.
+ */
+ public String getCpNameString(int cpIndex);
+
+ /**
+ * Returns the type of the NameAndTypeCpEntry at the specified index.
+ */
+ public String getCpTypeString(int cpIndex);
+
+
+ // Methods pertaining to related class files.
+
+ /**
+ * Notifies this ClassFile that it is being subclassed by another class.
+ */
+ public void addSubClass(ClassFile classFile);
+
+ /**
+ * Returns the super class of this class.
+ */
+ public ClassFile getSuperClass();
+
+ /**
+ * Returns the interface at the given index.
+ */
+ public ClassFile getInterface(int index);
+
+ /**
+ * Returns whether this class extends the given class.
+ * A class is always considered to extend itself.
+ * Interfaces are considered to only extend the root Object class.
+ */
+ public boolean extends_(ClassFile classFile);
+
+ /**
+ * Returns whether this class implements the given class.
+ * A class is always considered to implement itself.
+ * Interfaces are considered to implement all their superinterfaces.
+ */
+ public boolean implements_(ClassFile classFile);
+
+
+ // Methods for getting specific class members.
+
+ /**
+ * Returns the field with the given name and descriptor.
+ */
+ FieldInfo findField(String name, String descriptor);
+
+ /**
+ * Returns the method with the given name and descriptor.
+ */
+ MethodInfo findMethod(String name, String descriptor);
+
+
+ // Methods for accepting various types of visitors.
+
+ /**
+ * Accepts the given class file visitor.
+ */
+ public void accept(ClassFileVisitor classFileVisitor);
+
+ /**
+ * Accepts the given class file visitor in the class hierarchy.
+ * @param visitThisClass specifies whether to visit this class.
+ * @param visitSuperClass specifies whether to visit the super classes.
+ * @param visitInterfaces specifies whether to visit the interfaces.
+ * @param visitSubclasses specifies whether to visit the subclasses.
+ * @param classFileVisitor the <code>ClassFileVisitor</code> that will
+ * visit the class hierarchy.
+ */
+ public void hierarchyAccept(boolean visitThisClass,
+ boolean visitSuperClass,
+ boolean visitInterfaces,
+ boolean visitSubclasses,
+ ClassFileVisitor classFileVisitor);
+
+ /**
+ * Lets the given constant pool entry visitor visit all constant pool entries
+ * of this class.
+ */
+ public void constantPoolEntriesAccept(CpInfoVisitor cpInfoVisitor);
+
+ /**
+ * Lets the given constant pool entry visitor visit the constant pool entry
+ * at the specified index.
+ */
+ public void constantPoolEntryAccept(int index, CpInfoVisitor cpInfoVisitor);
+
+ /**
+ * Lets the given member info visitor visit all fields of this class.
+ */
+ public void fieldsAccept(MemberInfoVisitor memberInfoVisitor);
+
+ /**
+ * Lets the given member info visitor visit the specified field.
+ */
+ public void fieldAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor);
+
+ /**
+ * Lets the given member info visitor visit all methods of this class.
+ */
+ public void methodsAccept(MemberInfoVisitor memberInfoVisitor);
+
+ /**
+ * Lets the given member info visitor visit the specified method.
+ */
+ public void methodAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor);
+
+ /**
+ * Lets the given attribute info visitor visit all attributes of this class.
+ */
+ public void attributesAccept(AttrInfoVisitor attrInfoVisitor);
+}
diff --git a/src/proguard/classfile/ClassPool.java b/src/proguard/classfile/ClassPool.java
new file mode 100644
index 0000000..e60728e
--- /dev/null
+++ b/src/proguard/classfile/ClassPool.java
@@ -0,0 +1,151 @@
+/* $Id: ClassPool.java,v 1.16 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+import java.util.*;
+
+/**
+ * This is a set of representations of class files. They can be enumerated or
+ * retrieved by name. They can also be accessed by means of class file visitors.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassPool
+{
+ private Map classFiles = new HashMap();
+
+
+ /**
+ * Adds the given ClassFile to the class pool. If a class file of the same
+ * name is already present, it is left unchanged and the old class file is
+ * returned.
+ */
+ public ClassFile addClass(ClassFile classFile)
+ {
+ String name = classFile.getName();
+
+ ClassFile previousClassFile = (ClassFile)classFiles.put(name, classFile);
+ if (previousClassFile != null)
+ {
+ // We'll put the original one back.
+ classFiles.put(name, previousClassFile);
+ }
+
+ return previousClassFile;
+ }
+
+
+ /**
+ * Removes the given ClassFile from the class pool.
+ */
+ public void removeClass(ClassFile classFile)
+ {
+ classFiles.remove(classFile.getName());
+ }
+
+
+ /**
+ * Returns a ClassFile from the class pool based on its name. Returns
+ * <code>null</code> if the class with the given name is not in the class
+ * pool. Returns the base class if the class name is an array type, and the
+ * <code>java.lang.Object</code> class if that base class is a primitive type.
+ */
+ public ClassFile getClass(String className)
+ {
+ return (ClassFile)classFiles.get(ClassUtil.internalClassNameFromType(className));
+ }
+
+
+ /**
+ * Returns an Iterator of all ClassFile objects in the class pool.
+ */
+ public Iterator elements()
+ {
+ return classFiles.values().iterator();
+ }
+
+
+ /**
+ * Returns the number of class files in the class pool.
+ */
+ public int size()
+ {
+ return classFiles.size();
+ }
+
+
+ /**
+ * Applies the given ClassPoolVisitor to the class pool.
+ */
+ public void accept(ClassPoolVisitor classPoolVisitor)
+ {
+ classPoolVisitor.visitClassPool(this);
+ }
+
+
+ /**
+ * Applies the given ClassFileVisitor to all classes in the class pool,
+ * in random order.
+ */
+ public void classFilesAccept(ClassFileVisitor classFileVisitor)
+ {
+ Iterator iterator = elements();
+ while (iterator.hasNext())
+ {
+ ClassFile classFile = (ClassFile)iterator.next();
+ classFile.accept(classFileVisitor);
+ }
+ }
+
+
+ /**
+ * Applies the given ClassFileVisitor to all classes in the class pool,
+ * in sorted order.
+ */
+ public void classFilesAcceptAlphabetically(ClassFileVisitor classFileVisitor)
+ {
+ TreeMap sortedClassFiles = new TreeMap(classFiles);
+ Iterator iterator = sortedClassFiles.values().iterator();
+ while (iterator.hasNext())
+ {
+ ClassFile classFile = (ClassFile)iterator.next();
+ classFile.accept(classFileVisitor);
+ }
+ }
+
+
+ /**
+ * Applies the given ClassFileVisitor to the class with the given name,
+ * if it is present in the class pool.
+ */
+ public void classFileAccept(ClassFileVisitor classFileVisitor, String className)
+ {
+ ClassFile classFile = getClass(className);
+ if (classFile != null)
+ {
+ classFile.accept(classFileVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/CpInfo.java b/src/proguard/classfile/CpInfo.java
new file mode 100644
index 0000000..81c3cbe
--- /dev/null
+++ b/src/proguard/classfile/CpInfo.java
@@ -0,0 +1,166 @@
+/* $Id: CpInfo.java,v 1.22 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of an entry in the ConstantPool. Specific types of entry
+ * have their representations sub-classed from this.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public abstract class CpInfo implements VisitorAccepter
+{
+ // Shared copies of constant pool objects, to avoid creating a lot of objects.
+ private static final IntegerCpInfo integerCpInfo = new IntegerCpInfo();
+ private static final FloatCpInfo floatCpInfo = new FloatCpInfo();
+ private static final LongCpInfo longCpInfo = new LongCpInfo();
+ private static final DoubleCpInfo doubleCpInfo = new DoubleCpInfo();
+ private static final StringCpInfo stringCpInfo = new StringCpInfo();
+ private static final FieldrefCpInfo fieldrefCpInfo = new FieldrefCpInfo();
+ private static final MethodrefCpInfo methodrefCpInfo = new MethodrefCpInfo();
+ private static final InterfaceMethodrefCpInfo interfaceMethodrefCpInfo = new InterfaceMethodrefCpInfo();
+ private static final NameAndTypeCpInfo nameAndTypeCpInfo = new NameAndTypeCpInfo();
+
+
+ //public int u1tag;
+ //public byte info[];
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ /**
+ * Creates a new CpInfo from the data passed.
+ *
+ * @throws IOException if the class file is corrupt or incomplete.
+ */
+ public static CpInfo create(DataInput din) throws IOException
+ {
+ // Instantiate based on tag byte
+ CpInfo cpInfo = null;
+ int u1tag = din.readUnsignedByte();
+ switch (u1tag)
+ {
+ case ClassConstants.CONSTANT_Utf8: cpInfo = new Utf8CpInfo(); break;
+ case ClassConstants.CONSTANT_Integer: cpInfo = new IntegerCpInfo(); break;
+ case ClassConstants.CONSTANT_Float: cpInfo = new FloatCpInfo(); break;
+ case ClassConstants.CONSTANT_Long: cpInfo = new LongCpInfo(); break;
+ case ClassConstants.CONSTANT_Double: cpInfo = new DoubleCpInfo(); break;
+ case ClassConstants.CONSTANT_Class: cpInfo = new ClassCpInfo(); break;
+ case ClassConstants.CONSTANT_String: cpInfo = new StringCpInfo(); break;
+ case ClassConstants.CONSTANT_Fieldref: cpInfo = new FieldrefCpInfo(); break;
+ case ClassConstants.CONSTANT_Methodref: cpInfo = new MethodrefCpInfo(); break;
+ case ClassConstants.CONSTANT_InterfaceMethodref: cpInfo = new InterfaceMethodrefCpInfo();break;
+ case ClassConstants.CONSTANT_NameAndType: cpInfo = new NameAndTypeCpInfo(); break;
+ default: throw new IOException("Unknown constant type ["+u1tag+"] in constant pool");
+ }
+ cpInfo.readInfo(din);
+ return cpInfo;
+ }
+
+
+ /**
+ * Creates a new CpInfo from the data passed, for UTF-8 and Class constant
+ * pool entries, or returns a shared object, for all other entries.
+ *
+ * @throws IOException if the class file is corrupt or incomplete.
+ */
+ public static CpInfo createOrShare(DataInput din) throws IOException
+ {
+ // Instantiate based on tag byte
+ CpInfo cpInfo = null;
+ int u1tag = din.readUnsignedByte();
+ switch (u1tag)
+ {
+ case ClassConstants.CONSTANT_Utf8: cpInfo = new Utf8CpInfo(); break;
+ case ClassConstants.CONSTANT_Integer: cpInfo = integerCpInfo; break;
+ case ClassConstants.CONSTANT_Float: cpInfo = floatCpInfo; break;
+ case ClassConstants.CONSTANT_Long: cpInfo = longCpInfo; break;
+ case ClassConstants.CONSTANT_Double: cpInfo = doubleCpInfo; break;
+ case ClassConstants.CONSTANT_Class: cpInfo = new ClassCpInfo(); break;
+ case ClassConstants.CONSTANT_String: cpInfo = stringCpInfo; break;
+ case ClassConstants.CONSTANT_Fieldref: cpInfo = fieldrefCpInfo; break;
+ case ClassConstants.CONSTANT_Methodref: cpInfo = methodrefCpInfo; break;
+ case ClassConstants.CONSTANT_InterfaceMethodref: cpInfo = interfaceMethodrefCpInfo; break;
+ case ClassConstants.CONSTANT_NameAndType: cpInfo = nameAndTypeCpInfo; break;
+ default: throw new IOException("Unknown constant type ["+u1tag+"] in constant pool");
+ }
+ cpInfo.readInfo(din);
+ return cpInfo;
+ }
+
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public void write(DataOutput dout) throws IOException
+ {
+ dout.writeByte(getTag());
+ writeInfo(dout);
+ }
+
+
+ // Abstract methods to be implemented by extensions.
+
+ /**
+ * Returns the class pool info tag that specifies the entry type.
+ */
+ public abstract int getTag();
+
+
+ /**
+ * Reads the 'info' data following the u1tag byte.
+ */
+ protected abstract void readInfo(DataInput din) throws IOException;
+
+
+ /**
+ * Writes the 'info' data following the u1tag byte.
+ */
+ protected abstract void writeInfo(DataOutput dout) throws IOException;
+
+
+ /**
+ * Accepts the given visitor.
+ */
+ public abstract void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor);
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/DoubleCpInfo.java b/src/proguard/classfile/DoubleCpInfo.java
new file mode 100644
index 0000000..b309649
--- /dev/null
+++ b/src/proguard/classfile/DoubleCpInfo.java
@@ -0,0 +1,97 @@
+/* $Id: DoubleCpInfo.java,v 1.17 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a 'double' entry in the ConstantPool (takes up two indices).
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class DoubleCpInfo extends CpInfo
+{
+ public int u4highBytes;
+ public int u4lowBytes;
+
+
+ /**
+ * Creates a new DoubleCpInfo with the given double value.
+ */
+ public DoubleCpInfo(double value)
+ {
+ setValue(value);
+ }
+
+
+ protected DoubleCpInfo()
+ {
+ }
+
+
+ /**
+ * Returns the double value of this DoubleCpInfo.
+ */
+ public double getValue()
+ {
+ return Double.longBitsToDouble(((long)u4highBytes << 32) | (long)u4lowBytes);
+ }
+
+
+ /**
+ * Sets the double value of this DoubleCpInfo.
+ */
+ public void setValue(double value)
+ {
+ long longValue = Double.doubleToLongBits(value);
+ u4highBytes = (int)(longValue >> 32);
+ u4lowBytes = (int) longValue;
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Double;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u4highBytes = din.readInt();
+ u4lowBytes = din.readInt();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeInt(u4highBytes);
+ dout.writeInt(u4lowBytes);
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitDoubleCpInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/FieldInfo.java b/src/proguard/classfile/FieldInfo.java
new file mode 100644
index 0000000..9c7607b
--- /dev/null
+++ b/src/proguard/classfile/FieldInfo.java
@@ -0,0 +1,33 @@
+/* $Id: FieldInfo.java,v 1.12 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+
+
+/**
+ * Representation of a field from a class file.
+ *
+ * @author Eric Lafortune
+ */
+public interface FieldInfo extends MemberInfo
+{
+}
diff --git a/src/proguard/classfile/FieldrefCpInfo.java b/src/proguard/classfile/FieldrefCpInfo.java
new file mode 100644
index 0000000..1ff608b
--- /dev/null
+++ b/src/proguard/classfile/FieldrefCpInfo.java
@@ -0,0 +1,69 @@
+/* $Id: FieldrefCpInfo.java,v 1.20 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+/**
+ * Representation of a 'field reference' entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class FieldrefCpInfo extends RefCpInfo
+{
+ protected FieldrefCpInfo()
+ {
+ }
+
+
+ /**
+ * Creates a new FieldrefCpInfo with the given name and type indices.
+ * @param u2classIndex the index of the class in the constant pool.
+ * @param u2nameAndTypeIndex the index of the name and type entry in the constant pool.
+ * @param referencedClassFile the referenced class file.
+ * @param referencedMemberInfo the referenced member info.
+ */
+ public FieldrefCpInfo(int u2classIndex,
+ int u2nameAndTypeIndex,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo)
+ {
+ this.u2classIndex = u2classIndex;
+ this.u2nameAndTypeIndex = u2nameAndTypeIndex;
+ this.referencedClassFile = referencedClassFile;
+ this.referencedMemberInfo = referencedMemberInfo;
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Fieldref;
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitFieldrefCpInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/FloatCpInfo.java b/src/proguard/classfile/FloatCpInfo.java
new file mode 100644
index 0000000..2218446
--- /dev/null
+++ b/src/proguard/classfile/FloatCpInfo.java
@@ -0,0 +1,92 @@
+/* $Id: FloatCpInfo.java,v 1.16 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a 'float' entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class FloatCpInfo extends CpInfo
+{
+ public int u4bytes;
+
+
+ /**
+ * Creates a new FloatCpInfo with the given float value.
+ */
+ public FloatCpInfo(float value)
+ {
+ setValue(value);
+ }
+
+
+ protected FloatCpInfo()
+ {
+ }
+
+
+ /**
+ * Returns the float value of this FloatCpInfo.
+ */
+ public float getValue()
+ {
+ return Float.intBitsToFloat(u4bytes);
+ }
+
+
+ /**
+ * Sets the float value of this FloatCpInfo.
+ */
+ public void setValue(float value)
+ {
+ u4bytes = Float.floatToIntBits(value);
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Float;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u4bytes = din.readInt();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeInt(u4bytes);
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitFloatCpInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/IntegerCpInfo.java b/src/proguard/classfile/IntegerCpInfo.java
new file mode 100644
index 0000000..eec5f50
--- /dev/null
+++ b/src/proguard/classfile/IntegerCpInfo.java
@@ -0,0 +1,92 @@
+/* $Id: IntegerCpInfo.java,v 1.16 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a 'integer' entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class IntegerCpInfo extends CpInfo
+{
+ public int u4bytes;
+
+
+ /**
+ * Creates a new IntegerCpInfo with the given integer value.
+ */
+ public IntegerCpInfo(int value)
+ {
+ setValue(value);
+ }
+
+
+ protected IntegerCpInfo()
+ {
+ }
+
+
+ /**
+ * Returns the integer value of this IntegerCpInfo.
+ */
+ public int getValue()
+ {
+ return u4bytes;
+ }
+
+
+ /**
+ * Sets the integer value of this IntegerCpInfo.
+ */
+ public void setValue(int value)
+ {
+ u4bytes = value;
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Integer;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u4bytes = din.readInt();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeInt(u4bytes);
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitIntegerCpInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/InterfaceMethodrefCpInfo.java b/src/proguard/classfile/InterfaceMethodrefCpInfo.java
new file mode 100644
index 0000000..a9c229b
--- /dev/null
+++ b/src/proguard/classfile/InterfaceMethodrefCpInfo.java
@@ -0,0 +1,69 @@
+/* $Id: InterfaceMethodrefCpInfo.java,v 1.20 2004/11/07 18:49:09 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+/**
+ * Representation of a 'interface method reference' entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class InterfaceMethodrefCpInfo extends RefCpInfo
+{
+ protected InterfaceMethodrefCpInfo()
+ {
+ }
+
+
+ /**
+ * Creates a new InterfaceMethodrefCpInfo with the given name and type indices.
+ * @param u2classIndex the index of the class in the constant pool.
+ * @param u2nameAndTypeIndex the index of the name and type entry in the constant pool.
+ * @param referencedClassFile the referenced class file.
+ * @param referencedMemberInfo the referenced member info.
+ */
+ public InterfaceMethodrefCpInfo(int u2classIndex,
+ int u2nameAndTypeIndex,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo)
+ {
+ this.u2classIndex = u2classIndex;
+ this.u2nameAndTypeIndex = u2nameAndTypeIndex;
+ this.referencedClassFile = referencedClassFile;
+ this.referencedMemberInfo = referencedMemberInfo;
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_InterfaceMethodref;
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitInterfaceMethodrefCpInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/LibraryClassFile.java b/src/proguard/classfile/LibraryClassFile.java
new file mode 100644
index 0000000..1f6af92
--- /dev/null
+++ b/src/proguard/classfile/LibraryClassFile.java
@@ -0,0 +1,586 @@
+/* $Id: LibraryClassFile.java,v 1.35 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+
+import java.io.*;
+
+/**
+ * This is a compact representation of the essential data in a Java class file.
+ * A LibraryClassFile instance representing a *.class file can be generated
+ * using the static create(DataInput) method, but not persisted back.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LibraryClassFile implements ClassFile
+{
+ // Some objects and arrays that can be reused.
+ private static LibraryClassFile reusableLibraryClassFile;
+ private static CpInfo[] reusableConstantPool;
+ private static LibraryFieldInfo[] reusableFields;
+ private static LibraryMethodInfo[] reusableMethods;
+
+
+ public int u2accessFlags;
+ public String thisClassName;
+ public String superClassName;
+ public String[] interfaceNames;
+ public LibraryFieldInfo[] fields;
+ public LibraryMethodInfo[] methods;
+
+ /**
+ * An extra field pointing to the superclass of this class.
+ * This field is filled out by the <code>{@link ClassFileReferenceInitializer}</code>.
+ */
+ public ClassFile superClass = null;
+
+ /**
+ * An extra field pointing to the interfaces of this class.
+ * This field is filled out by the <code>{@link ClassFileReferenceInitializer}</code>.
+ */
+ public ClassFile[] interfaceClasses = null;
+
+ /**
+ * An extra field pointing to the subclasses of this class.
+ * This field is filled out by the <code>{@link ClassFileReferenceInitializer}</code>.
+ */
+ public ClassFile[] subClasses = null;
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ /**
+ * Creates a new LibraryClassFile from the class file format data in the DataInput
+ * stream. If specified, this method may return <code>null</code> if the
+ * class file is not visible.
+ *
+ * @throws IOException if the class file is corrupt or incomplete
+ */
+ public static LibraryClassFile create(DataInput din,
+ boolean skipNonPublicClasses,
+ boolean skipNonPublicClassMembers)
+ throws IOException
+ {
+ // See if we have to create a new library class file object.
+ if (reusableLibraryClassFile == null)
+ {
+ reusableLibraryClassFile = new LibraryClassFile();
+ }
+
+ // We'll start using the reusable object.
+ LibraryClassFile libraryClassFile = reusableLibraryClassFile;
+
+ libraryClassFile.read(din, skipNonPublicClasses, skipNonPublicClassMembers);
+
+ // Did we actually read a useful library class file?
+ if (libraryClassFile.thisClassName != null)
+ {
+ // We can't reuse this library class file object next time.
+ reusableLibraryClassFile = null;
+ }
+ else
+ {
+ // We don't have a useful library class file to return.
+ libraryClassFile = null;
+ }
+
+ return libraryClassFile;
+ }
+
+
+ /**
+ * Creates an empty LibraryClassFile.
+ */
+ private LibraryClassFile() {}
+
+
+ /**
+ * Imports the class data into this LibraryClassFile.
+ */
+ private void read(DataInput din,
+ boolean skipNonPublicClasses,
+ boolean skipNonPublicClassmembers) throws IOException
+ {
+ // Read and check the class file magic number.
+ int u4magic = din.readInt();
+ ClassUtil.checkMagicNumber(u4magic);
+
+ // Read and check the class file version numbers.
+ int u2minorVersion = din.readUnsignedShort();
+ int u2majorVersion = din.readUnsignedShort();
+ ClassUtil.checkVersionNumbers(u2majorVersion, u2minorVersion);
+
+ // Read the constant pool.
+ int u2constantPoolCount = din.readUnsignedShort();
+
+ // Make sure there's sufficient space in the reused constant pool array.
+ if (reusableConstantPool == null ||
+ reusableConstantPool.length < u2constantPoolCount)
+ {
+ reusableConstantPool = new CpInfo[u2constantPoolCount];
+ }
+
+ // Fill the constant pool. The zero entry is not used, nor are the
+ // entries following a Long or Double.
+ for (int i = 1; i < u2constantPoolCount; i++)
+ {
+ reusableConstantPool[i] = CpInfo.createOrShare(din);
+ int tag = reusableConstantPool[i].getTag();
+ if (tag == ClassConstants.CONSTANT_Long ||
+ tag == ClassConstants.CONSTANT_Double)
+ {
+ i++;
+ }
+ }
+
+ u2accessFlags = din.readUnsignedShort();
+
+ // We may stop parsing this library class file if it's not public anyway.
+ // E.g. only about 60% of all rt.jar classes need to be parsed.
+ if (skipNonPublicClasses && !isVisible())
+ {
+ return;
+ }
+
+ // Read the class and super class indices.
+ int u2thisClass = din.readUnsignedShort();
+ int u2superClass = din.readUnsignedShort();
+
+ // Store their actual names.
+ thisClassName = toName(reusableConstantPool, u2thisClass);
+ superClassName = (u2superClass == 0) ? null :
+ toName(reusableConstantPool, u2superClass);
+
+ // Read the interface indices.
+ int u2interfacesCount = din.readUnsignedShort();
+
+ // Store their actual names.
+ interfaceNames = new String[u2interfacesCount];
+ for (int i = 0; i < u2interfacesCount; i++)
+ {
+ int u2interface = din.readUnsignedShort();
+ interfaceNames[i] = toName(reusableConstantPool, u2interface);
+ }
+
+ // Read the fields.
+ int u2fieldsCount = din.readUnsignedShort();
+
+ // Make sure there's sufficient space in the reused fields array.
+ if (reusableFields == null ||
+ reusableFields.length < u2fieldsCount)
+ {
+ reusableFields = new LibraryFieldInfo[u2fieldsCount];
+ }
+
+ int visibleFieldsCount = 0;
+ for (int i = 0; i < u2fieldsCount; i++)
+ {
+ LibraryFieldInfo field = LibraryFieldInfo.create(din, reusableConstantPool);
+
+ // Only store fields that are visible.
+ if (field.isVisible() ||
+ (!skipNonPublicClassmembers &&
+ (field.getAccessFlags() & ClassConstants.INTERNAL_ACC_PRIVATE) == 0))
+ {
+ reusableFields[visibleFieldsCount++] = field;
+ }
+ }
+
+ // Copy the visible fields into a fields array of the right size.
+ fields = new LibraryFieldInfo[visibleFieldsCount];
+ System.arraycopy(reusableFields, 0, fields, 0, visibleFieldsCount);
+
+
+ // Read the methods.
+ int u2methodsCount = din.readUnsignedShort();
+
+ // Make sure there's sufficient space in the reused methods array.
+ if (reusableMethods == null ||
+ reusableMethods.length < u2methodsCount)
+ {
+ reusableMethods = new LibraryMethodInfo[u2methodsCount];
+ }
+
+ int visibleMethodsCount = 0;
+ for (int i = 0; i < u2methodsCount; i++)
+ {
+ LibraryMethodInfo method = LibraryMethodInfo.create(din, reusableConstantPool);
+
+ // Only store methods that are visible.
+ if (method.isVisible() ||
+ (!skipNonPublicClasses &&
+ (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_PRIVATE) == 0))
+ {
+ reusableMethods[visibleMethodsCount++] = method;
+ }
+ }
+
+ // Copy the visible methods into a methods array of the right size.
+ methods = new LibraryMethodInfo[visibleMethodsCount];
+ System.arraycopy(reusableMethods, 0, methods, 0, visibleMethodsCount);
+
+
+ // Skip the attributes.
+ int u2attributesCount = din.readUnsignedShort();
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ LibraryAttrInfo.skip(din);
+ }
+ }
+
+
+ /**
+ * Returns whether this library class file is visible to the outside world.
+ */
+ boolean isVisible()
+ {
+ return (u2accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0;
+ }
+
+
+ /**
+ * Returns the class name of the ClassCpInfo at the specified index in the
+ * given constant pool.
+ */
+ private String toName(CpInfo[] constantPool, int cpIndex)
+ {
+ ClassCpInfo classEntry = (ClassCpInfo)constantPool[cpIndex];
+ Utf8CpInfo nameEntry = (Utf8CpInfo)constantPool[classEntry.getNameIndex()];
+
+ return nameEntry.getString();
+ }
+
+
+ /**
+ * Returns the field with the given name and descriptor.
+ */
+ private LibraryFieldInfo findLibraryField(String name, String descriptor)
+ {
+ for (int i = 0; i < fields.length; i++)
+ {
+ LibraryFieldInfo field = fields[i];
+ if (field != null &&
+ (name == null || field.getName(this).equals(name)) &&
+ (descriptor == null || field.getDescriptor(this).equals(descriptor)))
+ {
+ return field;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Returns the method with the given name and descriptor.
+ */
+ private LibraryMethodInfo findLibraryMethod(String name, String descriptor)
+ {
+ for (int i = 0; i < methods.length; i++)
+ {
+ LibraryMethodInfo method = methods[i];
+ if (method != null &&
+ (name == null || method.getName(this).equals(name)) &&
+ (descriptor == null || method.getDescriptor(this).equals(descriptor)))
+ {
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+
+ // Implementations for ClassFile.
+
+ public int getAccessFlags()
+ {
+ return u2accessFlags;
+ }
+
+ public String getName()
+ {
+ return thisClassName;
+ }
+
+ public String getSuperName()
+ {
+ // This may be java/lang/Object, in which case there is no super.
+ return superClassName;
+ }
+
+ public String getInterfaceName(int index)
+ {
+ return interfaceNames[index];
+ }
+
+ public int getCpTag(int cpIndex)
+ {
+ return -1;
+ }
+
+ public String getCpString(int cpIndex)
+ {
+ return null;
+ }
+
+ public String getCpClassNameString(int cpIndex)
+ {
+ return null;
+ }
+
+ public String getCpNameString(int cpIndex)
+ {
+ return null;
+ }
+
+ public String getCpTypeString(int cpIndex)
+ {
+ return null;
+ }
+
+
+ public void addSubClass(ClassFile classFile)
+ {
+ if (subClasses == null)
+ {
+ subClasses = new ClassFile[1];
+ }
+ else
+ {
+ // Copy the old elements into new larger array.
+ ClassFile[] temp = new ClassFile[subClasses.length+1];
+ System.arraycopy(subClasses, 0, temp, 0, subClasses.length);
+ subClasses = temp;
+ }
+
+ subClasses[subClasses.length-1] = classFile;
+ }
+
+
+ public ClassFile getSuperClass()
+ {
+ return superClass;
+ }
+
+
+ public ClassFile getInterface(int index)
+ {
+ return interfaceClasses[index];
+ }
+
+
+ public boolean extends_(ClassFile classFile)
+ {
+ if (this.equals(classFile))
+ {
+ return true;
+ }
+
+ ClassFile superClass = getSuperClass();
+ return superClass != null &&
+ superClass.extends_(classFile);
+ }
+
+
+ public boolean implements_(ClassFile classFile)
+ {
+ if (this.equals(classFile))
+ {
+ return true;
+ }
+
+ if (interfaceClasses != null)
+ {
+ for (int i = 0; i < interfaceClasses.length; i++)
+ {
+ ClassFile interfaceClass = getInterface(i);
+ if (interfaceClass != null &&
+ interfaceClass.implements_(classFile))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ public FieldInfo findField(String name, String descriptor)
+ {
+ return findLibraryField(name, descriptor);
+ }
+
+
+ public MethodInfo findMethod(String name, String descriptor)
+ {
+ return findLibraryMethod(name, descriptor);
+ }
+
+
+ public void accept(ClassFileVisitor classFileVisitor)
+ {
+ classFileVisitor.visitLibraryClassFile(this);
+ }
+
+
+ public void hierarchyAccept(boolean visitThisClass,
+ boolean visitSuperClass,
+ boolean visitInterfaces,
+ boolean visitSubclasses,
+ ClassFileVisitor classFileVisitor)
+ {
+ // First visit the current classfile.
+ if (visitThisClass)
+ {
+ accept(classFileVisitor);
+ }
+
+ // Then visit its superclass, recursively.
+ if (visitSuperClass)
+ {
+ if (superClass != null)
+ {
+ superClass.hierarchyAccept(true,
+ true,
+ visitInterfaces,
+ false,
+ classFileVisitor);
+ }
+ }
+
+ // Then visit its interfaces, recursively.
+ if (visitInterfaces)
+ {
+ if (interfaceClasses != null)
+ {
+ for (int i = 0; i < interfaceClasses.length; i++)
+ {
+ ClassFile interfaceClass = getInterface(i);
+ if (interfaceClass != null)
+ {
+ interfaceClass.hierarchyAccept(true,
+ true,
+ true,
+ false,
+ classFileVisitor);
+ }
+ }
+ }
+ }
+
+ // Then visit its subclasses, recursively.
+ if (visitSubclasses)
+ {
+ if (subClasses != null)
+ {
+ for (int i = 0; i < subClasses.length; i++)
+ {
+ ClassFile subClass = subClasses[i];
+ subClass.hierarchyAccept(true,
+ false,
+ false,
+ true,
+ classFileVisitor);
+ }
+ }
+ }
+ }
+
+
+ public void constantPoolEntriesAccept(CpInfoVisitor cpInfoVisitor)
+ {
+ // This class doesn't keep references to its constant pool entries.
+ }
+
+ public void constantPoolEntryAccept(int index, CpInfoVisitor cpInfoVisitor)
+ {
+ // This class doesn't keep references to its constant pool entries.
+ }
+
+ public void fieldsAccept(MemberInfoVisitor memberInfoVisitor)
+ {
+ for (int i = 0; i < fields.length; i++)
+ {
+ if (fields[i] != null)
+ {
+ fields[i].accept(this, memberInfoVisitor);
+ }
+ }
+ }
+
+ public void fieldAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor)
+ {
+ LibraryMemberInfo libraryMemberInfo = findLibraryField(name, descriptor);
+ if (libraryMemberInfo != null)
+ {
+ libraryMemberInfo.accept(this, memberInfoVisitor);
+ }
+ }
+
+ public void methodsAccept(MemberInfoVisitor memberInfoVisitor)
+ {
+ for (int i = 0; i < methods.length; i++)
+ {
+ if (methods[i] != null)
+ {
+ methods[i].accept(this, memberInfoVisitor);
+ }
+ }
+ }
+
+ public void methodAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor)
+ {
+ LibraryMemberInfo libraryMemberInfo = findLibraryMethod(name, descriptor);
+ if (libraryMemberInfo != null)
+ {
+ libraryMemberInfo.accept(this, memberInfoVisitor);
+ }
+ }
+
+ public void attributesAccept(AttrInfoVisitor attrInfoVisitor)
+ {
+ // This class doesn't keep references to its attributes.
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/LibraryFieldInfo.java b/src/proguard/classfile/LibraryFieldInfo.java
new file mode 100644
index 0000000..f7f0472
--- /dev/null
+++ b/src/proguard/classfile/LibraryFieldInfo.java
@@ -0,0 +1,60 @@
+/* $Id: LibraryFieldInfo.java,v 1.14 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a field from a class-file.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LibraryFieldInfo extends LibraryMemberInfo implements FieldInfo
+{
+
+
+ /**
+ * Creates a new LibraryFieldInfo from the file format data in the DataInput stream.
+ *
+ * @throws IOException if class file is corrupt or incomplete
+ */
+ public static LibraryFieldInfo create(DataInput din, CpInfo[] constantPool) throws IOException
+ {
+ LibraryFieldInfo fi = new LibraryFieldInfo();
+ fi.read(din, constantPool);
+ return fi;
+ }
+
+ /**
+ * Accepts the given visitor.
+ */
+ public void accept(LibraryClassFile libraryClassFile, MemberInfoVisitor memberInfoVisitor)
+ {
+ memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, this);
+ }
+
+
+ protected LibraryFieldInfo() {}
+}
diff --git a/src/proguard/classfile/LibraryMemberInfo.java b/src/proguard/classfile/LibraryMemberInfo.java
new file mode 100644
index 0000000..c52b2c2
--- /dev/null
+++ b/src/proguard/classfile/LibraryMemberInfo.java
@@ -0,0 +1,129 @@
+/* $Id: LibraryMemberInfo.java,v 1.21 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+
+import java.io.*;
+
+/**
+ * Representation of a field or method from a library class file.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+abstract public class LibraryMemberInfo implements MemberInfo
+{
+ private static final int ACC_VISIBLE = ClassConstants.INTERNAL_ACC_PUBLIC |
+ ClassConstants.INTERNAL_ACC_PROTECTED;
+
+
+ public int u2accessFlags;
+ public String name;
+ public String descriptor;
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ protected LibraryMemberInfo() {}
+
+
+ /**
+ * Accepts the given member info visitor.
+ */
+ public abstract void accept(LibraryClassFile libraryClassFile,
+ MemberInfoVisitor memberInfoVisitor);
+
+
+ /**
+ * Imports the field or method data to internal representation.
+ */
+ protected void read(DataInput din, CpInfo[] constantPool) throws IOException
+ {
+ // Read the access flags.
+ u2accessFlags = din.readUnsignedShort();
+
+ // Read the name and descriptor indices.
+ int u2nameIndex = din.readUnsignedShort();
+ int u2descriptorIndex = din.readUnsignedShort();
+
+ // Store the actual name and descriptor.
+ name = ((Utf8CpInfo)constantPool[u2nameIndex]).getString();
+ descriptor = ((Utf8CpInfo)constantPool[u2descriptorIndex]).getString();
+
+ // Skip the attributes.
+ int u2attributesCount = din.readUnsignedShort();
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ LibraryAttrInfo.skip(din);
+ }
+ }
+
+
+ /**
+ * Returns whether this library member is visible to the outside world.
+ */
+ boolean isVisible()
+ {
+ return (u2accessFlags & ACC_VISIBLE) != 0;
+ }
+
+
+ // Implementations for MemberInfo.
+
+ public int getAccessFlags()
+ {
+ return u2accessFlags;
+ }
+
+ public String getName(ClassFile classFile)
+ {
+ return name;
+ }
+
+ public String getDescriptor(ClassFile classFile)
+ {
+ return descriptor;
+ }
+
+ public void accept(ClassFile classFile, MemberInfoVisitor memberInfoVisitor)
+ {
+ accept((LibraryClassFile)classFile, memberInfoVisitor);
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/LibraryMethodInfo.java b/src/proguard/classfile/LibraryMethodInfo.java
new file mode 100644
index 0000000..00e4242
--- /dev/null
+++ b/src/proguard/classfile/LibraryMethodInfo.java
@@ -0,0 +1,60 @@
+/* $Id: LibraryMethodInfo.java,v 1.14 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a method from a class-file.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LibraryMethodInfo extends LibraryMemberInfo implements MethodInfo
+{
+
+
+ /**
+ * Creates a new LibraryMethodInfo from the file format data in the DataInput stream.
+ *
+ * @throws IOException if class file is corrupt or incomplete
+ */
+ public static LibraryMethodInfo create(DataInput din, CpInfo[] constantPool) throws IOException
+ {
+ LibraryMethodInfo mi = new LibraryMethodInfo();
+ mi.read(din, constantPool);
+ return mi;
+ }
+
+ /**
+ * Accepts the given visitor.
+ */
+ public void accept(LibraryClassFile libraryClassFile, MemberInfoVisitor memberInfoVisitor)
+ {
+ memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, this);
+ }
+
+
+ protected LibraryMethodInfo() {}
+}
diff --git a/src/proguard/classfile/LongCpInfo.java b/src/proguard/classfile/LongCpInfo.java
new file mode 100644
index 0000000..9935962
--- /dev/null
+++ b/src/proguard/classfile/LongCpInfo.java
@@ -0,0 +1,96 @@
+/* $Id: LongCpInfo.java,v 1.16 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a 'long' entry in the ConstantPool (takes up two indices).
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LongCpInfo extends CpInfo
+{
+ public int u4highBytes;
+ public int u4lowBytes;
+
+
+ /**
+ * Creates a new LongCpInfo with the given long value.
+ */
+ public LongCpInfo(long value)
+ {
+ setValue(value);
+ }
+
+
+ protected LongCpInfo()
+ {
+ }
+
+
+ /**
+ * Returns the long value of this LongCpInfo.
+ */
+ public long getValue()
+ {
+ return (long)u4highBytes << 32 | (long)u4lowBytes;
+ }
+
+
+ /**
+ * Sets the long value of this LongCpInfo.
+ */
+ public void setValue(long value)
+ {
+ u4highBytes = (int)(value >> 32);
+ u4lowBytes = (int) value;
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Long;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u4highBytes = din.readInt();
+ u4lowBytes = din.readInt();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeInt(u4highBytes);
+ dout.writeInt(u4lowBytes);
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitLongCpInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/MemberInfo.java b/src/proguard/classfile/MemberInfo.java
new file mode 100644
index 0000000..420f5c2
--- /dev/null
+++ b/src/proguard/classfile/MemberInfo.java
@@ -0,0 +1,53 @@
+/* $Id: MemberInfo.java,v 1.19 2004/10/23 16:53:00 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.MemberInfoVisitor;
+
+/**
+ * Representation of a field or method from a program class file.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public interface MemberInfo extends VisitorAccepter
+{
+ /**
+ * Returns access flags.
+ */
+ public int getAccessFlags();
+
+ /**
+ * Returns method/field string name.
+ */
+ public String getName(ClassFile classFile);
+
+ /**
+ * Returns descriptor string.
+ */
+ public String getDescriptor(ClassFile classFile);
+
+ /**
+ * Accepts the given class file visitor.
+ */
+ public void accept(ClassFile classFile, MemberInfoVisitor memberInfoVisitor);
+}
diff --git a/src/proguard/classfile/MethodInfo.java b/src/proguard/classfile/MethodInfo.java
new file mode 100644
index 0000000..c0bde5a
--- /dev/null
+++ b/src/proguard/classfile/MethodInfo.java
@@ -0,0 +1,33 @@
+/* $Id: MethodInfo.java,v 1.12 2004/10/23 16:53:01 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+
+
+/**
+ * Representation of a method from a class file.
+ *
+ * @author Eric Lafortune
+ */
+public interface MethodInfo extends MemberInfo
+{
+}
diff --git a/src/proguard/classfile/MethodrefCpInfo.java b/src/proguard/classfile/MethodrefCpInfo.java
new file mode 100644
index 0000000..4c317fc
--- /dev/null
+++ b/src/proguard/classfile/MethodrefCpInfo.java
@@ -0,0 +1,69 @@
+/* $Id: MethodrefCpInfo.java,v 1.20 2004/10/23 16:53:01 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+/**
+ * Representation of a 'method reference' entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class MethodrefCpInfo extends RefCpInfo
+{
+ protected MethodrefCpInfo()
+ {
+ }
+
+
+ /**
+ * Creates a new MethodrefCpInfo with the given name and type indices.
+ * @param u2classIndex the index of the class in the constant pool.
+ * @param u2nameAndTypeIndex the index of the name and type entry in the constant pool.
+ * @param referencedClassFile the referenced class file.
+ * @param referencedMemberInfo the referenced member info.
+ */
+ public MethodrefCpInfo(int u2classIndex,
+ int u2nameAndTypeIndex,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo)
+ {
+ this.u2classIndex = u2classIndex;
+ this.u2nameAndTypeIndex = u2nameAndTypeIndex;
+ this.referencedClassFile = referencedClassFile;
+ this.referencedMemberInfo = referencedMemberInfo;
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Methodref;
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitMethodrefCpInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/NameAndTypeCpInfo.java b/src/proguard/classfile/NameAndTypeCpInfo.java
new file mode 100644
index 0000000..b10404d
--- /dev/null
+++ b/src/proguard/classfile/NameAndTypeCpInfo.java
@@ -0,0 +1,162 @@
+/* $Id: NameAndTypeCpInfo.java,v 1.19 2004/10/23 16:53:01 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a 'name and type' entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class NameAndTypeCpInfo extends CpInfo implements Cloneable
+{
+ public int u2nameIndex;
+ public int u2descriptorIndex;
+
+ /**
+ * An extra field pointing to the ClassFile objects referenced in the
+ * descriptor string. This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ * References to primitive types are ignored.
+ */
+ public ClassFile[] referencedClassFiles;
+
+
+ protected NameAndTypeCpInfo()
+ {
+ }
+
+
+ /**
+ * Creates a new NameAndTypeCpInfo with the given name and type indices.
+ * @param u2nameIndex the index of the name in the constant pool.
+ * @param u2descriptorIndex the index of the descriptor in the constant
+ * pool.
+ * @param referencedClassFiles the list of class files referenced in the
+ * descriptor string.
+ */
+ public NameAndTypeCpInfo(int u2nameIndex,
+ int u2descriptorIndex,
+ ClassFile[] referencedClassFiles)
+ {
+ this.u2nameIndex = u2nameIndex;
+ this.u2descriptorIndex = u2descriptorIndex;
+ this.referencedClassFiles = referencedClassFiles;
+ }
+
+
+ /**
+ * Returns the name index.
+ */
+ protected int getNameIndex()
+ {
+ return u2nameIndex;
+ }
+
+ /**
+ * Sets the name index.
+ */
+ protected void setNameIndex(int index)
+ {
+ u2nameIndex = index;
+ }
+
+ /**
+ * Returns the descriptor index.
+ */
+ protected int getDescriptorIndex()
+ {
+ return u2descriptorIndex;
+ }
+
+ /**
+ * Sets the descriptor index.
+ */
+ protected void setDescriptorIndex(int index)
+ {
+ u2descriptorIndex = index;
+ }
+
+ /**
+ * Returns the name.
+ */
+ public String getName(ClassFile classFile)
+ {
+ return classFile.getCpString(u2nameIndex);
+ }
+
+ /**
+ * Returns the type.
+ */
+ public String getType(ClassFile classFile)
+ {
+ return classFile.getCpString(u2descriptorIndex);
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_NameAndType;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u2nameIndex = din.readUnsignedShort();
+ u2descriptorIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2nameIndex);
+ dout.writeShort(u2descriptorIndex);
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitNameAndTypeCpInfo(classFile, this);
+ }
+
+
+ /**
+ * Lets the ClassFile objects referenced in the descriptor string
+ * accept the given visitor.
+ */
+ public void referencedClassesAccept(ClassFileVisitor classFileVisitor)
+ {
+ if (referencedClassFiles != null)
+ {
+ for (int i = 0; i < referencedClassFiles.length; i++)
+ {
+ if (referencedClassFiles[i] != null)
+ {
+ referencedClassFiles[i].accept(classFileVisitor);
+ }
+ }
+ }
+ }
+}
diff --git a/src/proguard/classfile/ProgramClassFile.java b/src/proguard/classfile/ProgramClassFile.java
new file mode 100644
index 0000000..54d1a19
--- /dev/null
+++ b/src/proguard/classfile/ProgramClassFile.java
@@ -0,0 +1,537 @@
+/* $Id: ProgramClassFile.java,v 1.32 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+
+import java.io.*;
+
+/**
+ * This is a complete representation of the data in a Java class file.
+ * A ClassFile instance can be generated using the static create(DataInput)
+ * method, manipulated using various operators, and persisted back using the
+ * write(DataOutput) method.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class ProgramClassFile implements ClassFile
+{
+ public int u4magic;
+ public int u2minorVersion;
+ public int u2majorVersion;
+ public int u2constantPoolCount;
+ public CpInfo[] constantPool;
+ public int u2accessFlags;
+ public int u2thisClass;
+ public int u2superClass;
+ public int u2interfacesCount;
+ public int[] u2interfaces;
+ public int u2fieldsCount;
+ public ProgramFieldInfo[] fields;
+ public int u2methodsCount;
+ public ProgramMethodInfo[] methods;
+ public int u2attributesCount;
+ public AttrInfo[] attributes;
+
+ /**
+ * An extra field pointing to the subclasses of this class.
+ * This field is filled out by the <code>{@link ClassFileReferenceInitializer}</code>.
+ */
+ public ClassFile[] subClasses = null;
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ /**
+ * Creates a new ClassFile from the class file format data in the DataInput
+ * stream.
+ *
+ * @throws IOException if class file is corrupt or incomplete
+ */
+ public static ClassFile create(DataInput din) throws IOException
+ {
+ ProgramClassFile cf = new ProgramClassFile();
+ cf.read(din);
+ return cf;
+ }
+
+
+ /**
+ * Creates an empty ProgramClassFile.
+ */
+ private ProgramClassFile() {}
+
+
+ /**
+ * Imports the class data into this ProgramClassFile.
+ */
+ private void read(DataInput din) throws IOException
+ {
+ // Read and check the class file magic number.
+ u4magic = din.readInt();
+ ClassUtil.checkMagicNumber(u4magic);
+
+ // Read and check the class file version numbers.
+ u2minorVersion = din.readUnsignedShort();
+ u2majorVersion = din.readUnsignedShort();
+ ClassUtil.checkVersionNumbers(u2majorVersion, u2minorVersion);
+
+ // Read the constant pool.
+ u2constantPoolCount = din.readUnsignedShort();
+ constantPool = new CpInfo[u2constantPoolCount];
+
+ // Fill the constant pool. The zero entry is not used, nor are the
+ // entries following a Long or Double.
+ for (int i = 1; i < u2constantPoolCount; i++)
+ {
+ constantPool[i] = CpInfo.create(din);
+
+ int tag = constantPool[i].getTag();
+ if (tag == ClassConstants.CONSTANT_Long ||
+ tag == ClassConstants.CONSTANT_Double)
+ {
+ i++;
+ }
+ }
+
+ // Read the access flags, class name, and super class name.
+ u2accessFlags = din.readUnsignedShort();
+ u2thisClass = din.readUnsignedShort();
+ u2superClass = din.readUnsignedShort();
+
+ // Read the interfaces.
+ u2interfacesCount = din.readUnsignedShort();
+ u2interfaces = new int[u2interfacesCount];
+ for (int i = 0; i < u2interfacesCount; i++)
+ {
+ u2interfaces[i] = din.readUnsignedShort();
+ }
+
+ // Read the fields.
+ u2fieldsCount = din.readUnsignedShort();
+ fields = new ProgramFieldInfo[u2fieldsCount];
+ for (int i = 0; i < u2fieldsCount; i++)
+ {
+ fields[i] = ProgramFieldInfo.create(din, this);
+ }
+
+ // Read the methods.
+ u2methodsCount = din.readUnsignedShort();
+ methods = new ProgramMethodInfo[u2methodsCount];
+ for (int i = 0; i < u2methodsCount; i++)
+ {
+ methods[i] = ProgramMethodInfo.create(din, this);
+ }
+
+ // Read the attributes.
+ u2attributesCount = din.readUnsignedShort();
+ attributes = new AttrInfo[u2attributesCount];
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i] = AttrInfo.create(din, this);
+ }
+ }
+
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public void write(DataOutput dout) throws IOException
+ {
+ dout.writeInt(u4magic);
+ dout.writeShort(u2minorVersion);
+ dout.writeShort(u2majorVersion);
+ dout.writeShort(u2constantPoolCount);
+ for (int i = 1; i < u2constantPoolCount; i++)
+ {
+ CpInfo cpInfo = constantPool[i];
+ if (cpInfo != null)
+ {
+ cpInfo.write(dout);
+ }
+ }
+ dout.writeShort(u2accessFlags);
+ dout.writeShort(u2thisClass);
+ dout.writeShort(u2superClass);
+ dout.writeShort(u2interfacesCount);
+ for (int i = 0; i < u2interfacesCount; i++)
+ {
+ dout.writeShort(u2interfaces[i]);
+ }
+ dout.writeShort(u2fieldsCount);
+ for (int i = 0; i < u2fieldsCount; i++)
+ {
+ fields[i].write(dout);
+ }
+ dout.writeShort(u2methodsCount);
+ for (int i = 0; i < u2methodsCount; i++)
+ {
+ methods[i].write(dout);
+ }
+ dout.writeShort(u2attributesCount);
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i].write(dout);
+ }
+ }
+
+
+ /**
+ * Returns the CpInfo at the given index in the constant pool.
+ */
+ public CpInfo getCpEntry(int cpIndex)
+ {
+ return constantPool[cpIndex];
+ }
+
+
+ /**
+ * Returns the field with the given name and descriptor.
+ */
+ ProgramFieldInfo findProgramField(String name, String descriptor)
+ {
+ for (int i = 0; i < u2fieldsCount; i++)
+ {
+ ProgramFieldInfo field = fields[i];
+ if ((name == null || field.getName(this).equals(name)) &&
+ (descriptor == null || field.getDescriptor(this).equals(descriptor)))
+ {
+ return field;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Returns the method with the given name and descriptor.
+ */
+ ProgramMethodInfo findProgramMethod(String name, String descriptor)
+ {
+ for (int i = 0; i < u2methodsCount; i++)
+ {
+ ProgramMethodInfo method = methods[i];
+ if ((name == null || method.getName(this).equals(name)) &&
+ (descriptor == null || method.getDescriptor(this).equals(descriptor)))
+ {
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Returns the attribute specified by the given name.
+ */
+ AttrInfo getAttribute(String name)
+ {
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ AttrInfo attribute = attributes[i];
+ if (attribute.getAttributeName(this).equals(name))
+ {
+ return attribute;
+ }
+ }
+
+ return null;
+ }
+
+
+ // Implementations for ClassFile.
+
+ public int getAccessFlags()
+ {
+ return u2accessFlags;
+ }
+
+ public String getName()
+ {
+ return getCpClassNameString(u2thisClass);
+ }
+
+ public String getSuperName()
+ {
+ return u2superClass == 0 ? null : getCpClassNameString(u2superClass);
+ }
+
+ public String getInterfaceName(int index)
+ {
+ return getCpClassNameString(u2interfaces[index]);
+ }
+
+ public int getCpTag(int cpIndex)
+ {
+ return constantPool[cpIndex].getTag();
+ }
+
+ public String getCpString(int cpIndex)
+ {
+ return ((Utf8CpInfo)constantPool[cpIndex]).getString();
+ }
+
+ public String getCpClassNameString(int cpIndex)
+ {
+ ClassCpInfo classEntry = (ClassCpInfo)constantPool[cpIndex];
+ Utf8CpInfo nameEntry = (Utf8CpInfo)constantPool[classEntry.getNameIndex()];
+
+ return nameEntry.getString();
+ }
+
+ public String getCpNameString(int cpIndex)
+ {
+ return ((NameAndTypeCpInfo)constantPool[cpIndex]).getName(this);
+ }
+
+ public String getCpTypeString(int cpIndex)
+ {
+ return ((NameAndTypeCpInfo)constantPool[cpIndex]).getType(this);
+ }
+
+
+ public void addSubClass(ClassFile classFile)
+ {
+ if (subClasses == null)
+ {
+ subClasses = new ClassFile[1];
+ }
+ else
+ {
+ // Copy the old elements into new larger array.
+ ClassFile[] temp = new ClassFile[subClasses.length+1];
+ System.arraycopy(subClasses, 0, temp, 0, subClasses.length);
+ subClasses = temp;
+ }
+
+ subClasses[subClasses.length-1] = classFile;
+ }
+
+
+ public ClassFile getSuperClass()
+ {
+ return u2superClass != 0 ?
+ ((ClassCpInfo)constantPool[u2superClass]).referencedClassFile :
+ null;
+ }
+
+
+ public ClassFile getInterface(int index)
+ {
+ return ((ClassCpInfo)constantPool[u2interfaces[index]]).referencedClassFile;
+ }
+
+
+ public boolean extends_(ClassFile classFile)
+ {
+ if (this.equals(classFile))
+ {
+ return true;
+ }
+
+ ClassFile superClass = getSuperClass();
+ return superClass != null &&
+ superClass.extends_(classFile);
+ }
+
+
+ public boolean implements_(ClassFile classFile)
+ {
+ if (this.equals(classFile))
+ {
+ return true;
+ }
+
+ for (int i = 0; i < u2interfacesCount; i++)
+ {
+ ClassFile interfaceClass = getInterface(i);
+ if (interfaceClass != null &&
+ interfaceClass.implements_(classFile))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ public FieldInfo findField(String name, String descriptor)
+ {
+ return findProgramField(name, descriptor);
+ }
+
+
+ public MethodInfo findMethod(String name, String descriptor)
+ {
+ return findProgramMethod(name, descriptor);
+ }
+
+
+ public void accept(ClassFileVisitor classFileVisitor)
+ {
+ classFileVisitor.visitProgramClassFile(this);
+ }
+
+
+ public void hierarchyAccept(boolean visitThisClass,
+ boolean visitSuperClass,
+ boolean visitInterfaces,
+ boolean visitSubclasses,
+ ClassFileVisitor classFileVisitor)
+ {
+ // First visit the current classfile.
+ if (visitThisClass)
+ {
+ accept(classFileVisitor);
+ }
+
+ // Then visit its superclass, recursively.
+ if (visitSuperClass)
+ {
+ ClassFile superClass = getSuperClass();
+ if (superClass != null)
+ {
+ superClass.hierarchyAccept(true,
+ true,
+ visitInterfaces,
+ false,
+ classFileVisitor);
+ }
+ }
+
+ // Then visit its interfaces, recursively.
+ if (visitInterfaces)
+ {
+ for (int i = 0; i < u2interfacesCount; i++)
+ {
+ ClassFile interfaceClass = getInterface(i);
+ if (interfaceClass != null)
+ {
+ interfaceClass.hierarchyAccept(true,
+ true,
+ true,
+ false,
+ classFileVisitor);
+ }
+ }
+ }
+
+ // Then visit its subclasses, recursively.
+ if (visitSubclasses)
+ {
+ if (subClasses != null)
+ {
+ for (int i = 0; i < subClasses.length; i++)
+ {
+ ClassFile subClass = subClasses[i];
+ subClass.hierarchyAccept(true,
+ false,
+ false,
+ true,
+ classFileVisitor);
+ }
+ }
+ }
+ }
+
+
+ public void constantPoolEntriesAccept(CpInfoVisitor cpInfoVisitor)
+ {
+ for (int i = 1; i < u2constantPoolCount; i++)
+ {
+ if (constantPool[i] != null)
+ {
+ constantPool[i].accept(this, cpInfoVisitor);
+ }
+ }
+ }
+
+ public void constantPoolEntryAccept(int index, CpInfoVisitor cpInfoVisitor)
+ {
+ constantPool[index].accept(this, cpInfoVisitor);
+ }
+
+ public void fieldsAccept(MemberInfoVisitor memberInfoVisitor)
+ {
+ for (int i = 0; i < u2fieldsCount; i++)
+ {
+ fields[i].accept(this, memberInfoVisitor);
+ }
+ }
+
+ public void fieldAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor)
+ {
+ ProgramFieldInfo field = findProgramField(name, descriptor);
+ if (field != null)
+ {
+ field.accept(this, memberInfoVisitor);
+ }
+ }
+
+ public void methodsAccept(MemberInfoVisitor memberInfoVisitor)
+ {
+ for (int i = 0; i < u2methodsCount; i++)
+ {
+ methods[i].accept(this, memberInfoVisitor);
+ }
+ }
+
+ public void methodAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor)
+ {
+ ProgramMethodInfo method = findProgramMethod(name, descriptor);
+ if (method != null)
+ {
+ method.accept(this, memberInfoVisitor);
+ }
+ }
+
+ public void attributesAccept(AttrInfoVisitor attrInfoVisitor)
+ {
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i].accept(this, attrInfoVisitor);
+ }
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/ProgramFieldInfo.java b/src/proguard/classfile/ProgramFieldInfo.java
new file mode 100644
index 0000000..f36993f
--- /dev/null
+++ b/src/proguard/classfile/ProgramFieldInfo.java
@@ -0,0 +1,70 @@
+/* $Id: ProgramFieldInfo.java,v 1.16 2004/10/23 16:53:01 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+
+import java.io.*;
+
+/**
+ * Representation of a field from a program class file.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class ProgramFieldInfo extends ProgramMemberInfo implements FieldInfo
+{
+ /**
+ * Creates a new ProgramFieldInfo from the file format data in the DataInput stream.
+ *
+ * @throws IOException if class file is corrupt or incomplete
+ */
+ public static ProgramFieldInfo create(DataInput din, ClassFile cf) throws IOException
+ {
+ ProgramFieldInfo fi = new ProgramFieldInfo();
+ fi.read(din, cf);
+ return fi;
+ }
+
+
+ protected ProgramFieldInfo()
+ {
+ }
+
+
+ // Implementations for ProgramMemberInfo.
+
+ public void accept(ProgramClassFile programClassFile, MemberInfoVisitor memberInfoVisitor)
+ {
+ memberInfoVisitor.visitProgramFieldInfo(programClassFile, this);
+ }
+
+
+ public void attributesAccept(ProgramClassFile programClassFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i].accept(programClassFile, this, attrInfoVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/ProgramMemberInfo.java b/src/proguard/classfile/ProgramMemberInfo.java
new file mode 100644
index 0000000..7b3bade
--- /dev/null
+++ b/src/proguard/classfile/ProgramMemberInfo.java
@@ -0,0 +1,208 @@
+/* $Id: ProgramMemberInfo.java,v 1.27 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+
+import java.io.*;
+
+/**
+ * Representation of a field or method from a program class file.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+abstract public class ProgramMemberInfo implements MemberInfo
+{
+ public int u2accessFlags;
+ public int u2nameIndex;
+ public int u2descriptorIndex;
+ public int u2attributesCount;
+ public AttrInfo[] attributes;
+
+ /**
+ * An extra field pointing to the ClassFile objects referenced in the
+ * descriptor string. This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ * References to primitive types are ignored.
+ */
+ public ClassFile[] referencedClassFiles;
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ protected ProgramMemberInfo() {}
+
+
+ /**
+ * Returns the line number range of the given class member as "m:n",
+ * if it can find it, or <code>null</code> otherwise.
+ */
+ public String getLineNumberRange(ClassFile classFile)
+ {
+ CodeAttrInfo codeAttribute =
+ (CodeAttrInfo)getAttribute(classFile, ClassConstants.ATTR_Code);
+ if (codeAttribute == null)
+ {
+ return null;
+ }
+
+ LineNumberTableAttrInfo lineNumberTableAttribute =
+ (LineNumberTableAttrInfo)codeAttribute.getAttribute(classFile,
+ ClassConstants.ATTR_LineNumberTable);
+ if (lineNumberTableAttribute == null)
+ {
+ return null;
+ }
+
+ return "" +
+ lineNumberTableAttribute.getLineNumber(0) +
+ ":" +
+ lineNumberTableAttribute.getLineNumber(Integer.MAX_VALUE);
+ }
+
+
+ /**
+ * Returns the (first) attribute with the given name.
+ */
+ private AttrInfo getAttribute(ClassFile classFile, String name)
+ {
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ AttrInfo attribute = attributes[i];
+ if (attribute.getAttributeName(classFile).equals(name))
+ {
+ return attribute;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Accepts the given member info visitor.
+ */
+ public abstract void accept(ProgramClassFile programClassFile,
+ MemberInfoVisitor memberInfoVisitor);
+
+
+
+ /**
+ * Lets the given attribute info visitor visit all the attributes of
+ * this member info.
+ */
+ public abstract void attributesAccept(ProgramClassFile programClassFile,
+ AttrInfoVisitor attrInfoVisitor);
+
+
+ /**
+ * Lets the ClassFile objects referenced in the descriptor string
+ * accept the given visitor.
+ */
+ public void referencedClassesAccept(ClassFileVisitor classFileVisitor)
+ {
+ if (referencedClassFiles != null)
+ {
+ for (int i = 0; i < referencedClassFiles.length; i++)
+ {
+ if (referencedClassFiles[i] != null)
+ {
+ referencedClassFiles[i].accept(classFileVisitor);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Imports the field or method data to internal representation.
+ */
+ protected void read(DataInput din, ClassFile cf) throws IOException
+ {
+ u2accessFlags = din.readUnsignedShort();
+ u2nameIndex = din.readUnsignedShort();
+ u2descriptorIndex = din.readUnsignedShort();
+ u2attributesCount = din.readUnsignedShort();
+ attributes = new AttrInfo[u2attributesCount];
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i] = AttrInfo.create(din, cf);
+ }
+ }
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public void write(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2accessFlags);
+ dout.writeShort(u2nameIndex);
+ dout.writeShort(u2descriptorIndex);
+ dout.writeShort(u2attributesCount);
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i].write(dout);
+ }
+ }
+
+
+ // Implementations for MemberInfo.
+
+ public int getAccessFlags()
+ {
+ return u2accessFlags;
+ }
+
+ public String getName(ClassFile classFile)
+ {
+ return classFile.getCpString(u2nameIndex);
+ }
+
+ public String getDescriptor(ClassFile classFile)
+ {
+ return classFile.getCpString(u2descriptorIndex);
+ }
+
+ public void accept(ClassFile classFile, MemberInfoVisitor memberInfoVisitor)
+ {
+ accept((ProgramClassFile)classFile, memberInfoVisitor);
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/ProgramMethodInfo.java b/src/proguard/classfile/ProgramMethodInfo.java
new file mode 100644
index 0000000..b46a733
--- /dev/null
+++ b/src/proguard/classfile/ProgramMethodInfo.java
@@ -0,0 +1,70 @@
+/* $Id: ProgramMethodInfo.java,v 1.16 2004/10/23 16:53:01 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+
+import java.io.*;
+
+/**
+ * Representation of a method from a program class file.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class ProgramMethodInfo extends ProgramMemberInfo implements MethodInfo
+{
+ /**
+ * Creates a new ProgramMethodInfo from the file format data in the DataInput stream.
+ *
+ * @throws IOException if class file is corrupt or incomplete
+ */
+ public static ProgramMethodInfo create(DataInput din, ClassFile cf) throws IOException
+ {
+ ProgramMethodInfo mi = new ProgramMethodInfo();
+ mi.read(din, cf);
+ return mi;
+ }
+
+
+ public ProgramMethodInfo()
+ {
+ }
+
+
+ // Implementations for ProgramMemberInfo.
+
+ public void accept(ProgramClassFile programClassFile, MemberInfoVisitor memberInfoVisitor)
+ {
+ memberInfoVisitor.visitProgramMethodInfo(programClassFile, this);
+ }
+
+
+ public void attributesAccept(ProgramClassFile programClassFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i].accept(programClassFile, this, attrInfoVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/RefCpInfo.java b/src/proguard/classfile/RefCpInfo.java
new file mode 100644
index 0000000..37b2637
--- /dev/null
+++ b/src/proguard/classfile/RefCpInfo.java
@@ -0,0 +1,146 @@
+/* $Id: RefCpInfo.java,v 1.21 2004/10/31 18:13:37 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a 'ref'-type entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public abstract class RefCpInfo extends CpInfo
+{
+ public int u2classIndex;
+ public int u2nameAndTypeIndex;
+
+ /**
+ * An extra field pointing to the referenced ClassFile object.
+ * This field is typically filled out by the <code>{@link
+ * ClassFileReferenceInitializer}</code>.
+ */
+ public ClassFile referencedClassFile;
+
+ /**
+ * An extra field optionally pointing to the referenced MemberInfo object.
+ * This field is typically filled out by the <code>{@link
+ * ClassFileReferenceInitializer}</code>.
+ */
+ public MemberInfo referencedMemberInfo;
+
+
+ protected RefCpInfo()
+ {
+ }
+
+
+ /**
+ * Returns the class index.
+ */
+ public int getClassIndex()
+ {
+ return u2classIndex;
+ }
+
+ /**
+ * Returns the name-and-type index.
+ */
+ public int getNameAndTypeIndex()
+ {
+ return u2nameAndTypeIndex;
+ }
+
+ /**
+ * Sets the name-and-type index.
+ */
+ public void setNameAndTypeIndex(int index)
+ {
+ u2nameAndTypeIndex = index;
+ }
+
+ /**
+ * Returns the class name.
+ */
+ public String getClassName(ClassFile classFile)
+ {
+ return classFile.getCpClassNameString(u2classIndex);
+ }
+
+ /**
+ * Returns the method/field name.
+ */
+ public String getName(ClassFile classFile)
+ {
+ return classFile.getCpNameString(u2nameAndTypeIndex);
+ }
+
+ /**
+ * Returns the type.
+ */
+ public String getType(ClassFile classFile)
+ {
+ return classFile.getCpTypeString(u2nameAndTypeIndex);
+ }
+
+
+ /**
+ * Lets the referenced class file accept the given visitor.
+ */
+ public void referencedClassAccept(ClassFileVisitor classFileVisitor)
+ {
+ if (referencedClassFile != null)
+ {
+ referencedClassFile.accept(classFileVisitor);
+ }
+ }
+
+
+ /**
+ * Lets the referenced class member accept the given visitor.
+ */
+ public void referencedMemberInfoAccept(MemberInfoVisitor memberInfoVisitor)
+ {
+ if (referencedMemberInfo != null)
+ {
+ referencedMemberInfo.accept(referencedClassFile,
+ memberInfoVisitor);
+ }
+ }
+
+
+ // Implementations for CpInfo.
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u2classIndex = din.readUnsignedShort();
+ u2nameAndTypeIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2classIndex);
+ dout.writeShort(u2nameAndTypeIndex);
+ }
+}
diff --git a/src/proguard/classfile/StringCpInfo.java b/src/proguard/classfile/StringCpInfo.java
new file mode 100644
index 0000000..9fd8021
--- /dev/null
+++ b/src/proguard/classfile/StringCpInfo.java
@@ -0,0 +1,108 @@
+/* $Id: StringCpInfo.java,v 1.17 2004/11/07 18:49:09 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a 'string' entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class StringCpInfo extends CpInfo
+{
+ public int u2stringIndex;
+
+ /**
+ * An extra field pointing to the referenced ClassFile object, if this
+ * string is being used in Class.forName() or .class constructs.
+ * This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ * References to library class files are not filled out.
+ */
+ public ClassFile referencedClassFile;
+
+
+ protected StringCpInfo()
+ {
+ }
+
+
+ /**
+ * Creates a new StringCpInfo with the given string index.
+ * @param u2nameIndex the index of the string in the constant pool.
+ * @param referencedClassFile the referenced class file, if any.
+ */
+ public StringCpInfo(int u2stringIndex,
+ ClassFile referencedClassFile)
+ {
+ this.u2stringIndex = u2stringIndex;
+ this.referencedClassFile = referencedClassFile;
+ }
+
+
+ /**
+ * Returns the string value.
+ */
+ public String getString(ClassFile classFile)
+ {
+ return classFile.getCpString(u2stringIndex);
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_String;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u2stringIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2stringIndex);
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitStringCpInfo(classFile, this);
+ }
+
+
+ /**
+ * Lets the referenced class file accept the given visitor.
+ */
+ public void referencedClassAccept(ClassFileVisitor classFileVisitor)
+ {
+ if (referencedClassFile != null)
+ {
+ referencedClassFile.accept(classFileVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/Utf8CpInfo.java b/src/proguard/classfile/Utf8CpInfo.java
new file mode 100644
index 0000000..35faa3d
--- /dev/null
+++ b/src/proguard/classfile/Utf8CpInfo.java
@@ -0,0 +1,215 @@
+/* $Id: Utf8CpInfo.java,v 1.20 2004/10/23 16:53:01 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of a 'UTF-8' entry in the ConstantPool.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class Utf8CpInfo extends CpInfo
+{
+ private static final String ENCODING = "UTF-8";
+
+ private static final char TWO_BYTE_LIMIT = 0x80;
+ private static final byte TWO_BYTE_CONSTANT1 = (byte)0xc0;
+ private static final byte TWO_BYTE_CONSTANT2 = (byte)0x80;
+ private static final int TWO_BYTE_SHIFT1 = 6;
+ private static final byte TWO_BYTE_MASK1 = (byte)0x1f;
+ private static final byte TWO_BYTE_MASK2 = (byte)0x3f;
+
+ private static final char THREE_BYTE_LIMIT = 0x800;
+ private static final byte THREE_BYTE_CONSTANT1 = (byte)0xe0;
+ private static final byte THREE_BYTE_CONSTANT2 = (byte)0x80;
+ private static final byte THREE_BYTE_CONSTANT3 = (byte)0x80;
+ private static final int THREE_BYTE_SHIFT1 = 12;
+ private static final int THREE_BYTE_SHIFT2 = 6;
+ private static final byte THREE_BYTE_MASK1 = (byte)0x0f;
+ private static final byte THREE_BYTE_MASK2 = (byte)0x3f;
+ private static final byte THREE_BYTE_MASK3 = (byte)0x3f;
+
+
+ // There are a lot of Utf8CpInfo objects, so we're optimising their storage.
+ // Initially, we're storing the UTF-8 bytes in a byte array.
+ // When the corresponding String is requested, we ditch the array and just
+ // store the String.
+
+ //private int u2length;
+ private byte[] bytes;
+
+ private String utf8string;
+
+
+ protected Utf8CpInfo()
+ {
+ }
+
+ /**
+ * Constructor used when appending fresh UTF-8 entries to the constant pool.
+ */
+ public Utf8CpInfo(String utf8string)
+ {
+ this.bytes = null;
+ this.utf8string = utf8string;
+ }
+
+ /**
+ * Returns UTF-8 data as a String.
+ */
+ public String getString()
+ {
+ try
+ {
+ switchToStringRepresentation();
+ }
+ catch (UnsupportedEncodingException ex)
+ {
+ }
+
+ return utf8string;
+ }
+
+ /**
+ * Sets UTF-8 data as String.
+ */
+ public void setString(String utf8String) throws Exception
+ {
+ this.bytes = null;
+ this.utf8string = utf8String;
+ }
+
+
+ // Implementations for CpInfo.
+
+ public int getTag()
+ {
+ return ClassConstants.CONSTANT_Utf8;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ int u2length = din.readUnsignedShort();
+ bytes = new byte[u2length];
+ din.readFully(bytes);
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ byte[] bytes = getByteArrayRepresentation();
+ int u2length = bytes.length;
+
+ dout.writeShort(u2length);
+ dout.write(bytes);
+ }
+
+ public void accept(ClassFile classFile, CpInfoVisitor cpInfoVisitor)
+ {
+ cpInfoVisitor.visitUtf8CpInfo(classFile, this);
+ }
+
+
+ /**
+ * Switches to a String representation of the UTF-8 data.
+ */
+ private void switchToStringRepresentation() throws UnsupportedEncodingException
+ {
+ if (utf8string == null)
+ {
+ utf8string = new String(bytes, ENCODING);
+ bytes = null;
+ }
+ }
+
+
+ /**
+ * Transforms UTF-8 bytes to the slightly modified UTF-8 representation that
+ * is used by class files.
+ */
+ private byte[] getByteArrayRepresentation() throws UnsupportedEncodingException
+ {
+ // Do we still have the byte array representation?
+ if (bytes != null)
+ {
+ // Then return that one.
+ return bytes;
+ }
+
+ // We're computing the byte array ourselves, because the implementation
+ // of String.getBytes("UTF-8") has a bug, at least up to JRE 1.4.2.
+ // Also note the special treatment of the 0 character.
+
+ // Compute the byte array length.
+ int byteLength = 0;
+ int stringLength = utf8string.length();
+ for (int stringIndex = 0; stringIndex < stringLength; stringIndex++)
+ {
+ char c = utf8string.charAt(stringIndex);
+
+ // The character is represented by one, two, or three bytes.
+ byteLength += c == 0 ? 2 :
+ c < TWO_BYTE_LIMIT ? 1 :
+ c < THREE_BYTE_LIMIT ? 2 :
+ 3;
+ }
+
+ // Allocate the byte array with the computed length.
+ byte[] bytes = new byte[byteLength];
+
+ // Fill out the array.
+ int byteIndex = 0;
+ for (int stringIndex = 0; stringIndex < stringLength; stringIndex++)
+ {
+ char c = utf8string.charAt(stringIndex);
+ if (c == 0)
+ {
+ // The 0 character gets a two-byte representation in class files.
+ bytes[byteIndex++] = TWO_BYTE_CONSTANT1;
+ bytes[byteIndex++] = TWO_BYTE_CONSTANT2;
+ }
+ else if (c < TWO_BYTE_LIMIT)
+ {
+ // The character is represented by a single byte.
+ bytes[byteIndex++] = (byte)c;
+ }
+ else if (c < THREE_BYTE_LIMIT)
+ {
+ // The character is represented by two bytes.
+ bytes[byteIndex++] = (byte)(TWO_BYTE_CONSTANT1 | ((c >>> TWO_BYTE_SHIFT1) & TWO_BYTE_MASK1));
+ bytes[byteIndex++] = (byte)(TWO_BYTE_CONSTANT2 | ( c & TWO_BYTE_MASK2));
+ }
+ else
+ {
+ // The character is represented by three bytes.
+ bytes[byteIndex++] = (byte)(THREE_BYTE_CONSTANT1 | ((c >>> THREE_BYTE_SHIFT1) & THREE_BYTE_MASK1));
+ bytes[byteIndex++] = (byte)(THREE_BYTE_CONSTANT2 | ((c >>> THREE_BYTE_SHIFT2) & THREE_BYTE_MASK2));
+ bytes[byteIndex++] = (byte)(THREE_BYTE_CONSTANT3 | ( c & THREE_BYTE_MASK3));
+ }
+ }
+
+ return bytes;
+ }
+}
diff --git a/src/proguard/classfile/VisitorAccepter.java b/src/proguard/classfile/VisitorAccepter.java
new file mode 100644
index 0000000..d5d8b31
--- /dev/null
+++ b/src/proguard/classfile/VisitorAccepter.java
@@ -0,0 +1,48 @@
+/* $Id: VisitorAccepter.java,v 1.11 2004/10/23 16:53:01 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile;
+
+
+
+
+/**
+ * This interface is a base interface for visitor accepters. It allows
+ * visitors to set and get any temporary information they desire on the
+ * objects they are visiting. Note that every visitor accepter has only one
+ * such property, so visitors will have to take care not to overwrite each
+ * other's information, if it is still required.
+ *
+ * @author Eric Lafortune
+ */
+public interface VisitorAccepter
+{
+ /**
+ * Gets the visitor information of the visitor accepter.
+ */
+ public Object getVisitorInfo();
+
+
+ /**
+ * Sets the visitor information of the visitor accepter.
+ */
+ public void setVisitorInfo(Object visitorInfo);
+}
diff --git a/src/proguard/classfile/attribute/AllAttrInfoVisitor.java b/src/proguard/classfile/attribute/AllAttrInfoVisitor.java
new file mode 100644
index 0000000..ca8582e
--- /dev/null
+++ b/src/proguard/classfile/attribute/AllAttrInfoVisitor.java
@@ -0,0 +1,68 @@
+/* $Id: AllAttrInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This MemberInfoVisitor lets a given AttrInfoVisitor visit all AttrInfo
+ * objects of the program class members it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllAttrInfoVisitor implements MemberInfoVisitor
+{
+ private AttrInfoVisitor attrInfoVisitor;
+
+
+ public AllAttrInfoVisitor(AttrInfoVisitor attrInfoVisitor)
+ {
+ this.attrInfoVisitor = attrInfoVisitor;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ programFieldInfo.attributesAccept(programClassFile, attrInfoVisitor);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ programMethodInfo.attributesAccept(programClassFile, attrInfoVisitor);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ // Library class file fields don't have attributes.
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ // Library class file methods don't have attributes.
+ }
+}
diff --git a/src/proguard/classfile/attribute/AttrInfo.java b/src/proguard/classfile/attribute/AttrInfo.java
new file mode 100644
index 0000000..c7a0b31
--- /dev/null
+++ b/src/proguard/classfile/attribute/AttrInfo.java
@@ -0,0 +1,184 @@
+/* $Id: AttrInfo.java,v 1.3 2004/11/26 17:19:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.annotation.*;
+
+import java.io.*;
+
+/**
+ * Representation of an attribute. Specific attributes have their representations
+ * sub-classed from this.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public abstract class AttrInfo implements VisitorAccepter
+{
+ protected static final int CONSTANT_FIELD_SIZE = 6;
+
+
+ public int u2attrNameIndex;
+ //public int u4attrLength;
+ //public byte info[];
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ /**
+ * Creates a new AttrInfo from the data passed.
+ *
+ * @throws java.io.IOException if class file is corrupt or incomplete
+ */
+ public static AttrInfo create(DataInput din, ClassFile classFile) throws IOException
+ {
+ // Instantiate based on attribute name
+ int u2attrNameIndex = din.readUnsignedShort();
+ int u4attrLength = din.readInt();
+ String attrName = classFile.getCpString(u2attrNameIndex);
+ AttrInfo attrInfo =
+ attrName.equals(ClassConstants.ATTR_InnerClasses) ? (AttrInfo)new InnerClassesAttrInfo():
+ attrName.equals(ClassConstants.ATTR_EnclosingMethod) ? (AttrInfo)new EnclosingMethodAttrInfo():
+ attrName.equals(ClassConstants.ATTR_ConstantValue) ? (AttrInfo)new ConstantValueAttrInfo():
+ attrName.equals(ClassConstants.ATTR_Exceptions) ? (AttrInfo)new ExceptionsAttrInfo():
+ attrName.equals(ClassConstants.ATTR_Code) ? (AttrInfo)new CodeAttrInfo():
+ attrName.equals(ClassConstants.ATTR_LineNumberTable) ? (AttrInfo)new LineNumberTableAttrInfo():
+ attrName.equals(ClassConstants.ATTR_LocalVariableTable) ? (AttrInfo)new LocalVariableTableAttrInfo():
+ attrName.equals(ClassConstants.ATTR_LocalVariableTypeTable) ? (AttrInfo)new LocalVariableTypeTableAttrInfo():
+ attrName.equals(ClassConstants.ATTR_SourceFile) ? (AttrInfo)new SourceFileAttrInfo():
+ attrName.equals(ClassConstants.ATTR_SourceDir) ? (AttrInfo)new SourceDirAttrInfo():
+ attrName.equals(ClassConstants.ATTR_Deprecated) ? (AttrInfo)new DeprecatedAttrInfo():
+ attrName.equals(ClassConstants.ATTR_Synthetic) ? (AttrInfo)new SyntheticAttrInfo():
+ attrName.equals(ClassConstants.ATTR_Signature) ? (AttrInfo)new SignatureAttrInfo():
+ attrName.equals(ClassConstants.ATTR_RuntimeVisibleAnnotations) ? (AttrInfo)new RuntimeVisibleAnnotationsAttrInfo():
+ attrName.equals(ClassConstants.ATTR_RuntimeInvisibleAnnotations) ? (AttrInfo)new RuntimeInvisibleAnnotationsAttrInfo():
+ attrName.equals(ClassConstants.ATTR_RuntimeVisibleParameterAnnotations) ? (AttrInfo)new RuntimeVisibleParameterAnnotationsAttrInfo():
+ attrName.equals(ClassConstants.ATTR_RuntimeInvisibleParameterAnnotations) ? (AttrInfo)new RuntimeInvisibleParameterAnnotationsAttrInfo():
+ attrName.equals(ClassConstants.ATTR_AnnotationDefault) ? (AttrInfo)new AnnotationDefaultAttrInfo():
+ (AttrInfo)new UnknownAttrInfo(u4attrLength);
+ attrInfo.u2attrNameIndex = u2attrNameIndex;
+ attrInfo.readInfo(din, classFile);
+
+ return attrInfo;
+ }
+
+
+ protected AttrInfo()
+ {
+ }
+
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public final void write(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2attrNameIndex);
+ dout.writeInt(getLength());
+ writeInfo(dout);
+ }
+
+
+ /**
+ * Returns the String name of the attribute; override this in subclasses.
+ */
+ public String getAttributeName(ClassFile classFile)
+ {
+ return classFile.getCpString(u2attrNameIndex);
+ }
+
+
+ // Abstract methods to be implemented by extensions.
+
+ /**
+ * Returns the length of the attribute, expressed in bytes.
+ */
+ protected abstract int getLength();
+
+
+ /**
+ * Reads the data following the header.
+ */
+ protected abstract void readInfo(DataInput din, ClassFile classFile) throws IOException;
+
+
+ /**
+ * Exports data following the header to a DataOutput stream.
+ */
+ protected abstract void writeInfo(DataOutput dout) throws IOException;
+
+
+ /**
+ * Accepts the given visitor.
+ * This default implementation does nothing, which is useful for attributes
+ * that require a context.
+ */
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ // Do nothing.
+ }
+
+ /**
+ * Accepts the given visitor in the context of a field.
+ * This default implementation ignores the context.
+ */
+ public void accept(ClassFile classFile, FieldInfo fieldInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ accept(classFile, attrInfoVisitor);
+ }
+
+ /**
+ * Accepts the given visitor in the context of a method.
+ * This default implementation ignores the context.
+ */
+ public void accept(ClassFile classFile, MethodInfo methodInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ accept(classFile, attrInfoVisitor);
+ }
+
+ /**
+ * Accepts the given visitor in the context of a method's code.
+ * This default implementation ignores the code.
+ */
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ accept(classFile, methodInfo, attrInfoVisitor);
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/attribute/AttrInfoVisitor.java b/src/proguard/classfile/attribute/AttrInfoVisitor.java
new file mode 100644
index 0000000..3388d37
--- /dev/null
+++ b/src/proguard/classfile/attribute/AttrInfoVisitor.java
@@ -0,0 +1,59 @@
+/* $Id: AttrInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+
+/**
+ * This interface specifies the methods for a visitor of <code>AttrInfo</code>
+ * objects.
+ *
+ * @author Eric Lafortune
+ */
+public interface AttrInfoVisitor
+{
+ public void visitUnknownAttrInfo( ClassFile classFile, UnknownAttrInfo unknownAttrInfo);
+ public void visitInnerClassesAttrInfo( ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo);
+ public void visitEnclosingMethodAttrInfo( ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo);
+
+ public void visitConstantValueAttrInfo( ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo);
+
+ public void visitExceptionsAttrInfo( ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo);
+ public void visitCodeAttrInfo( ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo);
+
+ public void visitLineNumberTableAttrInfo( ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo);
+ public void visitLocalVariableTableAttrInfo( ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo);
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo);
+
+ public void visitSourceFileAttrInfo( ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo);
+ public void visitSourceDirAttrInfo( ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo);
+ public void visitDeprecatedAttrInfo( ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo);
+ public void visitSyntheticAttrInfo( ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo);
+ public void visitSignatureAttrInfo( ClassFile classFile, SignatureAttrInfo syntheticAttrInfo);
+
+ public void visitRuntimeVisibleAnnotationAttrInfo( ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo);
+ public void visitRuntimeInvisibleAnnotationAttrInfo( ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo);
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo( ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo);
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo);
+ public void visitAnnotationDefaultAttrInfo( ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo);
+}
diff --git a/src/proguard/classfile/attribute/CodeAttrInfo.java b/src/proguard/classfile/attribute/CodeAttrInfo.java
new file mode 100644
index 0000000..9e89d83
--- /dev/null
+++ b/src/proguard/classfile/attribute/CodeAttrInfo.java
@@ -0,0 +1,190 @@
+/* $Id: CodeAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a code attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class CodeAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 12;
+
+
+ public int u2maxStack;
+ public int u2maxLocals;
+ public int u4codeLength;
+ public byte[] code;
+ public int u2exceptionTableLength;
+ public ExceptionInfo[] exceptionTable;
+ public int u2attributesCount;
+ public AttrInfo[] attributes;
+
+
+ protected CodeAttrInfo()
+ {
+ }
+
+
+ /**
+ * Returns the (first) attribute with the given name.
+ */
+ public AttrInfo getAttribute(ClassFile classFile, String name)
+ {
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ AttrInfo attribute = attributes[i];
+ if (attribute.getAttributeName(classFile).equals(name))
+ {
+ return attribute;
+ }
+ }
+
+ return null;
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ int length = CONSTANT_FIELD_SIZE + u4codeLength +
+ u2exceptionTableLength * ExceptionInfo.CONSTANT_FIELD_SIZE;
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ length += AttrInfo.CONSTANT_FIELD_SIZE + attributes[i].getLength();
+ }
+
+ return length;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2maxStack = din.readUnsignedShort();
+ u2maxLocals = din.readUnsignedShort();
+ u4codeLength = din.readInt();
+ code = new byte[u4codeLength];
+ din.readFully(code);
+ u2exceptionTableLength = din.readUnsignedShort();
+ exceptionTable = new ExceptionInfo[u2exceptionTableLength];
+ for (int i = 0; i < u2exceptionTableLength; i++)
+ {
+ exceptionTable[i] = ExceptionInfo.create(din);
+ }
+ u2attributesCount = din.readUnsignedShort();
+ attributes = new AttrInfo[u2attributesCount];
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i] = AttrInfo.create(din, classFile);
+ }
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2maxStack);
+ dout.writeShort(u2maxLocals);
+ dout.writeInt(u4codeLength);
+ dout.write(code, 0, u4codeLength);
+ dout.writeShort(u2exceptionTableLength);
+ for (int i = 0; i < u2exceptionTableLength; i++)
+ {
+ exceptionTable[i].write(dout);
+ }
+ dout.writeShort(u2attributesCount);
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i].write(dout);
+ }
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitCodeAttrInfo(classFile, null, this);
+ }
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitCodeAttrInfo(classFile, methodInfo, this);
+ }
+
+
+ /**
+ * Applies the given instruction visitor to all instructions.
+ */
+ public void instructionsAccept(ClassFile classFile, MethodInfo methodInfo, InstructionVisitor instructionVisitor)
+ {
+ int offset = 0;
+
+ do
+ {
+ // Note that the instruction is only volatile.
+ Instruction instruction = InstructionFactory.create(code, offset);
+ int length = instruction.length(offset);
+ instruction.accept(classFile, methodInfo, this, offset, instructionVisitor);
+ offset += length;
+ }
+ while (offset < u4codeLength);
+ }
+
+ /**
+ * Applies the given instruction visitor to the given instruction.
+ */
+ public void instructionAccept(ClassFile classFile, MethodInfo methodInfo, InstructionVisitor instructionVisitor, int offset)
+ {
+ Instruction instruction = InstructionFactory.create(code, offset);
+ instruction.accept(classFile, methodInfo, this, offset, instructionVisitor);
+ }
+
+ /**
+ * Applies the given exception visitor to all exceptions.
+ */
+ public void exceptionsAccept(ClassFile classFile, MethodInfo methodInfo, ExceptionInfoVisitor exceptionInfoVisitor)
+ {
+ for (int i = 0; i < u2exceptionTableLength; i++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of ExceptionInfo.
+ exceptionInfoVisitor.visitExceptionInfo(classFile, methodInfo, this, exceptionTable[i]);
+ }
+ }
+
+ /**
+ * Applies the given attribute visitor to all attributes.
+ */
+ public void attributesAccept(ClassFile classFile, MethodInfo methodInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ for (int i = 0; i < u2attributesCount; i++)
+ {
+ attributes[i].accept(classFile, methodInfo, this, attrInfoVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/ConstantValueAttrInfo.java b/src/proguard/classfile/attribute/ConstantValueAttrInfo.java
new file mode 100644
index 0000000..86e937c
--- /dev/null
+++ b/src/proguard/classfile/attribute/ConstantValueAttrInfo.java
@@ -0,0 +1,70 @@
+/* $Id: ConstantValueAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a constant value attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class ConstantValueAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2constantValueIndex;
+
+
+ protected ConstantValueAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2constantValueIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2constantValueIndex);
+ }
+
+ public void accept(ClassFile classFile, FieldInfo fieldInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitConstantValueAttrInfo(classFile, fieldInfo, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/DeprecatedAttrInfo.java b/src/proguard/classfile/attribute/DeprecatedAttrInfo.java
new file mode 100644
index 0000000..d45d692
--- /dev/null
+++ b/src/proguard/classfile/attribute/DeprecatedAttrInfo.java
@@ -0,0 +1,65 @@
+/* $Id: DeprecatedAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a deprecated attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class DeprecatedAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 0;
+
+
+ protected DeprecatedAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitDeprecatedAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/EnclosingMethodAttrInfo.java b/src/proguard/classfile/attribute/EnclosingMethodAttrInfo.java
new file mode 100644
index 0000000..1587550
--- /dev/null
+++ b/src/proguard/classfile/attribute/EnclosingMethodAttrInfo.java
@@ -0,0 +1,135 @@
+/* $Id: EnclosingMethodAttrInfo.java,v 1.2 2004/10/31 18:13:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * Representation of an enclosing method attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class EnclosingMethodAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 4;
+
+
+ public int u2classIndex;
+ public int u2nameAndTypeIndex;
+
+ /**
+ * An extra field pointing to the referenced ClassFile object.
+ * This field is typically filled out by the <code>{@link
+ * ClassFileReferenceInitializer}</code>.
+ */
+ public ClassFile referencedClassFile;
+
+ /**
+ * An extra field optionally pointing to the referenced MethodInfo object.
+ * This field is typically filled out by the <code>{@link
+ * ClassFileReferenceInitializer}</code>.
+ */
+ public MethodInfo referencedMethodInfo;
+
+
+ protected EnclosingMethodAttrInfo()
+ {
+ }
+
+
+ /**
+ * Returns the class name.
+ */
+ public String getClassName(ClassFile classFile)
+ {
+ return classFile.getCpClassNameString(u2classIndex);
+ }
+
+ /**
+ * Returns the method/field name.
+ */
+ public String getName(ClassFile classFile)
+ {
+ return classFile.getCpNameString(u2nameAndTypeIndex);
+ }
+
+ /**
+ * Returns the type.
+ */
+ public String getType(ClassFile classFile)
+ {
+ return classFile.getCpTypeString(u2nameAndTypeIndex);
+ }
+
+
+ /**
+ * Lets the referenced class file accept the given visitor.
+ */
+ public void referencedClassAccept(ClassFileVisitor classFileVisitor)
+ {
+ if (referencedClassFile != null)
+ {
+ referencedClassFile.accept(classFileVisitor);
+ }
+ }
+
+
+ /**
+ * Lets the referenced class member accept the given visitor.
+ */
+ public void referencedMethodInfoAccept(MemberInfoVisitor memberInfoVisitor)
+ {
+ if (referencedMethodInfo != null)
+ {
+ referencedMethodInfo.accept(referencedClassFile,
+ memberInfoVisitor);
+ }
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2classIndex = din.readUnsignedShort();
+ u2nameAndTypeIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2classIndex);
+ dout.writeShort(u2nameAndTypeIndex);
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitEnclosingMethodAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/ExceptionInfo.java b/src/proguard/classfile/attribute/ExceptionInfo.java
new file mode 100644
index 0000000..b289343
--- /dev/null
+++ b/src/proguard/classfile/attribute/ExceptionInfo.java
@@ -0,0 +1,91 @@
+/* $Id: ExceptionInfo.java,v 1.2 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of an Exception table entry.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class ExceptionInfo implements VisitorAccepter
+{
+ public static final int CONSTANT_FIELD_SIZE = 8;
+
+
+ public int u2startpc;
+ public int u2endpc;
+ public int u2handlerpc;
+ public int u2catchType;
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ public static ExceptionInfo create(DataInput din) throws IOException
+ {
+ ExceptionInfo ei = new ExceptionInfo();
+ ei.read(din);
+ return ei;
+ }
+
+
+ private ExceptionInfo() {}
+
+ private void read(DataInput din) throws IOException
+ {
+ u2startpc = din.readUnsignedShort();
+ u2endpc = din.readUnsignedShort();
+ u2handlerpc = din.readUnsignedShort();
+ u2catchType = din.readUnsignedShort();
+ }
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public void write(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2startpc);
+ dout.writeShort(u2endpc);
+ dout.writeShort(u2handlerpc);
+ dout.writeShort(u2catchType);
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/attribute/ExceptionInfoVisitor.java b/src/proguard/classfile/attribute/ExceptionInfoVisitor.java
new file mode 100644
index 0000000..e692133
--- /dev/null
+++ b/src/proguard/classfile/attribute/ExceptionInfoVisitor.java
@@ -0,0 +1,36 @@
+/* $Id: ExceptionInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>ExceptionInfo</code> objects. Note that there is only a single
+ * implementation of <code>ExceptionInfo</code>, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Eric Lafortune
+ */
+public interface ExceptionInfoVisitor
+{
+ public void visitExceptionInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, ExceptionInfo exceptionInfo);
+}
diff --git a/src/proguard/classfile/attribute/ExceptionsAttrInfo.java b/src/proguard/classfile/attribute/ExceptionsAttrInfo.java
new file mode 100644
index 0000000..d465543
--- /dev/null
+++ b/src/proguard/classfile/attribute/ExceptionsAttrInfo.java
@@ -0,0 +1,99 @@
+/* $Id: ExceptionsAttrInfo.java,v 1.2 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of an exceptions attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class ExceptionsAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2numberOfExceptions;
+ public int[] u2exceptionIndexTable;
+
+
+ protected ExceptionsAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE + 2 * u2numberOfExceptions;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2numberOfExceptions = din.readUnsignedShort();
+ u2exceptionIndexTable = new int[u2numberOfExceptions];
+ for (int i = 0; i < u2numberOfExceptions; i++)
+ {
+ u2exceptionIndexTable[i] = din.readUnsignedShort();
+ }
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2numberOfExceptions);
+ for (int i = 0; i < u2numberOfExceptions; i++)
+ {
+ dout.writeShort(u2exceptionIndexTable[i]);
+ }
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ // We'll just ignore Exception attributes that do not belong to a method.
+ }
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitExceptionsAttrInfo(classFile, methodInfo, this);
+ }
+
+
+ /**
+ * Applies the given constant pool visitor to all exception class pool info
+ * entries.
+ */
+ public void exceptionEntriesAccept(ProgramClassFile programClassFile, CpInfoVisitor cpInfoVisitor)
+ {
+ for (int i = 0; i < u2numberOfExceptions; i++)
+ {
+ programClassFile.constantPoolEntryAccept(u2exceptionIndexTable[i],
+ cpInfoVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/InnerClassesAttrInfo.java b/src/proguard/classfile/attribute/InnerClassesAttrInfo.java
new file mode 100644
index 0000000..174a028
--- /dev/null
+++ b/src/proguard/classfile/attribute/InnerClassesAttrInfo.java
@@ -0,0 +1,104 @@
+/* $Id: InnerClassesAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of an inner classes attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class InnerClassesAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2numberOfClasses;
+ public InnerClassesInfo[] classes;
+
+
+ protected InnerClassesAttrInfo()
+ {
+ }
+
+
+ /**
+ * Returns the array of inner classes data.
+ */
+ protected InnerClassesInfo[] getInfo() throws Exception
+ {
+ return classes;
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE +
+ u2numberOfClasses * InnerClassesInfo.CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2numberOfClasses = din.readUnsignedShort();
+ classes = new InnerClassesInfo[u2numberOfClasses];
+ for (int i = 0; i < u2numberOfClasses; i++)
+ {
+ classes[i] = InnerClassesInfo.create(din);
+ }
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2numberOfClasses);
+ for (int i = 0; i < u2numberOfClasses; i++)
+ {
+ classes[i].write(dout);
+ }
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitInnerClassesAttrInfo(classFile, this);
+ }
+
+
+ /**
+ * Applies the given visitor to all inner classes.
+ */
+ public void innerClassEntriesAccept(ClassFile classFile, InnerClassesInfoVisitor innerClassesInfoVisitor)
+ {
+ for (int i = 0; i < u2numberOfClasses; i++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of InnerClassesInfo.
+ innerClassesInfoVisitor.visitInnerClassesInfo(classFile, classes[i]);
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/InnerClassesInfo.java b/src/proguard/classfile/attribute/InnerClassesInfo.java
new file mode 100644
index 0000000..51b3bb0
--- /dev/null
+++ b/src/proguard/classfile/attribute/InnerClassesInfo.java
@@ -0,0 +1,112 @@
+/* $Id: InnerClassesInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of an Inner Classes table entry.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class InnerClassesInfo implements VisitorAccepter
+{
+ public static final int CONSTANT_FIELD_SIZE = 8;
+
+
+ public int u2innerClassInfoIndex;
+ public int u2outerClassInfoIndex;
+ public int u2innerNameIndex;
+ public int u2innerClassAccessFlags;
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ public static InnerClassesInfo create(DataInput din) throws IOException
+ {
+ InnerClassesInfo ici = new InnerClassesInfo();
+ ici.read(din);
+ return ici;
+ }
+
+ /**
+ * Returns the inner class index.
+ */
+ protected int getInnerClassIndex()
+ {
+ return u2innerClassInfoIndex;
+ }
+
+ /**
+ * Returns the name index.
+ */
+ protected int getInnerNameIndex()
+ {
+ return u2innerNameIndex;
+ }
+
+ /**
+ * Sets the name index.
+ */
+ protected void setInnerNameIndex(int index)
+ {
+ u2innerNameIndex = index;
+ }
+
+ private void read(DataInput din) throws IOException
+ {
+ u2innerClassInfoIndex = din.readUnsignedShort();
+ u2outerClassInfoIndex = din.readUnsignedShort();
+ u2innerNameIndex = din.readUnsignedShort();
+ u2innerClassAccessFlags = din.readUnsignedShort();
+ }
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public void write(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2innerClassInfoIndex);
+ dout.writeShort(u2outerClassInfoIndex);
+ dout.writeShort(u2innerNameIndex);
+ dout.writeShort(u2innerClassAccessFlags);
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/attribute/InnerClassesInfoVisitor.java b/src/proguard/classfile/attribute/InnerClassesInfoVisitor.java
new file mode 100644
index 0000000..aa3a7b8
--- /dev/null
+++ b/src/proguard/classfile/attribute/InnerClassesInfoVisitor.java
@@ -0,0 +1,38 @@
+/* $Id: InnerClassesInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>InnerClassesInfo</code> objects. Note that there is only a single
+ * implementation of <code>InnerClassesInfo</code>, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Eric Lafortune
+ */
+public interface InnerClassesInfoVisitor
+{
+ public void visitInnerClassesInfo(ClassFile classFile, InnerClassesInfo innerClassesInfo);
+}
diff --git a/src/proguard/classfile/attribute/LibraryAttrInfo.java b/src/proguard/classfile/attribute/LibraryAttrInfo.java
new file mode 100644
index 0000000..579ce04
--- /dev/null
+++ b/src/proguard/classfile/attribute/LibraryAttrInfo.java
@@ -0,0 +1,45 @@
+/* $Id: LibraryAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import java.io.*;
+
+/**
+ * Representation of a light-weight library attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class LibraryAttrInfo
+{
+ /**
+ * Skips LibraryAttrInfo from the data passed.
+ *
+ * @throws java.io.IOException if class file is corrupt or incomplete
+ */
+ public static void skip(DataInput din) throws IOException
+ {
+ // Instantiate based on attribute name
+ int u2attrNameIndex = din.readUnsignedShort();
+ int u4attrLength = din.readInt();
+ din.skipBytes(u4attrLength);
+ }
+}
diff --git a/src/proguard/classfile/attribute/LineNumberInfo.java b/src/proguard/classfile/attribute/LineNumberInfo.java
new file mode 100644
index 0000000..cc48492
--- /dev/null
+++ b/src/proguard/classfile/attribute/LineNumberInfo.java
@@ -0,0 +1,64 @@
+/* $Id: LineNumberInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import java.io.*;
+
+/**
+ * Representation of an Line Number table entry.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LineNumberInfo
+{
+ public static final int CONSTANT_FIELD_SIZE = 4;
+
+
+ public int u2startpc;
+ public int u2lineNumber;
+
+
+ public static LineNumberInfo create(DataInput din) throws IOException
+ {
+ LineNumberInfo lni = new LineNumberInfo();
+ lni.read(din);
+ return lni;
+ }
+
+
+ private LineNumberInfo() {}
+ private void read(DataInput din) throws IOException
+ {
+ u2startpc = din.readUnsignedShort();
+ u2lineNumber = din.readUnsignedShort();
+ }
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public void write(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2startpc);
+ dout.writeShort(u2lineNumber);
+ }
+}
diff --git a/src/proguard/classfile/attribute/LineNumberTableAttrInfo.java b/src/proguard/classfile/attribute/LineNumberTableAttrInfo.java
new file mode 100644
index 0000000..48d0d4b
--- /dev/null
+++ b/src/proguard/classfile/attribute/LineNumberTableAttrInfo.java
@@ -0,0 +1,116 @@
+/* $Id: LineNumberTableAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a line number table attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LineNumberTableAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2lineNumberTableLength;
+ public LineNumberInfo[] lineNumberTable;
+
+
+ protected LineNumberTableAttrInfo()
+ {
+ }
+
+
+ /**
+ * Returns the line number corresponding to the given byte code program
+ * counter.
+ */
+ public int getLineNumber(int pc)
+ {
+ for (int i = u2lineNumberTableLength-1 ; i >= 0 ; i--)
+ {
+ LineNumberInfo info = lineNumberTable[i];
+ if (pc >= info.u2startpc)
+ {
+ return info.u2lineNumber;
+ }
+ }
+
+ return u2lineNumberTableLength > 0 ?
+ lineNumberTable[0].u2lineNumber :
+ 0;
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE +
+ u2lineNumberTableLength * LineNumberInfo.CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2lineNumberTableLength = din.readUnsignedShort();
+ lineNumberTable = new LineNumberInfo[u2lineNumberTableLength];
+ for (int i = 0; i < u2lineNumberTableLength; i++)
+ {
+ lineNumberTable[i] = LineNumberInfo.create(din);
+ }
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2lineNumberTableLength);
+ for (int i = 0; i < u2lineNumberTableLength; i++)
+ {
+ lineNumberTable[i].write(dout);
+ }
+ }
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitLineNumberTableAttrInfo(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ /**
+ * Applies the given visitor to all line numbers.
+ */
+ public void lineNumbersAccept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberInfoVisitor lineNumberInfoVisitor)
+ {
+ for (int i = 0; i < u2lineNumberTableLength; i++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of LineNumberInfo.
+ lineNumberInfoVisitor.visitLineNumberInfo(classFile, methodInfo, codeAttrInfo, lineNumberTable[i]);
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/LocalVariableInfo.java b/src/proguard/classfile/attribute/LocalVariableInfo.java
new file mode 100644
index 0000000..0108794
--- /dev/null
+++ b/src/proguard/classfile/attribute/LocalVariableInfo.java
@@ -0,0 +1,112 @@
+/* $Id: LocalVariableInfo.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.ClassFile;
+
+import java.io.*;
+
+/**
+ * Representation of an Local Variable table entry.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LocalVariableInfo
+{
+ public static final int CONSTANT_FIELD_SIZE = 10;
+
+
+ public int u2startpc;
+ public int u2length;
+ public int u2nameIndex;
+ public int u2descriptorIndex;
+ public int u2index;
+
+ /**
+ * An extra field pointing to the referenced ClassFile object.
+ * This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ */
+ public ClassFile referencedClassFile;
+
+
+ public static LocalVariableInfo create(DataInput din) throws IOException
+ {
+ LocalVariableInfo lvi = new LocalVariableInfo();
+ lvi.read(din);
+ return lvi;
+ }
+
+ /**
+ * Returns name index into Constant Pool.
+ */
+ protected int getNameIndex()
+ {
+ return u2nameIndex;
+ }
+
+ /**
+ * Sets the name index.
+ */
+ protected void setNameIndex(int index)
+ {
+ u2nameIndex = index;
+ }
+
+ /**
+ * Returns descriptor index into Constant Pool.
+ */
+ protected int getDescriptorIndex()
+ {
+ return u2descriptorIndex;
+ }
+
+ /**
+ * Sets the descriptor index.
+ */
+ protected void setDescriptorIndex(int index)
+ {
+ u2descriptorIndex = index;
+ }
+
+ private void read(DataInput din) throws IOException
+ {
+ u2startpc = din.readUnsignedShort();
+ u2length = din.readUnsignedShort();
+ u2nameIndex = din.readUnsignedShort();
+ u2descriptorIndex = din.readUnsignedShort();
+ u2index = din.readUnsignedShort();
+ }
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public void write(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2startpc);
+ dout.writeShort(u2length);
+ dout.writeShort(u2nameIndex);
+ dout.writeShort(u2descriptorIndex);
+ dout.writeShort(u2index);
+ }
+}
diff --git a/src/proguard/classfile/attribute/LocalVariableInfoVisitor.java b/src/proguard/classfile/attribute/LocalVariableInfoVisitor.java
new file mode 100644
index 0000000..088675b
--- /dev/null
+++ b/src/proguard/classfile/attribute/LocalVariableInfoVisitor.java
@@ -0,0 +1,38 @@
+/* $Id: LocalVariableInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>LocalVariableInfo</code> objects. Note that there is only a single
+ * implementation of <code>LocalVariableInfo</code>, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Eric Lafortune
+ */
+public interface LocalVariableInfoVisitor
+{
+ public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo);
+}
diff --git a/src/proguard/classfile/attribute/LocalVariableTableAttrInfo.java b/src/proguard/classfile/attribute/LocalVariableTableAttrInfo.java
new file mode 100644
index 0000000..107b806
--- /dev/null
+++ b/src/proguard/classfile/attribute/LocalVariableTableAttrInfo.java
@@ -0,0 +1,102 @@
+/* $Id: LocalVariableTableAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a local variable table attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LocalVariableTableAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2localVariableTableLength;
+ public LocalVariableInfo[] localVariableTable;
+
+
+ protected LocalVariableTableAttrInfo()
+ {
+ }
+
+
+ /**
+ * Returns the array of local variable table entries.
+ */
+ protected LocalVariableInfo[] getLocalVariableTable() throws Exception
+ {
+ return localVariableTable;
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE +
+ u2localVariableTableLength * LocalVariableInfo.CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2localVariableTableLength = din.readUnsignedShort();
+ localVariableTable = new LocalVariableInfo[u2localVariableTableLength];
+ for (int i = 0; i < u2localVariableTableLength; i++)
+ {
+ localVariableTable[i] = LocalVariableInfo.create(din);
+ }
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2localVariableTableLength);
+ for (int i = 0; i < u2localVariableTableLength; i++)
+ {
+ localVariableTable[i].write(dout);
+ }
+ }
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitLocalVariableTableAttrInfo(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ /**
+ * Applies the given visitor to all local variables.
+ */
+ public void localVariablesAccept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfoVisitor localVariableInfoVisitor)
+ {
+ for (int i = 0; i < u2localVariableTableLength; i++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of LocalVariableInfo.
+ localVariableInfoVisitor.visitLocalVariableInfo(classFile, methodInfo, codeAttrInfo, localVariableTable[i]);
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/LocalVariableTypeInfo.java b/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
new file mode 100644
index 0000000..5453992
--- /dev/null
+++ b/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
@@ -0,0 +1,113 @@
+/* $Id: LocalVariableTypeInfo.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.ClassFile;
+
+import java.io.*;
+
+/**
+ * Representation of an Local Variable table entry.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LocalVariableTypeInfo
+{
+ public static final int CONSTANT_FIELD_SIZE = 10;
+
+
+ public int u2startpc;
+ public int u2length;
+ public int u2nameIndex;
+ public int u2signatureIndex;
+ public int u2index;
+
+ /**
+ * An extra field pointing to the ClassFile objects referenced in the
+ * type string. This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ * References to primitive types are ignored.
+ */
+ public ClassFile[] referencedClassFiles;
+
+
+ public static LocalVariableTypeInfo create(DataInput din) throws IOException
+ {
+ LocalVariableTypeInfo lvi = new LocalVariableTypeInfo();
+ lvi.read(din);
+ return lvi;
+ }
+
+ /**
+ * Returns name index into Constant Pool.
+ */
+ protected int getNameIndex()
+ {
+ return u2nameIndex;
+ }
+
+ /**
+ * Sets the name index.
+ */
+ protected void setNameIndex(int index)
+ {
+ u2nameIndex = index;
+ }
+
+ /**
+ * Returns descriptor index into Constant Pool.
+ */
+ protected int getDescriptorIndex()
+ {
+ return u2signatureIndex;
+ }
+
+ /**
+ * Sets the descriptor index.
+ */
+ protected void setDescriptorIndex(int index)
+ {
+ u2signatureIndex = index;
+ }
+
+ private void read(DataInput din) throws IOException
+ {
+ u2startpc = din.readUnsignedShort();
+ u2length = din.readUnsignedShort();
+ u2nameIndex = din.readUnsignedShort();
+ u2signatureIndex = din.readUnsignedShort();
+ u2index = din.readUnsignedShort();
+ }
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public void write(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2startpc);
+ dout.writeShort(u2length);
+ dout.writeShort(u2nameIndex);
+ dout.writeShort(u2signatureIndex);
+ dout.writeShort(u2index);
+ }
+}
diff --git a/src/proguard/classfile/attribute/LocalVariableTypeInfoVisitor.java b/src/proguard/classfile/attribute/LocalVariableTypeInfoVisitor.java
new file mode 100644
index 0000000..f3666c4
--- /dev/null
+++ b/src/proguard/classfile/attribute/LocalVariableTypeInfoVisitor.java
@@ -0,0 +1,38 @@
+/* $Id: LocalVariableTypeInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>LocalVariableTypeInfo</code> objects. Note that there is only a single
+ * implementation of <code>LocalVariableTypeInfo</code>, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Eric Lafortune
+ */
+public interface LocalVariableTypeInfoVisitor
+{
+ public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo);
+}
diff --git a/src/proguard/classfile/attribute/LocalVariableTypeTableAttrInfo.java b/src/proguard/classfile/attribute/LocalVariableTypeTableAttrInfo.java
new file mode 100644
index 0000000..c500a06
--- /dev/null
+++ b/src/proguard/classfile/attribute/LocalVariableTypeTableAttrInfo.java
@@ -0,0 +1,102 @@
+/* $Id: LocalVariableTypeTableAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a local variable table type attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class LocalVariableTypeTableAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2localVariableTypeTableLength;
+ public LocalVariableTypeInfo[] localVariableTypeTable;
+
+
+ protected LocalVariableTypeTableAttrInfo()
+ {
+ }
+
+
+ /**
+ * Returns the array of local variable type table entries.
+ */
+ protected LocalVariableTypeInfo[] getLocalVariableTypeTable() throws Exception
+ {
+ return localVariableTypeTable;
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE +
+ u2localVariableTypeTableLength * LocalVariableTypeInfo.CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2localVariableTypeTableLength = din.readUnsignedShort();
+ localVariableTypeTable = new LocalVariableTypeInfo[u2localVariableTypeTableLength];
+ for (int i = 0; i < u2localVariableTypeTableLength; i++)
+ {
+ localVariableTypeTable[i] = LocalVariableTypeInfo.create(din);
+ }
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2localVariableTypeTableLength);
+ for (int i = 0; i < u2localVariableTypeTableLength; i++)
+ {
+ localVariableTypeTable[i].write(dout);
+ }
+ }
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitLocalVariableTypeTableAttrInfo(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ /**
+ * Applies the given visitor to all local variable types.
+ */
+ public void localVariablesAccept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfoVisitor localVariableTypeInfoVisitor)
+ {
+ for (int i = 0; i < u2localVariableTypeTableLength; i++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of LocalVariableTypeInfo.
+ localVariableTypeInfoVisitor.visitLocalVariableTypeInfo(classFile, methodInfo, codeAttrInfo, localVariableTypeTable[i]);
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/MultiAttrInfoVisitor.java b/src/proguard/classfile/attribute/MultiAttrInfoVisitor.java
new file mode 100644
index 0000000..5fcbcfa
--- /dev/null
+++ b/src/proguard/classfile/attribute/MultiAttrInfoVisitor.java
@@ -0,0 +1,234 @@
+/* $Id: MultiAttrInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+
+/**
+ * This AttrInfoVisitor delegates all visits to each AttrInfoVisitor
+ * in a given list.
+ *
+ * @author Eric Lafortune
+ */
+public class MultiAttrInfoVisitor implements AttrInfoVisitor
+{
+ private static final int ARRAY_SIZE_INCREMENT = 5;
+
+ private AttrInfoVisitor[] attrInfoVisitors;
+ private int attrInfoVisitorCount;
+
+
+ public MultiAttrInfoVisitor()
+ {
+ }
+
+
+ public MultiAttrInfoVisitor(AttrInfoVisitor[] attrInfoVisitors)
+ {
+ this.attrInfoVisitors = attrInfoVisitors;
+ this.attrInfoVisitorCount = attrInfoVisitors.length;
+ }
+
+
+ public void addAttrInfoVisitor(AttrInfoVisitor attrInfoVisitor)
+ {
+ ensureArraySize();
+
+ attrInfoVisitors[attrInfoVisitorCount++] = attrInfoVisitor;
+ }
+
+
+ private void ensureArraySize()
+ {
+ if (attrInfoVisitors == null)
+ {
+ attrInfoVisitors = new AttrInfoVisitor[ARRAY_SIZE_INCREMENT];
+ }
+ else if (attrInfoVisitors.length == attrInfoVisitorCount)
+ {
+ AttrInfoVisitor[] newAttrInfoVisitors =
+ new AttrInfoVisitor[attrInfoVisitorCount +
+ ARRAY_SIZE_INCREMENT];
+ System.arraycopy(attrInfoVisitors, 0,
+ newAttrInfoVisitors, 0,
+ attrInfoVisitorCount);
+ attrInfoVisitors = newAttrInfoVisitors;
+ }
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitUnknownAttrInfo(classFile, unknownAttrInfo);
+ }
+ }
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitInnerClassesAttrInfo(classFile, innerClassesAttrInfo);
+ }
+ }
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitEnclosingMethodAttrInfo(classFile, enclosingMethodAttrInfo);
+ }
+ }
+
+
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitConstantValueAttrInfo(classFile, fieldInfo, constantValueAttrInfo);
+ }
+ }
+
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitExceptionsAttrInfo(classFile, methodInfo, exceptionsAttrInfo);
+ }
+ }
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
+ }
+ }
+
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitLineNumberTableAttrInfo(classFile, methodInfo, codeAttrInfo, lineNumberTableAttrInfo);
+ }
+ }
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitLocalVariableTableAttrInfo(classFile, methodInfo, codeAttrInfo, localVariableTableAttrInfo);
+ }
+ }
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitLocalVariableTypeTableAttrInfo(classFile, methodInfo, codeAttrInfo, localVariableTypeTableAttrInfo);
+ }
+ }
+
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitSourceFileAttrInfo(classFile, sourceFileAttrInfo);
+ }
+ }
+
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitSourceDirAttrInfo(classFile, sourceDirAttrInfo);
+ }
+ }
+
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitDeprecatedAttrInfo(classFile, deprecatedAttrInfo);
+ }
+ }
+
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitSyntheticAttrInfo(classFile, syntheticAttrInfo);
+ }
+ }
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo syntheticAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitSignatureAttrInfo(classFile, syntheticAttrInfo);
+ }
+ }
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitRuntimeVisibleAnnotationAttrInfo(classFile, runtimeVisibleAnnotationsAttrInfo);
+ }
+ }
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitRuntimeInvisibleAnnotationAttrInfo(classFile, runtimeInvisibleAnnotationsAttrInfo);
+ }
+ }
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitRuntimeVisibleParameterAnnotationAttrInfo(classFile, runtimeVisibleParameterAnnotationsAttrInfo);
+ }
+ }
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitRuntimeInvisibleParameterAnnotationAttrInfo(classFile, runtimeInvisibleParameterAnnotationsAttrInfo);
+ }
+ }
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ for (int index = 0; index < attrInfoVisitorCount; index++)
+ {
+ attrInfoVisitors[index].visitAnnotationDefaultAttrInfo(classFile, annotationDefaultAttrInfo);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/proguard/classfile/attribute/SignatureAttrInfo.java b/src/proguard/classfile/attribute/SignatureAttrInfo.java
new file mode 100644
index 0000000..18a7f16
--- /dev/null
+++ b/src/proguard/classfile/attribute/SignatureAttrInfo.java
@@ -0,0 +1,75 @@
+/* $Id: SignatureAttrInfo.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a signature attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class SignatureAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2signatureIndex;
+
+ /**
+ * An extra field pointing to the ClassFile objects referenced in the
+ * signature string. This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ * References to primitive types are ignored.
+ */
+ public ClassFile[] referencedClassFiles;
+
+
+ protected SignatureAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2signatureIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2signatureIndex);
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitSignatureAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/SourceDirAttrInfo.java b/src/proguard/classfile/attribute/SourceDirAttrInfo.java
new file mode 100644
index 0000000..1edf2bf
--- /dev/null
+++ b/src/proguard/classfile/attribute/SourceDirAttrInfo.java
@@ -0,0 +1,69 @@
+/* $Id: SourceDirAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a source directory attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class SourceDirAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2sourceDirIndex;
+
+
+ protected SourceDirAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2sourceDirIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2sourceDirIndex);
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitSourceDirAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/SourceFileAttrInfo.java b/src/proguard/classfile/attribute/SourceFileAttrInfo.java
new file mode 100644
index 0000000..8f6ff9e
--- /dev/null
+++ b/src/proguard/classfile/attribute/SourceFileAttrInfo.java
@@ -0,0 +1,70 @@
+/* $Id: SourceFileAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a source file attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class SourceFileAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2sourceFileIndex;
+
+
+ protected SourceFileAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2sourceFileIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2sourceFileIndex);
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitSourceFileAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/SyntheticAttrInfo.java b/src/proguard/classfile/attribute/SyntheticAttrInfo.java
new file mode 100644
index 0000000..c0fb2f9
--- /dev/null
+++ b/src/proguard/classfile/attribute/SyntheticAttrInfo.java
@@ -0,0 +1,65 @@
+/* $Id: SyntheticAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a synthetic attribute.
+ *
+ * @author Mark Welsh
+ * @author Eric Lafortune
+ */
+public class SyntheticAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 0;
+
+
+ protected SyntheticAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitSyntheticAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/UnknownAttrInfo.java b/src/proguard/classfile/attribute/UnknownAttrInfo.java
new file mode 100644
index 0000000..5811766
--- /dev/null
+++ b/src/proguard/classfile/attribute/UnknownAttrInfo.java
@@ -0,0 +1,70 @@
+/* $Id: UnknownAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute;
+
+
+import proguard.classfile.visitor.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of an unknown attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class UnknownAttrInfo extends AttrInfo
+{
+ public int u4attrLength;
+ public byte info[];
+
+
+ protected UnknownAttrInfo(int attrLength)
+ {
+ u4attrLength = attrLength;
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return u4attrLength;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ info = new byte[u4attrLength];
+ din.readFully(info);
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.write(info);
+ }
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitUnknownAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/Annotation.java b/src/proguard/classfile/attribute/annotation/Annotation.java
new file mode 100644
index 0000000..76cea29
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/Annotation.java
@@ -0,0 +1,134 @@
+/* $Id: Annotation.java,v 1.3 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a runtime annotation.
+ *
+ * @author Eric Lafortune
+ */
+public class Annotation implements VisitorAccepter
+{
+ private static final int CONSTANT_FIELD_SIZE = 4;
+ private static final int CONSTANT_FIELD_SIZE2 = 2;
+
+
+ public int u2typeIndex;
+ public int u2numberOfElementValuePairs;
+ public ElementValue[] elementValues;
+
+ /**
+ * An extra field pointing to the ClassFile objects referenced in the
+ * type string. This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ * References to primitive types are ignored.
+ */
+ public ClassFile[] referencedClassFiles;
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ public static Annotation create(DataInput din) throws IOException
+ {
+ Annotation annotation = new Annotation();
+ annotation.read(din);
+ return annotation;
+ }
+
+ private void read(DataInput din) throws IOException
+ {
+ u2typeIndex = din.readUnsignedShort();
+ u2numberOfElementValuePairs = din.readUnsignedShort();
+
+ elementValues = new ElementValue[u2numberOfElementValuePairs];
+
+ for (int i = 0; i < u2numberOfElementValuePairs; i++)
+ {
+ int u2elementName = din.readUnsignedShort();
+
+ elementValues[i] = ElementValue.create(din);
+
+ elementValues[i].u2elementName = u2elementName;
+ }
+ }
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public void write(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2typeIndex);
+ dout.writeShort(u2numberOfElementValuePairs);
+ for (int i = 0; i < u2numberOfElementValuePairs; i++)
+ {
+ dout.writeShort(elementValues[i].u2elementName);
+
+ elementValues[i].write(dout);
+ }
+ }
+
+
+ /**
+ * Returns the length of this annotation, expressed in bytes.
+ */
+ protected int getLength()
+ {
+ int length = CONSTANT_FIELD_SIZE;
+ for (int i = 0; i < u2numberOfElementValuePairs; i++)
+ {
+ length += CONSTANT_FIELD_SIZE2 + elementValues[i].getLength();
+ }
+
+ return length;
+ }
+
+
+ /**
+ * Applies the given visitor to all element value pairs.
+ */
+ public void elementValuesAccept(ClassFile classFile, ElementValueVisitor elementValueVisitor)
+ {
+ for (int i = 0; i < u2numberOfElementValuePairs; i++)
+ {
+ elementValues[i].accept(classFile, this, elementValueVisitor);
+ }
+ }
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttrInfo.java b/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttrInfo.java
new file mode 100644
index 0000000..37925cd
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttrInfo.java
@@ -0,0 +1,77 @@
+/* $Id: AnnotationDefaultAttrInfo.java,v 1.3 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.ClassFile;
+import proguard.classfile.attribute.*;
+
+import java.io.*;
+
+/**
+ * Representation of a runtime visible annotations attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class AnnotationDefaultAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 0;
+
+
+ public ElementValue defaultValue;
+
+
+ public AnnotationDefaultAttrInfo()
+ {
+ }
+
+
+ /**
+ * Applies the given visitor to the default element values.
+ */
+ public void defaultValueAccept(ClassFile classFile, ElementValueVisitor elementValueVisitor)
+ {
+ defaultValue.accept(classFile, null, elementValueVisitor);
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE + defaultValue.getLength();
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ defaultValue = ElementValue.create(din);
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ defaultValue.write(dout);
+ }
+
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitAnnotationDefaultAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java b/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
new file mode 100644
index 0000000..256c100
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
@@ -0,0 +1,76 @@
+/* $Id: AnnotationElementValue.java,v 1.3 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of an annotation element value.
+ *
+ * @author Eric Lafortune
+ */
+public class AnnotationElementValue extends ElementValue
+{
+ protected static final int CONSTANT_FIELD_SIZE = ElementValue.CONSTANT_FIELD_SIZE;
+
+
+ public Annotation annotationValue;
+
+
+ protected AnnotationElementValue()
+ {
+ }
+
+
+ /**
+ * Applies the given visitor to the annotation.
+ */
+ public void annotationAccept(ClassFile classFile, AnnotationVisitor annotationVisitor)
+ {
+ annotationVisitor.visitAnnotation(classFile, annotationValue);
+ }
+
+
+ // Implementations for ElementValue.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE + annotationValue.getLength();
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ annotationValue = Annotation.create(din);
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ annotationValue.write(dout);
+ }
+
+ public void accept(ClassFile classFile, Annotation annotation, ElementValueVisitor elementValueVisitor)
+ {
+ elementValueVisitor.visitAnnotationElementValue(classFile, annotation, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/AnnotationVisitor.java b/src/proguard/classfile/attribute/annotation/AnnotationVisitor.java
new file mode 100644
index 0000000..21892ec
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/AnnotationVisitor.java
@@ -0,0 +1,40 @@
+/* $Id: AnnotationVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>Annotation</code> objects. Note that there is only a single
+ * implementation of <code>Annotation</code>, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Eric Lafortune
+ */
+public interface AnnotationVisitor
+{
+ public void visitAnnotation(ClassFile classFile, Annotation annotation);
+
+// public void visitAnnotation(ClassFile classFile, MethodInfo methodInfo, int parameterIndex, Annotation annotation);
+}
diff --git a/src/proguard/classfile/attribute/annotation/ArrayElementValue.java b/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
new file mode 100644
index 0000000..e3ebbcb
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
@@ -0,0 +1,95 @@
+/* $Id: ArrayElementValue.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of an array element value.
+ *
+ * @author Eric Lafortune
+ */
+public class ArrayElementValue extends ElementValue
+{
+ protected static final int CONSTANT_FIELD_SIZE = ElementValue.CONSTANT_FIELD_SIZE + 2;
+
+
+ public int u2numberOfValues;
+ public ElementValue[] values;
+
+
+ protected ArrayElementValue()
+ {
+ }
+
+
+ // Implementations for ElementValue.
+
+ protected int getLength()
+ {
+ int length = CONSTANT_FIELD_SIZE;
+ for (int i = 0; i < u2numberOfValues; i++)
+ {
+ length += values[i].getLength();
+ }
+
+ return length;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u2numberOfValues = din.readUnsignedShort();
+ values = new ElementValue[u2numberOfValues];
+ for (int i = 0; i < u2numberOfValues; i++)
+ {
+ values[i] = ElementValue.create(din);
+ }
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2numberOfValues);
+ for (int i = 0; i < u2numberOfValues; i++)
+ {
+ values[i].write(dout);
+ }
+ }
+
+ public void accept(ClassFile classFile, Annotation annotation, ElementValueVisitor elementValueVisitor)
+ {
+ elementValueVisitor.visitArrayElementValue(classFile, annotation, this);
+ }
+
+
+ /**
+ * Applies the given visitor to all nested element values.
+ */
+ public void elementValuesAccept(ClassFile classFile, Annotation annotation, ElementValueVisitor elementValueVisitor)
+ {
+ for (int i = 0; i < u2numberOfValues; i++)
+ {
+ values[i].accept(classFile, annotation, elementValueVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/ClassElementValue.java b/src/proguard/classfile/attribute/annotation/ClassElementValue.java
new file mode 100644
index 0000000..7778a03
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/ClassElementValue.java
@@ -0,0 +1,75 @@
+/* $Id: ClassElementValue.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a class element value.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassElementValue extends ElementValue
+{
+ protected static final int CONSTANT_FIELD_SIZE = ElementValue.CONSTANT_FIELD_SIZE + 2;
+
+
+ public int u2classInfoIndex;
+
+ /**
+ * An extra field pointing to the ClassFile objects referenced in the
+ * type name string. This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ * References to primitive types are ignored.
+ */
+ public ClassFile[] referencedClassFiles;
+
+
+ protected ClassElementValue()
+ {
+ }
+
+
+ // Implementations for ElementValue.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u2classInfoIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2classInfoIndex);
+ }
+
+ public void accept(ClassFile classFile, Annotation annotation, ElementValueVisitor elementValueVisitor)
+ {
+ elementValueVisitor.visitClassElementValue(classFile, annotation, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/ConstantElementValue.java b/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
new file mode 100644
index 0000000..2c3997b
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
@@ -0,0 +1,67 @@
+/* $Id: ConstantElementValue.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of a constant element value.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantElementValue extends ElementValue
+{
+ protected static final int CONSTANT_FIELD_SIZE = ElementValue.CONSTANT_FIELD_SIZE + 2;
+
+
+ public int u2constantValueIndex;
+
+
+ protected ConstantElementValue()
+ {
+ }
+
+
+ // Implementations for ElementValue.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u2constantValueIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2constantValueIndex);
+ }
+
+ public void accept(ClassFile classFile, Annotation annotation, ElementValueVisitor elementValueVisitor)
+ {
+ elementValueVisitor.visitConstantElementValue(classFile, annotation, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/ElementValue.java b/src/proguard/classfile/attribute/annotation/ElementValue.java
new file mode 100644
index 0000000..d4754fb
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/ElementValue.java
@@ -0,0 +1,147 @@
+/* $Id: ElementValue.java,v 1.4 2004/11/27 10:09:26 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of an element value.
+ *
+ * @author Eric Lafortune
+ */
+public abstract class ElementValue implements VisitorAccepter
+{
+ protected static final int CONSTANT_FIELD_SIZE = 1;
+
+
+ public int u1tag;
+
+ /**
+ * An extra field for the optional element name. It is used in element value
+ * pairs of annotations. Otherwise, it is 0.
+ */
+ public int u2elementName;
+
+ /**
+ * An extra field pointing to the referenced <code>MethodInfo</code>
+ * object, if applicable. This field is typically filled out by the
+ * <code>{@link ClassFileReferenceInitializer}</code>.
+ */
+ public MethodInfo referencedMethodInfo;
+
+ /**
+ * An extra field in which visitors can store information.
+ */
+ public Object visitorInfo;
+
+
+ public static ElementValue create(DataInput din) throws IOException
+ {
+ int u1tag = din.readUnsignedByte();
+ ElementValue elementValue = createElementValue(u1tag);
+
+ elementValue.u1tag = u1tag;
+ elementValue.readInfo(din);
+
+ return elementValue;
+ }
+
+
+ private static ElementValue createElementValue(int u1tag)
+ {
+ switch (u1tag)
+ {
+ case ClassConstants.INTERNAL_TYPE_BOOLEAN:
+ case ClassConstants.INTERNAL_TYPE_BYTE:
+ case ClassConstants.INTERNAL_TYPE_CHAR:
+ case ClassConstants.INTERNAL_TYPE_SHORT:
+ case ClassConstants.INTERNAL_TYPE_INT:
+ case ClassConstants.INTERNAL_TYPE_FLOAT:
+ case ClassConstants.INTERNAL_TYPE_LONG:
+ case ClassConstants.INTERNAL_TYPE_DOUBLE:
+ case ClassConstants.ELEMENT_VALUE_STRING_CONSTANT: return new ConstantElementValue();
+
+ case ClassConstants.ELEMENT_VALUE_ENUM_CONSTANT: return new EnumConstantElementValue();
+ case ClassConstants.ELEMENT_VALUE_CLASS: return new ClassElementValue();
+ case ClassConstants.ELEMENT_VALUE_ANNOTATION: return new AnnotationElementValue();
+ case ClassConstants.ELEMENT_VALUE_ARRAY: return new ArrayElementValue();
+ }
+
+ throw new IllegalArgumentException("Unknown element value tag ["+u1tag+"]");
+ }
+
+
+ protected ElementValue()
+ {
+ }
+
+
+ /**
+ * Exports the representation to a DataOutput stream.
+ */
+ public final void write(DataOutput dout) throws IOException
+ {
+ dout.writeByte(u1tag);
+ writeInfo(dout);
+ }
+
+
+ // Abstract methods to be implemented by extensions.
+
+ /**
+ * Returns the length of this element value, expressed in bytes.
+ */
+ protected abstract int getLength();
+
+
+ /**
+ * Reads the data following the header.
+ */
+ protected abstract void readInfo(DataInput din) throws IOException;
+
+
+ /**
+ * Exports data following the header to a DataOutput stream.
+ */
+ protected abstract void writeInfo(DataOutput dout) throws IOException;
+
+
+ /**
+ * Accepts the given visitor.
+ */
+ public abstract void accept(ClassFile classFile, Annotation annotation, ElementValueVisitor elementValueVisitor);
+
+
+
+ // Implementations for VisitorAccepter.
+
+ public Object getVisitorInfo()
+ {
+ return visitorInfo;
+ }
+
+ public void setVisitorInfo(Object visitorInfo)
+ {
+ this.visitorInfo = visitorInfo;
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/ElementValueVisitor.java b/src/proguard/classfile/attribute/annotation/ElementValueVisitor.java
new file mode 100644
index 0000000..2bc4b29
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/ElementValueVisitor.java
@@ -0,0 +1,40 @@
+/* $Id: ElementValueVisitor.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of <code>ElementValue</code>
+ * objects.
+ *
+ * @author Eric Lafortune
+ */
+public interface ElementValueVisitor
+{
+ public void visitConstantElementValue( ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue);
+ public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue);
+ public void visitClassElementValue( ClassFile classFile, Annotation annotation, ClassElementValue classElementValue);
+ public void visitAnnotationElementValue( ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue);
+ public void visitArrayElementValue( ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue);
+}
diff --git a/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java b/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
new file mode 100644
index 0000000..21be5d5
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
@@ -0,0 +1,78 @@
+/* $Id: EnumConstantElementValue.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 1999 Mark Welsh (markw at retrologic.com)
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+/**
+ * Representation of an enumeration constant element value.
+ *
+ * @author Eric Lafortune
+ */
+public class EnumConstantElementValue extends ElementValue
+{
+ protected static final int CONSTANT_FIELD_SIZE = ElementValue.CONSTANT_FIELD_SIZE + 4;
+
+
+ public int u2typeNameIndex;
+ public int u2constantNameIndex;
+
+ /**
+ * An extra field pointing to the ClassFile objects referenced in the
+ * type name string. This field is filled out by the <code>{@link
+ * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+ * References to primitive types are ignored.
+ */
+ public ClassFile[] referencedClassFiles;
+
+
+ protected EnumConstantElementValue()
+ {
+ }
+
+
+ // Implementations for ElementValue.
+
+ protected int getLength()
+ {
+ return CONSTANT_FIELD_SIZE;
+ }
+
+ protected void readInfo(DataInput din) throws IOException
+ {
+ u2typeNameIndex = din.readUnsignedShort();
+ u2constantNameIndex = din.readUnsignedShort();
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2typeNameIndex);
+ dout.writeShort(u2constantNameIndex);
+ }
+
+ public void accept(ClassFile classFile, Annotation annotation, ElementValueVisitor elementValueVisitor)
+ {
+ elementValueVisitor.visitEnumConstantElementValue(classFile, annotation, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeAnnotationsAttrInfo.java
new file mode 100644
index 0000000..17a48b7
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/RuntimeAnnotationsAttrInfo.java
@@ -0,0 +1,92 @@
+/* $Id: RuntimeAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+import java.io.*;
+
+/**
+ * Representation of a runtime annotations attribute.
+ *
+ * @author Eric Lafortune
+ */
+public abstract class RuntimeAnnotationsAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ public int u2numberOfAnnotations;
+ public Annotation[] annotations;
+
+
+ protected RuntimeAnnotationsAttrInfo()
+ {
+ }
+
+
+ /**
+ * Applies the given visitor to all annotations.
+ */
+ public void annotationsAccept(ClassFile classFile, AnnotationVisitor annotationVisitor)
+ {
+ for (int i = 0; i < u2numberOfAnnotations; i++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of Annotation.
+ annotationVisitor.visitAnnotation(classFile, annotations[i]);
+ }
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ int length = CONSTANT_FIELD_SIZE;
+ for (int i = 0; i < u2numberOfAnnotations; i++)
+ {
+ length += annotations[i].getLength();
+ }
+
+ return length;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ u2numberOfAnnotations = din.readUnsignedShort();
+ annotations = new Annotation[u2numberOfAnnotations];
+ for (int i = 0; i < u2numberOfAnnotations; i++)
+ {
+ annotations[i] = Annotation.create(din);
+ }
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(u2numberOfAnnotations);
+ for (int i = 0; i < u2numberOfAnnotations; i++)
+ {
+ annotations[i].write(dout);
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttrInfo.java
new file mode 100644
index 0000000..89d755e
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttrInfo.java
@@ -0,0 +1,44 @@
+/* $Id: RuntimeInvisibleAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.ClassFile;
+import proguard.classfile.attribute.AttrInfoVisitor;
+
+/**
+ * Representation of a runtime invisible annotations attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class RuntimeInvisibleAnnotationsAttrInfo extends RuntimeAnnotationsAttrInfo
+{
+ public RuntimeInvisibleAnnotationsAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitRuntimeInvisibleAnnotationAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttrInfo.java
new file mode 100644
index 0000000..1c5387b
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttrInfo.java
@@ -0,0 +1,44 @@
+/* $Id: RuntimeInvisibleParameterAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.ClassFile;
+import proguard.classfile.attribute.AttrInfoVisitor;
+
+/**
+ * Representation of a runtime invisible parameter annotations attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class RuntimeInvisibleParameterAnnotationsAttrInfo extends RuntimeParameterAnnotationsAttrInfo
+{
+ public RuntimeInvisibleParameterAnnotationsAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitRuntimeInvisibleParameterAnnotationAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeParameterAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeParameterAnnotationsAttrInfo.java
new file mode 100644
index 0000000..0c2d191
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/RuntimeParameterAnnotationsAttrInfo.java
@@ -0,0 +1,120 @@
+/* $Id: RuntimeParameterAnnotationsAttrInfo.java,v 1.2 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.AttrInfo;
+
+import java.io.*;
+
+/**
+ * Representation of a runtime parameter annotations attribute.
+ *
+ * @author Eric Lafortune
+ */
+public abstract class RuntimeParameterAnnotationsAttrInfo extends AttrInfo
+{
+ private static final int CONSTANT_FIELD_SIZE = 2;
+
+
+ //public int u2numberOfParameters;
+ //public int[] u2numberOfAnnotations;
+ public Annotation[][] parameterAnnotations;
+
+
+ protected RuntimeParameterAnnotationsAttrInfo()
+ {
+ }
+
+
+ /**
+ * Applies the given visitor to all annotations.
+ */
+ public void annotationsAccept(ClassFile classFile, AnnotationVisitor annotationVisitor)
+ {
+ for (int i = 0; i < parameterAnnotations.length; i++)
+ {
+ Annotation[] annotations = parameterAnnotations[i];
+ for (int j = 0; j < annotations.length; i++)
+ {
+ // We don't need double dispatching here, since there is only one
+ // type of Annotation.
+ //annotationVisitor.visitAnnotation(classFile, methodInfo, i, annotations[j]);
+ annotationVisitor.visitAnnotation(classFile, annotations[j]);
+ }
+ }
+ }
+
+
+ // Implementations for AttrInfo.
+
+ protected int getLength()
+ {
+ int length = CONSTANT_FIELD_SIZE;
+
+ for (int i = 0; i < parameterAnnotations.length; i++)
+ {
+ length += CONSTANT_FIELD_SIZE;
+
+ Annotation[] annotations = parameterAnnotations[i];
+ for (int j = 0; j < annotations.length; i++)
+ {
+ length += annotations[j].getLength();
+ }
+ }
+
+ return length;
+ }
+
+ protected void readInfo(DataInput din, ClassFile classFile) throws IOException
+ {
+ int u2numberOfParameters = din.readUnsignedShort();
+ parameterAnnotations = new Annotation[u2numberOfParameters][];
+
+ for (int i = 0; i < u2numberOfParameters; i++)
+ {
+ int u2numberOfAnnotations = din.readUnsignedShort();
+ Annotation[] annotations = new Annotation[u2numberOfAnnotations];
+
+ for (int j = 0; j < u2numberOfAnnotations; j++)
+ {
+ annotations[j] = Annotation.create(din);
+ }
+
+ parameterAnnotations[i] = annotations;
+ }
+ }
+
+ protected void writeInfo(DataOutput dout) throws IOException
+ {
+ dout.writeShort(parameterAnnotations.length);
+ for (int i = 0; i < parameterAnnotations.length; i++)
+ {
+ Annotation[] annotations = parameterAnnotations[i];
+
+ dout.writeShort(annotations.length);
+ for (int j = 0; j < annotations.length; i++)
+ {
+ annotations[j].write(dout);
+ }
+ }
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttrInfo.java
new file mode 100644
index 0000000..9ea8fc8
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttrInfo.java
@@ -0,0 +1,44 @@
+/* $Id: RuntimeVisibleAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.ClassFile;
+import proguard.classfile.attribute.AttrInfoVisitor;
+
+/**
+ * Representation of a runtime visible annotations attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class RuntimeVisibleAnnotationsAttrInfo extends RuntimeAnnotationsAttrInfo
+{
+ public RuntimeVisibleAnnotationsAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitRuntimeVisibleAnnotationAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttrInfo.java
new file mode 100644
index 0000000..a1ee4a3
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttrInfo.java
@@ -0,0 +1,44 @@
+/* $Id: RuntimeVisibleParameterAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.attribute.annotation;
+
+import proguard.classfile.ClassFile;
+import proguard.classfile.attribute.AttrInfoVisitor;
+
+/**
+ * Representation of a runtime visible parameter annotations attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class RuntimeVisibleParameterAnnotationsAttrInfo extends RuntimeParameterAnnotationsAttrInfo
+{
+ public RuntimeVisibleParameterAnnotationsAttrInfo()
+ {
+ }
+
+
+ // Implementations for AttrInfo.
+
+ public void accept(ClassFile classFile, AttrInfoVisitor attrInfoVisitor)
+ {
+ attrInfoVisitor.visitRuntimeVisibleParameterAnnotationAttrInfo(classFile, this);
+ }
+}
diff --git a/src/proguard/classfile/attribute/annotation/package.html b/src/proguard/classfile/attribute/annotation/package.html
new file mode 100644
index 0000000..6aacff3
--- /dev/null
+++ b/src/proguard/classfile/attribute/annotation/package.html
@@ -0,0 +1,4 @@
+<body>
+This package contains classes to represent the annotation attributes inside
+class files.
+</body>
diff --git a/src/proguard/classfile/attribute/package.html b/src/proguard/classfile/attribute/package.html
new file mode 100644
index 0000000..d17caaa
--- /dev/null
+++ b/src/proguard/classfile/attribute/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains classes to represent the attributes inside class files.
+</body>
diff --git a/src/proguard/classfile/editor/CodeAttrInfoEditor.java b/src/proguard/classfile/editor/CodeAttrInfoEditor.java
new file mode 100644
index 0000000..c882cb9
--- /dev/null
+++ b/src/proguard/classfile/editor/CodeAttrInfoEditor.java
@@ -0,0 +1,667 @@
+/* $Id: CodeAttrInfoEditor.java,v 1.9 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This AttrInfoVisitor accumulates specified changes to code, and then applies
+ * these accumulated changes to the code attributes that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class CodeAttrInfoEditor
+ implements AttrInfoVisitor,
+ InstructionVisitor,
+ ExceptionInfoVisitor,
+ LineNumberInfoVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor
+{
+ private int codeLength;
+ private boolean modified;
+ /*private*/public Instruction[] preInsertions;
+ /*private*/public Instruction[] postInsertions;
+ private boolean[] deleted;
+
+ private int[] instructionOffsetMap;
+
+ private StackSizeUpdater stackSizeUpdater;
+
+
+ /**
+ * Creates a new CodeAttrInfoEditor.
+ * @param codeLength an estimate of the maximum length of all the code that
+ * will be edited.
+ */
+ public CodeAttrInfoEditor(int codeLength)
+ {
+ this.codeLength = codeLength;
+
+ preInsertions = new Instruction[codeLength];
+ postInsertions = new Instruction[codeLength];
+ deleted = new boolean[codeLength];
+
+ stackSizeUpdater = new StackSizeUpdater(codeLength);
+ }
+
+
+ /**
+ * Resets the accumulated code changes.
+ * @param codeLength the length of the code that will be edited next.
+ */
+ public void reset(int codeLength)
+ {
+ this.codeLength = codeLength;
+
+ // Try to reuse the previous arrays.
+ if (preInsertions.length < codeLength)
+ {
+ preInsertions = new Instruction[codeLength];
+ postInsertions = new Instruction[codeLength];
+ deleted = new boolean[codeLength];
+ }
+ else
+ {
+ for (int index = 0; index < codeLength; index++)
+ {
+ preInsertions[index] = null;
+ postInsertions[index] = null;
+ deleted[index] = false;
+ }
+ }
+
+ modified = false;
+ }
+
+
+ /**
+ * Remembers to replace the instruction at the given offset by the given
+ * instruction.
+ * @param instructionOffset the offset of the instruction to be replaced.
+ * @param instruction the new instruction.
+ */
+ public void replaceInstruction(int instructionOffset, Instruction instruction)
+ {
+ deleteInstruction(instructionOffset);
+ insertBeforeInstruction(instructionOffset, instruction);
+ }
+
+
+ /**
+ * Remembers to replace the instruction at the given offset by the given
+ * instruction.
+ * @param instructionOffset the offset of the instruction to be replaced.
+ * @param instruction the new instruction.
+ */
+ public void replaceInstruction2(int instructionOffset, Instruction instruction)
+ {
+ deleteInstruction(instructionOffset);
+ insertAfterInstruction(instructionOffset, instruction);
+ }
+
+
+ /**
+ * Remembers to place the given instruction right before the instruction
+ * at the given offset.
+ * @param instructionOffset the offset of the instruction.
+ * @param instruction the new instruction.
+ */
+ public void insertBeforeInstruction(int instructionOffset, Instruction instruction)
+ {
+ if (instructionOffset < 0 ||
+ instructionOffset >= codeLength)
+ {
+ throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
+ }
+
+ preInsertions[instructionOffset] = instruction;
+
+ modified = true;
+ }
+
+
+ /**
+ * Remembers to place the given instruction right after the instruction
+ * at the given offset.
+ * @param instructionOffset the offset of the instruction.
+ * @param instruction the new instruction.
+ */
+ public void insertAfterInstruction(int instructionOffset, Instruction instruction)
+ {
+ if (instructionOffset < 0 ||
+ instructionOffset >= codeLength)
+ {
+ throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
+ }
+
+ postInsertions[instructionOffset] = instruction;
+
+ modified = true;
+ }
+
+
+ /**
+ * Remembers to delete the instruction at the given offset.
+ * @param instructionOffset the offset of the instruction to be deleted.
+ */
+ public void deleteInstruction(int instructionOffset)
+ {
+ if (instructionOffset < 0 ||
+ instructionOffset >= codeLength)
+ {
+ throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
+ }
+
+ deleted[instructionOffset] = true;
+
+ modified = true;
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset has been modified
+ * in any way.
+ */
+ public boolean isModified(int instructionOffset)
+ {
+ return preInsertions[instructionOffset] != null ||
+ postInsertions[instructionOffset] != null ||
+ deleted[instructionOffset];
+
+ }
+
+
+ /**
+ * Returns whether any instruction has been modified in any way.
+ */
+ public boolean isModified()
+ {
+ return modified;
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ // Avoid doing any work if nothing is changing anyway.
+ if (!modified)
+ {
+ return;
+ }
+
+ // Move and remap the instructions.
+ codeAttrInfo.u4codeLength =
+ moveInstructions(classFile, methodInfo, codeAttrInfo);
+
+ // Remap the exception table.
+ codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
+
+ // Remap the line number table and the local variable table.
+ codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+
+ // Remove exceptions with empty code blocks.
+ codeAttrInfo.u2exceptionTableLength =
+ removeEmptyExceptions(codeAttrInfo.exceptionTable,
+ codeAttrInfo.u2exceptionTableLength);
+
+ // Update maximum stack size.
+ stackSizeUpdater.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
+ }
+
+
+ // Implementations for LineNumberInfoVisitor.
+
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo)
+ {
+ // Remap all line number table entries.
+ lineNumberTableAttrInfo.lineNumbersAccept(classFile, methodInfo, codeAttrInfo, this);
+
+ // Remove line numbers with empty code blocks.
+ lineNumberTableAttrInfo.u2lineNumberTableLength =
+ removeEmptyLineNumbers(lineNumberTableAttrInfo.lineNumberTable,
+ lineNumberTableAttrInfo.u2lineNumberTableLength,
+ codeAttrInfo.u4codeLength);
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ // Remap all local variable table entries.
+ localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+
+ // Remove local variables with empty code blocks.
+ localVariableTableAttrInfo.u2localVariableTableLength =
+ removeEmptyLocalVariables(localVariableTableAttrInfo.localVariableTable,
+ localVariableTableAttrInfo.u2localVariableTableLength);
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ // Remap all local variable table entries.
+ localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+
+ // Remove local variables with empty code blocks.
+ localVariableTypeTableAttrInfo.u2localVariableTypeTableLength =
+ removeEmptyLocalVariableTypes(localVariableTypeTableAttrInfo.localVariableTypeTable,
+ localVariableTypeTableAttrInfo.u2localVariableTypeTableLength);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+
+
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
+ {
+ // Adjust the branch offset.
+ branchInstruction.branchOffset = remapBranchOffset(offset,
+ branchInstruction.branchOffset);
+ }
+
+
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ // Adjust the default jump offset.
+ tableSwitchInstruction.defaultOffset = remapBranchOffset(offset,
+ tableSwitchInstruction.defaultOffset);
+
+ // Adjust the jump offsets.
+ remapJumpOffsets(offset,
+ tableSwitchInstruction.jumpOffsets,
+ tableSwitchInstruction.highCase -
+ tableSwitchInstruction.lowCase + 1);
+ }
+
+
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ // Adjust the default jump offset.
+ lookUpSwitchInstruction.defaultOffset = remapBranchOffset(offset,
+ lookUpSwitchInstruction.defaultOffset);
+
+ // Adjust the jump offsets.
+ remapJumpOffsets(offset,
+ lookUpSwitchInstruction.jumpOffsets,
+ lookUpSwitchInstruction.jumpOffsetCount);
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, ExceptionInfo exceptionInfo)
+ {
+ // Remap the code offsets. Note that the instruction offset map also has
+ // an entry for the first offset after the code, for u2endpc.
+ exceptionInfo.u2startpc = remapInstructionOffset(exceptionInfo.u2startpc);
+ exceptionInfo.u2endpc = remapInstructionOffset(exceptionInfo.u2endpc);
+ exceptionInfo.u2handlerpc = remapInstructionOffset(exceptionInfo.u2handlerpc);
+ }
+
+
+ // Implementations for LineNumberInfoVisitor.
+
+ public void visitLineNumberInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberInfo lineNumberInfo)
+ {
+ // Remap the code offset.
+ lineNumberInfo.u2startpc = remapInstructionOffset(lineNumberInfo.u2startpc);
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+ {
+ // Remap the code offset and length.
+ localVariableInfo.u2length = remapBranchOffset(localVariableInfo.u2startpc,
+ localVariableInfo.u2length);
+ localVariableInfo.u2startpc = remapInstructionOffset(localVariableInfo.u2startpc);
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ // Remap the code offset and length.
+ localVariableTypeInfo.u2length = remapBranchOffset(localVariableTypeInfo.u2startpc,
+ localVariableTypeInfo.u2length);
+ localVariableTypeInfo.u2startpc = remapInstructionOffset(localVariableTypeInfo.u2startpc);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Modifies the given code based on the previously specified changes.
+ *
+ * @param classFile the class file of the code to be changed.
+ * @param methodInfo the method of the code to be changed.
+ * @param codeAttrInfo the code to be changed.
+ * @return the new code length.
+ */
+ private int moveInstructions(ClassFile classFile,
+ MethodInfo methodInfo,
+ CodeAttrInfo codeAttrInfo)
+ {
+ byte[] oldCode = codeAttrInfo.code;
+ int oldLength = codeAttrInfo.u4codeLength;
+
+ // Make sure there is a sufficiently large instruction offset map.
+ if (instructionOffsetMap == null ||
+ instructionOffsetMap.length < oldLength + 1)
+ {
+ instructionOffsetMap = new int[oldLength + 1];
+ }
+
+ // Fill out the offset map that specifies the new instruction offsets,
+ // given their current instruction offsets, by going over the
+ // instructions, deleting and inserting instructions as specified.
+ int oldOffset = 0;
+ int newOffset = 0;
+ boolean lengthIncreased = false;
+ do
+ {
+ // Get the next instruction.
+ Instruction instruction = InstructionFactory.create(oldCode, oldOffset);
+
+ // Compute the mapping of the instruction.
+ newOffset = mapInstruction(instruction, oldOffset, newOffset);
+
+ oldOffset += instruction.length(oldOffset);
+
+ // Is the new instruction exceeding the available space?
+ if (newOffset > oldOffset)
+ {
+ // Remember to create a new code array later on.
+ lengthIncreased = true;
+ }
+ }
+ while (oldOffset < oldLength);
+
+ // Also add an entry for the first offset after the code.
+ instructionOffsetMap[oldOffset] = newOffset;
+
+ // Create a new code array if necessary.
+ if (lengthIncreased)
+ {
+ codeAttrInfo.code = new byte[newOffset];
+ }
+
+ // Now actually move the instructions based on this map.
+ oldOffset = 0;
+ do
+ {
+ // Get the next instruction.
+ Instruction instruction = InstructionFactory.create(oldCode, oldOffset);
+
+ // Move the instruction to its new offset.
+ moveInstruction(classFile, methodInfo, codeAttrInfo, oldOffset, instruction);
+
+ oldOffset += instruction.length(oldOffset);
+ }
+ while (oldOffset < oldLength);
+
+ return newOffset;
+ }
+
+
+ /**
+ * Fills out the instruction offset map for the given instruction with its
+ * new offset.
+ * @param instruction the instruction to be moved.
+ * @param oldOffset the instruction's old offset.
+ * @param newOffset the instruction's new offset.
+ * @return the next new offset.
+ */
+ private int mapInstruction(Instruction instruction,
+ int oldOffset,
+ int newOffset)
+ {
+ instructionOffsetMap[oldOffset] = newOffset;
+
+ // Account for the pre-inserted instruction, if any.
+ Instruction preInstruction = preInsertions[oldOffset];
+ if (preInstruction != null)
+ {
+ newOffset += preInstruction.length(newOffset);
+ }
+
+ // Account for the current instruction, if it shouldn't be deleted.
+ if (!deleted[oldOffset] )
+ {
+ // Note that the instruction's length may change at its new offset,
+ // e.g. if it is a switch instruction.
+ newOffset += instruction.length(newOffset);
+ }
+
+ // Account for the post-inserted instruction, if any.
+ Instruction postInstruction = postInsertions[oldOffset];
+ if (postInstruction != null)
+ {
+ newOffset += postInstruction.length(newOffset);
+ }
+
+ return newOffset;
+ }
+
+
+ /**
+ * Moves the given instruction to its new offset.
+ */
+ private void moveInstruction(ClassFile classFile,
+ MethodInfo methodInfo,
+ CodeAttrInfo codeAttrInfo,
+ int oldOffset,
+ Instruction instruction)
+ {
+ int newOffset = remapInstructionOffset(oldOffset);
+
+ // Remap and insert the pre-inserted instruction, if any.
+ Instruction preInstruction = preInsertions[oldOffset];
+ if (preInstruction != null)
+ {
+ preInstruction.accept(classFile, methodInfo, codeAttrInfo, oldOffset, this);
+
+ preInstruction.write(codeAttrInfo, newOffset);
+
+ newOffset += preInstruction.length(newOffset);
+ }
+
+ // Remap and insert the current instruction, if it shouldn't be deleted.
+ if (!deleted[oldOffset])
+ {
+ instruction.accept(classFile, methodInfo, codeAttrInfo, oldOffset, this);
+
+ instruction.write(codeAttrInfo, newOffset);
+
+ newOffset += instruction.length(newOffset);
+ }
+
+ // Remap and insert the post-inserted instruction, if any.
+ Instruction postInstruction = postInsertions[oldOffset];
+ if (postInstruction != null)
+ {
+ postInstruction.accept(classFile, methodInfo, codeAttrInfo, oldOffset, this);
+
+ postInstruction.write(codeAttrInfo, newOffset);
+ }
+ }
+
+
+ /**
+ * Adjusts the given jump offsets for the instruction at the given offset.
+ */
+ private void remapJumpOffsets(int offset, int[] jumpOffsets, int length)
+ {
+ for (int index = 0; index < length; index++)
+ {
+ jumpOffsets[index] = remapBranchOffset(offset, jumpOffsets[index]);
+ }
+ }
+
+
+ /**
+ * Computes the new branch offset for the instruction at the given offset
+ * with the given branch offset.
+ */
+ private int remapBranchOffset(int offset, int branchOffset)
+ {
+ return remapInstructionOffset(offset + branchOffset) -
+ remapInstructionOffset(offset);
+ }
+
+
+ /**
+ * Computes the new instruction offset for the instruction at the given offset.
+ */
+ private int remapInstructionOffset(int offset)
+ {
+ if (offset < 0 ||
+ offset > codeLength)
+ {
+ throw new IllegalArgumentException("Invalid instruction offset ["+offset+"] in code with length ["+codeLength+"]");
+ }
+
+ return instructionOffsetMap[offset];
+ }
+
+
+ /**
+ * Returns the given list of exceptions, without the ones that have empty
+ * code blocks.
+ */
+ private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos,
+ int exceptionInfoCount)
+ {
+ // Overwrite all empty exceptions.
+ int newIndex = 0;
+ for (int index = 0; index < exceptionInfoCount; index++)
+ {
+ ExceptionInfo exceptionInfo = exceptionInfos[index];
+ if (exceptionInfo.u2startpc < exceptionInfo.u2endpc)
+ {
+ exceptionInfos[newIndex++] = exceptionInfo;
+ }
+ }
+
+ return newIndex;
+ }
+
+
+ /**
+ * Returns the given list of line numbers, without the ones that have empty
+ * code blocks.
+ */
+ private int removeEmptyLineNumbers(LineNumberInfo[] lineNumberInfos,
+ int lineNumberInfoCount,
+ int codeLength)
+ {
+ // Overwrite all empty localVariables.
+ int newIndex = 0;
+ for (int index = 0; index < lineNumberInfoCount; index++)
+ {
+ LineNumberInfo lineNumberInfo = lineNumberInfos[index];
+ int startpc = lineNumberInfo.u2startpc;
+ if ( startpc < codeLength &&
+ (index == 0 || startpc > lineNumberInfos[index-1].u2startpc))
+ {
+ lineNumberInfos[newIndex++] = lineNumberInfo;
+ }
+ }
+
+ return newIndex;
+ }
+
+
+ /**
+ * Returns the given list of local variables, without the ones that have empty
+ * code blocks.
+ */
+ private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos,
+ int localVariableInfoCount)
+ {
+ // Overwrite all empty exceptions.
+ int newIndex = 0;
+ for (int index = 0; index < localVariableInfoCount; index++)
+ {
+ LocalVariableInfo localVariableInfo = localVariableInfos[index];
+ if (localVariableInfo.u2length > 0)
+ {
+ localVariableInfos[newIndex++] = localVariableInfo;
+ }
+ }
+
+ return newIndex;
+ }
+
+
+ /**
+ * Returns the given list of local variable types, without the ones that
+ * have empty code blocks.
+ */
+ private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos,
+ int localVariableTypeInfoCount)
+ {
+ // Overwrite all empty exceptions.
+ int newIndex = 0;
+ for (int index = 0; index < localVariableTypeInfoCount; index++)
+ {
+ LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index];
+ if (localVariableTypeInfo.u2length > 0)
+ {
+ localVariableTypeInfos[newIndex++] = localVariableTypeInfo;
+ }
+ }
+
+ return newIndex;
+ }
+}
diff --git a/src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java b/src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java
new file mode 100644
index 0000000..6e0b678
--- /dev/null
+++ b/src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java
@@ -0,0 +1,76 @@
+/* $Id: CodeAttrInfoEditorResetter.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This AttrInfoVisitor resets it CodeAttrInfoEditor whenever it visits a
+ * code attribute.
+ *
+ * @author Eric Lafortune
+ */
+public class CodeAttrInfoEditorResetter implements AttrInfoVisitor
+{
+ private CodeAttrInfoEditor codeAttrInfoEditor;
+
+
+ /**
+ * Creates a new CodeAttrInfoEditorResetter.
+ * @param codeAttrInfoEditor the code attribute editor that will be reset.
+ */
+ public CodeAttrInfoEditorResetter(CodeAttrInfoEditor codeAttrInfoEditor)
+ {
+ this.codeAttrInfoEditor = codeAttrInfoEditor;
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ codeAttrInfoEditor.reset(codeAttrInfo.u4codeLength);
+ }
+}
diff --git a/src/proguard/classfile/editor/ComparableCpInfo.java b/src/proguard/classfile/editor/ComparableCpInfo.java
new file mode 100644
index 0000000..3b7c539
--- /dev/null
+++ b/src/proguard/classfile/editor/ComparableCpInfo.java
@@ -0,0 +1,177 @@
+/* $Id: ComparableCpInfo.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This class is a <code>Comparable</code> wrapper of <code>CpInfo</code>
+ * objects. It can store an index, in order to identify the constant pool
+ * entry after it has been sorted. The comparison is primarily based on the
+ * types of the constant pool entries, and secondarily on the contents of
+ * the constant pool entries.
+ *
+ * @author Eric Lafortune
+ */
+class ComparableCpInfo implements Comparable, CpInfoVisitor
+{
+ private static int[] PRIORITIES = new int[13];
+ static
+ {
+ PRIORITIES[ClassConstants.CONSTANT_Class] = 0;
+ PRIORITIES[ClassConstants.CONSTANT_Fieldref] = 1;
+ PRIORITIES[ClassConstants.CONSTANT_Methodref] = 2;
+ PRIORITIES[ClassConstants.CONSTANT_InterfaceMethodref] = 3;
+ PRIORITIES[ClassConstants.CONSTANT_String] = 4;
+ PRIORITIES[ClassConstants.CONSTANT_Integer] = 5;
+ PRIORITIES[ClassConstants.CONSTANT_Float] = 6;
+ PRIORITIES[ClassConstants.CONSTANT_Long] = 7;
+ PRIORITIES[ClassConstants.CONSTANT_Double] = 8;
+ PRIORITIES[ClassConstants.CONSTANT_NameAndType] = 9;
+ PRIORITIES[ClassConstants.CONSTANT_Utf8] = 10;
+ }
+
+ private ClassFile classFile;
+ private int thisIndex;
+ private CpInfo thisCpInfo;
+ private CpInfo otherCpInfo;
+ private int result;
+
+
+ public ComparableCpInfo(ClassFile classFile, int index, CpInfo cpInfo)
+ {
+ this.classFile = classFile;
+ this.thisIndex = index;
+ this.thisCpInfo = cpInfo;
+ }
+
+
+ public int getIndex()
+ {
+ return thisIndex;
+ }
+
+
+ public CpInfo getCpInfo()
+ {
+ return thisCpInfo;
+ }
+
+
+ // Implementations for Comparable.
+
+ public int compareTo(Object other)
+ {
+ ComparableCpInfo otherComparableCpInfo = (ComparableCpInfo)other;
+
+ otherCpInfo = otherComparableCpInfo.thisCpInfo;
+
+ // Compare based on the original indices, if the actual constant pool
+ // entries are the same.
+ if (thisCpInfo == otherCpInfo)
+ {
+ int otherIndex = otherComparableCpInfo.thisIndex;
+
+ return thisIndex < otherIndex ? -1 :
+ thisIndex == otherIndex ? 0 :
+ 1;
+ }
+
+ // Compare based on the tags, if they are different.
+ int thisTag = thisCpInfo.getTag();
+ int otherTag = otherCpInfo.getTag();
+
+ if (thisTag != otherTag)
+ {
+ return PRIORITIES[thisTag] < PRIORITIES[otherTag] ? -1 : 1;
+ }
+
+ // Otherwise compare based on the contents of the CpInfo objects.
+ thisCpInfo.accept(classFile, this);
+
+ return result;
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo)
+ {
+ // In JDK 1.4, we can use Integer.compare(a,b).
+ result = new Integer(integerCpInfo.getValue()).compareTo(new Integer(((IntegerCpInfo)otherCpInfo).getValue()));
+ }
+
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo)
+ {
+ // In JDK 1.4, we can use Long.compare(a,b).
+ result = new Long(longCpInfo.getValue()).compareTo(new Long(((LongCpInfo)otherCpInfo).getValue()));
+ }
+
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo)
+ {
+ // In JDK 1.4, we can use Float.compare(a,b).
+ result = new Float(floatCpInfo.getValue()).compareTo(new Float(((FloatCpInfo)otherCpInfo).getValue()));
+ }
+
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo)
+ {
+ // In JDK 1.4, we can use Double.compare(a,b).
+ result = new Double(doubleCpInfo.getValue()).compareTo(new Double(((DoubleCpInfo)otherCpInfo).getValue()));
+ }
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ result = stringCpInfo.getString(classFile).compareTo(((StringCpInfo)otherCpInfo).getString(classFile));
+ }
+
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
+ {
+ result = utf8CpInfo.getString().compareTo(((Utf8CpInfo)otherCpInfo).getString());
+ }
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ result = fieldrefCpInfo.getName(classFile).compareTo(((FieldrefCpInfo)otherCpInfo).getName(classFile));
+ }
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ result = interfaceMethodrefCpInfo.getName(classFile).compareTo(((InterfaceMethodrefCpInfo)otherCpInfo).getName(classFile));
+ }
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ result = methodrefCpInfo.getName(classFile).compareTo(((MethodrefCpInfo)otherCpInfo).getName(classFile));
+ }
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ result = classCpInfo.getName(classFile).compareTo(((ClassCpInfo)otherCpInfo).getName(classFile));
+ }
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ result = nameAndTypeCpInfo.getName(classFile).compareTo(((NameAndTypeCpInfo)otherCpInfo).getName(classFile));
+ }
+}
diff --git a/src/proguard/classfile/editor/ConstantPoolEditor.java b/src/proguard/classfile/editor/ConstantPoolEditor.java
new file mode 100644
index 0000000..ec99ae2
--- /dev/null
+++ b/src/proguard/classfile/editor/ConstantPoolEditor.java
@@ -0,0 +1,531 @@
+/* $Id: ConstantPoolEditor.java,v 1.7 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+
+/**
+ * This class can add constant pool entries to given class files.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantPoolEditor
+{
+ /**
+ * Finds or creates a StringCpInfo constant pool entry with the given value,
+ * in the given class file.
+ * @return the constant pool index of the ClassCpInfo.
+ */
+ public int addStringCpInfo(ProgramClassFile programClassFile,
+ String string,
+ ClassFile referencedClassFile)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Check if the entry already exists.
+ for (int index = 1; index < constantPoolCount; index++)
+ {
+ CpInfo cpInfo = constantPool[index];
+
+ if (cpInfo != null &&
+ cpInfo.getTag() == ClassConstants.CONSTANT_String)
+ {
+ StringCpInfo classCpInfo = (StringCpInfo)cpInfo;
+ if (classCpInfo.getString(programClassFile).equals(string))
+ {
+ return index;
+ }
+ }
+ }
+
+ int nameIndex = addUtf8CpInfo(programClassFile, string);
+
+ return addCpInfo(programClassFile,
+ new StringCpInfo(nameIndex,
+ referencedClassFile));
+ }
+
+
+ /**
+ * Finds or creates a FieldrefCpInfo constant pool entry with the given
+ * class name, field name, and descriptor, in the given class file.
+ * @return the constant pool index of the FieldrefCpInfo.
+ */
+ public int addFieldrefCpInfo(ProgramClassFile programClassFile,
+ String className,
+ String name,
+ String descriptor,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo,
+ ClassFile[] referencedClassFiles)
+ {
+ return addFieldrefCpInfo(programClassFile,
+ className,
+ addNameAndTypeCpInfo(programClassFile,
+ name,
+ descriptor,
+ referencedClassFiles),
+ referencedClassFile,
+ referencedMemberInfo);
+ }
+
+
+ /**
+ * Finds or creates a FieldrefCpInfo constant pool entry with the given
+ * class name, field name, and descriptor, in the given class file.
+ * @return the constant pool index of the FieldrefCpInfo.
+ */
+ public int addFieldrefCpInfo(ProgramClassFile programClassFile,
+ String className,
+ int nameAndTypeIndex,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo)
+ {
+ return addFieldrefCpInfo(programClassFile,
+ addClassCpInfo(programClassFile,
+ className,
+ referencedClassFile),
+ nameAndTypeIndex,
+ referencedClassFile,
+ referencedMemberInfo);
+ }
+
+
+ /**
+ * Finds or creates a FieldrefCpInfo constant pool entry with the given
+ * class constant pool entry index, field name, and descriptor, in the
+ * given class file.
+ * @return the constant pool index of the FieldrefCpInfo.
+ */
+ public int addFieldrefCpInfo(ProgramClassFile programClassFile,
+ int classIndex,
+ String name,
+ String descriptor,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo,
+ ClassFile[] referencedClassFiles)
+ {
+ return addFieldrefCpInfo(programClassFile,
+ classIndex,
+ addNameAndTypeCpInfo(programClassFile,
+ name,
+ descriptor,
+ referencedClassFiles),
+ referencedClassFile,
+ referencedMemberInfo);
+ }
+
+
+ /**
+ * Finds or creates a FieldrefCpInfo constant pool entry with the given
+ * class constant pool entry index and name and type constant pool entry index
+ * the given class file.
+ * @return the constant pool index of the FieldrefCpInfo.
+ */
+ public int addFieldrefCpInfo(ProgramClassFile programClassFile,
+ int classIndex,
+ int nameAndTypeIndex,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Check if the entry already exists.
+ for (int index = 1; index < constantPoolCount; index++)
+ {
+ CpInfo cpInfo = constantPool[index];
+
+ if (cpInfo != null &&
+ cpInfo.getTag() == ClassConstants.CONSTANT_Fieldref)
+ {
+ FieldrefCpInfo fieldrefCpInfo = (FieldrefCpInfo)cpInfo;
+ if (fieldrefCpInfo.u2classIndex == classIndex &&
+ fieldrefCpInfo.u2nameAndTypeIndex == nameAndTypeIndex)
+ {
+ return index;
+ }
+ }
+ }
+
+ return addCpInfo(programClassFile,
+ new FieldrefCpInfo(classIndex,
+ nameAndTypeIndex,
+ referencedClassFile,
+ referencedMemberInfo));
+ }
+
+
+ /**
+ * Finds or creates a MethodrefCpInfo constant pool entry with the given
+ * class name, method name, and descriptor, in the given class file.
+ * @return the constant pool index of the MethodrefCpInfo.
+ */
+ public int addMethodrefCpInfo(ProgramClassFile programClassFile,
+ String className,
+ String name,
+ String descriptor,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo,
+ ClassFile[] referencedClassFiles)
+ {
+ return addMethodrefCpInfo(programClassFile,
+ className,
+ addNameAndTypeCpInfo(programClassFile,
+ name,
+ descriptor,
+ referencedClassFiles),
+ referencedClassFile,
+ referencedMemberInfo);
+ }
+
+
+ /**
+ * Finds or creates a MethodrefCpInfo constant pool entry with the given
+ * class name, method name, and descriptor, in the given class file.
+ * @return the constant pool index of the MethodrefCpInfo.
+ */
+ public int addMethodrefCpInfo(ProgramClassFile programClassFile,
+ String className,
+ int nameAndTypeIndex,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo)
+ {
+ return addMethodrefCpInfo(programClassFile,
+ addClassCpInfo(programClassFile,
+ className,
+ referencedClassFile),
+ nameAndTypeIndex,
+ referencedClassFile,
+ referencedMemberInfo);
+ }
+
+
+ /**
+ * Finds or creates a MethodrefCpInfo constant pool entry with the given
+ * class constant pool entry index, method name, and descriptor, in the
+ * given class file.
+ * @return the constant pool index of the MethodrefCpInfo.
+ */
+ public int addMethodrefCpInfo(ProgramClassFile programClassFile,
+ int classIndex,
+ String name,
+ String descriptor,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo,
+ ClassFile[] referencedClassFiles)
+ {
+ return addMethodrefCpInfo(programClassFile,
+ classIndex,
+ addNameAndTypeCpInfo(programClassFile,
+ name,
+ descriptor,
+ referencedClassFiles),
+ referencedClassFile,
+ referencedMemberInfo);
+ }
+
+
+ /**
+ * Finds or creates a MethodrefCpInfo constant pool entry with the given
+ * class constant pool entry index and name and type constant pool entry index
+ * the given class file.
+ * @return the constant pool index of the MethodrefCpInfo.
+ */
+ public int addMethodrefCpInfo(ProgramClassFile programClassFile,
+ int classIndex,
+ int nameAndTypeIndex,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Check if the entry already exists.
+ for (int index = 1; index < constantPoolCount; index++)
+ {
+ CpInfo cpInfo = constantPool[index];
+
+ if (cpInfo != null &&
+ cpInfo.getTag() == ClassConstants.CONSTANT_Methodref)
+ {
+ MethodrefCpInfo methodrefCpInfo = (MethodrefCpInfo)cpInfo;
+ if (methodrefCpInfo.u2classIndex == classIndex &&
+ methodrefCpInfo.u2nameAndTypeIndex == nameAndTypeIndex)
+ {
+ return index;
+ }
+ }
+ }
+
+ return addCpInfo(programClassFile,
+ new MethodrefCpInfo(classIndex,
+ nameAndTypeIndex,
+ referencedClassFile,
+ referencedMemberInfo));
+ }
+
+
+ /**
+ * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
+ * given class name, method name, and descriptor, in the given class file.
+ * @return the constant pool index of the InterfaceMethodrefCpInfo.
+ */
+ public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
+ String className,
+ String name,
+ String descriptor,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo,
+ ClassFile[] referencedClassFiles)
+ {
+ return addInterfaceMethodrefCpInfo(programClassFile,
+ className,
+ addNameAndTypeCpInfo(programClassFile,
+ name,
+ descriptor,
+ referencedClassFiles),
+ referencedClassFile,
+ referencedMemberInfo);
+ }
+
+
+ /**
+ * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
+ * given class name, method name, and descriptor, in the given class file.
+ * @return the constant pool index of the InterfaceMethodrefCpInfo.
+ */
+ public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
+ String className,
+ int nameAndTypeIndex,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo)
+ {
+ return addInterfaceMethodrefCpInfo(programClassFile,
+ addClassCpInfo(programClassFile,
+ className,
+ referencedClassFile),
+ nameAndTypeIndex,
+ referencedClassFile,
+ referencedMemberInfo);
+ }
+
+
+ /**
+ * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
+ * given class constant pool entry index, method name, and descriptor, in
+ * the given class file.
+ * @return the constant pool index of the InterfaceMethodrefCpInfo.
+ */
+ public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
+ int classIndex,
+ String name,
+ String descriptor,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo,
+ ClassFile[] referencedClassFiles)
+ {
+ return addInterfaceMethodrefCpInfo(programClassFile,
+ classIndex,
+ addNameAndTypeCpInfo(programClassFile,
+ name,
+ descriptor,
+ referencedClassFiles),
+ referencedClassFile,
+ referencedMemberInfo);
+ }
+
+
+ /**
+ * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
+ * given class constant pool entry index and name and type constant pool
+ * entry index the given class file.
+ * @return the constant pool index of the InterfaceMethodrefCpInfo.
+ */
+ public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
+ int classIndex,
+ int nameAndTypeIndex,
+ ClassFile referencedClassFile,
+ MemberInfo referencedMemberInfo)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Check if the entry already exists.
+ for (int index = 1; index < constantPoolCount; index++)
+ {
+ CpInfo cpInfo = constantPool[index];
+
+ if (cpInfo != null &&
+ cpInfo.getTag() == ClassConstants.CONSTANT_InterfaceMethodref)
+ {
+ InterfaceMethodrefCpInfo methodrefCpInfo = (InterfaceMethodrefCpInfo)cpInfo;
+ if (methodrefCpInfo.u2classIndex == classIndex &&
+ methodrefCpInfo.u2nameAndTypeIndex == nameAndTypeIndex)
+ {
+ return index;
+ }
+ }
+ }
+
+ return addCpInfo(programClassFile,
+ new InterfaceMethodrefCpInfo(classIndex,
+ nameAndTypeIndex,
+ referencedClassFile,
+ referencedMemberInfo));
+ }
+
+
+ /**
+ * Finds or creates a ClassCpInfo constant pool entry with the given name,
+ * in the given class file.
+ * @return the constant pool index of the ClassCpInfo.
+ */
+ public int addClassCpInfo(ProgramClassFile programClassFile,
+ String name,
+ ClassFile referencedClassFile)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Check if the entry already exists.
+ for (int index = 1; index < constantPoolCount; index++)
+ {
+ CpInfo cpInfo = constantPool[index];
+
+ if (cpInfo != null &&
+ cpInfo.getTag() == ClassConstants.CONSTANT_Class)
+ {
+ ClassCpInfo classCpInfo = (ClassCpInfo)cpInfo;
+ if (classCpInfo.getName(programClassFile).equals(name))
+ {
+ return index;
+ }
+ }
+ }
+
+ int nameIndex = addUtf8CpInfo(programClassFile, name);
+
+ return addCpInfo(programClassFile,
+ new ClassCpInfo(nameIndex,
+ referencedClassFile));
+ }
+
+
+ /**
+ * Finds or creates a NameAndTypeCpInfo constant pool entry with the given
+ * name and type, in the given class file.
+ * @return the constant pool index of the NameAndTypeCpInfo.
+ */
+ public int addNameAndTypeCpInfo(ProgramClassFile programClassFile,
+ String name,
+ String type,
+ ClassFile[] referencedClassFiles)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Check if the entry already exists.
+ for (int index = 1; index < constantPoolCount; index++)
+ {
+ CpInfo cpInfo = constantPool[index];
+
+ if (cpInfo != null &&
+ cpInfo.getTag() == ClassConstants.CONSTANT_NameAndType)
+ {
+ NameAndTypeCpInfo nameAndTypeCpInfo = (NameAndTypeCpInfo)cpInfo;
+ if (nameAndTypeCpInfo.getName(programClassFile).equals(name) &&
+ nameAndTypeCpInfo.getType(programClassFile).equals(type))
+ {
+ return index;
+ }
+ }
+ }
+
+ int nameIndex = addUtf8CpInfo(programClassFile, name);
+ int descriptorIndex = addUtf8CpInfo(programClassFile, type);
+
+ return addCpInfo(programClassFile,
+ new NameAndTypeCpInfo(nameIndex,
+ descriptorIndex,
+ referencedClassFiles));
+ }
+
+
+ /**
+ * Finds or creates an Utf8CpInfo constant pool entry for the given string,
+ * in the given class file.
+ * @return the constant pool index of the Utf8CpInfo.
+ */
+ public int addUtf8CpInfo(ProgramClassFile programClassFile,
+ String string)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Check if the entry already exists.
+ for (int index = 1; index < constantPoolCount; index++)
+ {
+ CpInfo cpInfo = constantPool[index];
+
+ if (cpInfo != null &&
+ cpInfo.getTag() == ClassConstants.CONSTANT_Utf8)
+ {
+ Utf8CpInfo utf8CpInfo = (Utf8CpInfo)cpInfo;
+ if (utf8CpInfo.getString().equals(string))
+ {
+ return index;
+ }
+ }
+ }
+
+ return addCpInfo(programClassFile, new Utf8CpInfo(string));
+ }
+
+
+ /**
+ * Adds a given constant pool entry to the end of the constant pool
+ * in the given class file.
+ * @return the constant pool index for the added entry.
+ */
+ private int addCpInfo(ProgramClassFile programClassFile,
+ CpInfo cpInfo)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Make sure there is enough space for another constant pool entry.
+ if (constantPoolCount == constantPool.length)
+ {
+ programClassFile.constantPool = new CpInfo[constantPoolCount+1];
+ System.arraycopy(constantPool, 0,
+ programClassFile.constantPool, 0,
+ constantPoolCount);
+ constantPool = programClassFile.constantPool;
+ }
+
+ // Create a new Utf8CpInfo for the given string.
+ constantPool[programClassFile.u2constantPoolCount++] = cpInfo;
+
+ return constantPoolCount;
+ }
+}
diff --git a/src/proguard/classfile/editor/ConstantPoolRemapper.java b/src/proguard/classfile/editor/ConstantPoolRemapper.java
new file mode 100644
index 0000000..ef7460f
--- /dev/null
+++ b/src/proguard/classfile/editor/ConstantPoolRemapper.java
@@ -0,0 +1,592 @@
+/* $Id: ConstantPoolRemapper.java,v 1.9 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassFileVisitor remaps all possible references to constant pool entries
+ * of the classes that it visits, based on a given index map. It is assumed that
+ * the constant pool entries themselves have already been remapped.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantPoolRemapper
+ implements ClassFileVisitor,
+ CpInfoVisitor,
+ MemberInfoVisitor,
+ AttrInfoVisitor,
+ InstructionVisitor,
+ InnerClassesInfoVisitor,
+ ExceptionInfoVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor
+{
+ private CodeAttrInfoEditor codeAttrInfoEditor;
+
+ private int[] cpIndexMap;
+
+
+ /**
+ * Creates a new ConstantPoolRemapper.
+ * @param codeLength an estimate of the maximum length of all the code that
+ * will be edited.
+ */
+ public ConstantPoolRemapper(int codeLength)
+ {
+ codeAttrInfoEditor = new CodeAttrInfoEditor(codeLength);
+ }
+
+
+ /**
+ * Sets the given mapping of old constant pool entry indexes to their new
+ * indexes.
+ */
+ public void setCpIndexMap(int[] cpIndexMap)
+ {
+ this.cpIndexMap = cpIndexMap;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Remap the local constant pool references.
+ programClassFile.u2thisClass = remapCpIndex(programClassFile.u2thisClass);
+ programClassFile.u2superClass = remapCpIndex(programClassFile.u2superClass);
+
+ remapCpIndexArray(programClassFile.u2interfaces,
+ programClassFile.u2interfacesCount);
+
+ // Remap the references of the contant pool entries themselves.
+ programClassFile.constantPoolEntriesAccept(this);
+
+ // Remap the references in all fields, methods, and attributes.
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+ programClassFile.attributesAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ classCpInfo.u2nameIndex =
+ remapCpIndex(classCpInfo.u2nameIndex);
+ }
+
+
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo)
+ {
+ // Nothing to do.
+ }
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ fieldrefCpInfo.u2classIndex =
+ remapCpIndex(fieldrefCpInfo.u2classIndex);
+ fieldrefCpInfo.u2nameAndTypeIndex =
+ remapCpIndex(fieldrefCpInfo.u2nameAndTypeIndex);
+ }
+
+
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo)
+ {
+ // Nothing to do.
+ }
+
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo)
+ {
+ // Nothing to do.
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ interfaceMethodrefCpInfo.u2classIndex =
+ remapCpIndex(interfaceMethodrefCpInfo.u2classIndex);
+ interfaceMethodrefCpInfo.u2nameAndTypeIndex =
+ remapCpIndex(interfaceMethodrefCpInfo.u2nameAndTypeIndex);
+ }
+
+
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo)
+ {
+ // Nothing to do.
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ methodrefCpInfo.u2classIndex =
+ remapCpIndex(methodrefCpInfo.u2classIndex);
+ methodrefCpInfo.u2nameAndTypeIndex =
+ remapCpIndex(methodrefCpInfo.u2nameAndTypeIndex);
+ }
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ nameAndTypeCpInfo.u2nameIndex =
+ remapCpIndex(nameAndTypeCpInfo.u2nameIndex);
+ nameAndTypeCpInfo.u2descriptorIndex =
+ remapCpIndex(nameAndTypeCpInfo.u2descriptorIndex);
+ }
+
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ stringCpInfo.u2stringIndex =
+ remapCpIndex(stringCpInfo.u2stringIndex);
+ }
+
+
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
+ {
+ // Nothing to do.
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ // Remap the local constant pool references.
+ programMemberInfo.u2nameIndex =
+ remapCpIndex(programMemberInfo.u2nameIndex);
+ programMemberInfo.u2descriptorIndex =
+ remapCpIndex(programMemberInfo.u2descriptorIndex);
+
+ // Remap the constant pool references of the remaining attributes.
+ programMemberInfo.attributesAccept(programClassFile, this);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ // Library class files are left unchanged.
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ // Library class files are left unchanged.
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo)
+ {
+ unknownAttrInfo.u2attrNameIndex =
+ remapCpIndex(unknownAttrInfo.u2attrNameIndex);
+
+ // There's not much else we can do with unknown attributes.
+ }
+
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ innerClassesAttrInfo.u2attrNameIndex =
+ remapCpIndex(innerClassesAttrInfo.u2attrNameIndex);
+
+ // Remap the constant pool references of the inner classes.
+ innerClassesAttrInfo.innerClassEntriesAccept(classFile, this);
+ }
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ enclosingMethodAttrInfo.u2attrNameIndex =
+ remapCpIndex(enclosingMethodAttrInfo.u2attrNameIndex);
+ enclosingMethodAttrInfo.u2classIndex =
+ remapCpIndex(enclosingMethodAttrInfo.u2classIndex);
+ enclosingMethodAttrInfo.u2nameAndTypeIndex =
+ remapCpIndex(enclosingMethodAttrInfo.u2nameAndTypeIndex);
+ }
+
+
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo)
+ {
+ constantValueAttrInfo.u2attrNameIndex =
+ remapCpIndex(constantValueAttrInfo.u2attrNameIndex);
+ constantValueAttrInfo.u2constantValueIndex =
+ remapCpIndex(constantValueAttrInfo.u2constantValueIndex);
+ }
+
+
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo)
+ {
+ exceptionsAttrInfo.u2attrNameIndex =
+ remapCpIndex(exceptionsAttrInfo.u2attrNameIndex);
+
+ // Remap the constant pool references of the exceptions.
+ remapCpIndexArray(exceptionsAttrInfo.u2exceptionIndexTable,
+ exceptionsAttrInfo.u2numberOfExceptions);
+ }
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ codeAttrInfo.u2attrNameIndex =
+ remapCpIndex(codeAttrInfo.u2attrNameIndex);
+
+ // Initially, the code attribute editor doesn't contain any changes.
+ codeAttrInfoEditor.reset(codeAttrInfo.u4codeLength);
+
+ // Remap the constant pool references of the instructions.
+ codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
+
+ // Apply the code atribute editor. It will only contain any changes if
+ // the code length is changing at any point.
+ codeAttrInfoEditor.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
+
+ // Remap the constant pool references of the exceptions and attributes.
+ codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
+ codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+ }
+
+
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo)
+ {
+ lineNumberTableAttrInfo.u2attrNameIndex =
+ remapCpIndex(lineNumberTableAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ localVariableTableAttrInfo.u2attrNameIndex =
+ remapCpIndex(localVariableTableAttrInfo.u2attrNameIndex);
+
+ // Remap the constant pool references of the local variables.
+ localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ localVariableTypeTableAttrInfo.u2attrNameIndex =
+ remapCpIndex(localVariableTypeTableAttrInfo.u2attrNameIndex);
+
+ // Remap the constant pool references of the local variables.
+ localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+ {
+ sourceFileAttrInfo.u2attrNameIndex =
+ remapCpIndex(sourceFileAttrInfo.u2attrNameIndex);
+ sourceFileAttrInfo.u2sourceFileIndex =
+ remapCpIndex(sourceFileAttrInfo.u2sourceFileIndex);
+ }
+
+
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
+ {
+ sourceDirAttrInfo.u2attrNameIndex =
+ remapCpIndex(sourceDirAttrInfo.u2attrNameIndex);
+ sourceDirAttrInfo.u2sourceDirIndex =
+ remapCpIndex(sourceDirAttrInfo.u2sourceDirIndex);
+ }
+
+
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo)
+ {
+ deprecatedAttrInfo.u2attrNameIndex =
+ remapCpIndex(deprecatedAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo)
+ {
+ syntheticAttrInfo.u2attrNameIndex =
+ remapCpIndex(syntheticAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ signatureAttrInfo.u2attrNameIndex =
+ remapCpIndex(signatureAttrInfo.u2attrNameIndex);
+ signatureAttrInfo.u2signatureIndex =
+ remapCpIndex(signatureAttrInfo.u2signatureIndex);
+ }
+
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ runtimeVisibleAnnotationsAttrInfo.u2attrNameIndex =
+ remapCpIndex(runtimeVisibleAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Remap the constant pool references of the annotations.
+ runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ runtimeInvisibleAnnotationsAttrInfo.u2attrNameIndex =
+ remapCpIndex(runtimeInvisibleAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Remap the constant pool references of the annotations.
+ runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ runtimeVisibleParameterAnnotationsAttrInfo.u2attrNameIndex =
+ remapCpIndex(runtimeVisibleParameterAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Remap the constant pool references of the annotations.
+ runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ runtimeInvisibleParameterAnnotationsAttrInfo.u2attrNameIndex =
+ remapCpIndex(runtimeInvisibleParameterAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Remap the constant pool references of the annotations.
+ runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ annotationDefaultAttrInfo.u2attrNameIndex =
+ remapCpIndex(annotationDefaultAttrInfo.u2attrNameIndex);
+
+ // Remap the constant pool references of the annotations.
+ annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(ClassFile classFile, InnerClassesInfo innerClassesInfo)
+ {
+ if (innerClassesInfo.u2innerClassInfoIndex != 0)
+ {
+ innerClassesInfo.u2innerClassInfoIndex =
+ remapCpIndex(innerClassesInfo.u2innerClassInfoIndex);
+ }
+
+ if (innerClassesInfo.u2outerClassInfoIndex != 0)
+ {
+ innerClassesInfo.u2outerClassInfoIndex =
+ remapCpIndex(innerClassesInfo.u2outerClassInfoIndex);
+ }
+
+ if (innerClassesInfo.u2innerNameIndex != 0)
+ {
+ innerClassesInfo.u2innerNameIndex =
+ remapCpIndex(innerClassesInfo.u2innerNameIndex);
+ }
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, ExceptionInfo exceptionInfo)
+ {
+ if (exceptionInfo.u2catchType != 0)
+ {
+ exceptionInfo.u2catchType =
+ remapCpIndex(exceptionInfo.u2catchType);
+ }
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+ {
+ localVariableInfo.u2nameIndex =
+ remapCpIndex(localVariableInfo.u2nameIndex);
+ localVariableInfo.u2descriptorIndex =
+ remapCpIndex(localVariableInfo.u2descriptorIndex);
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ localVariableTypeInfo.u2nameIndex =
+ remapCpIndex(localVariableTypeInfo.u2nameIndex);
+ localVariableTypeInfo.u2signatureIndex =
+ remapCpIndex(localVariableTypeInfo.u2signatureIndex);
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(ClassFile classFile, Annotation annotation)
+ {
+ annotation.u2typeIndex =
+ remapCpIndex(annotation.u2typeIndex);
+
+ // Remap the constant pool references of the element values.
+ annotation.elementValuesAccept(classFile, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ constantElementValue.u2elementName =
+ remapCpIndex(constantElementValue.u2elementName);
+ constantElementValue.u2constantValueIndex =
+ remapCpIndex(constantElementValue.u2constantValueIndex);
+ }
+
+
+ public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ enumConstantElementValue.u2elementName =
+ remapCpIndex(enumConstantElementValue.u2elementName);
+ enumConstantElementValue.u2typeNameIndex =
+ remapCpIndex(enumConstantElementValue.u2typeNameIndex);
+ enumConstantElementValue.u2constantNameIndex =
+ remapCpIndex(enumConstantElementValue.u2constantNameIndex);
+ }
+
+
+ public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
+ {
+ classElementValue.u2elementName =
+ remapCpIndex(classElementValue.u2elementName);
+ classElementValue.u2classInfoIndex =
+ remapCpIndex(classElementValue.u2classInfoIndex);
+ }
+
+
+ public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ annotationElementValue.u2elementName =
+ remapCpIndex(annotationElementValue.u2elementName);
+
+ // Remap the constant pool references of the annotation.
+ annotationElementValue.annotationAccept(classFile, this);
+ }
+
+
+ public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ arrayElementValue.u2elementName =
+ remapCpIndex(arrayElementValue.u2elementName);
+
+ // Remap the constant pool references of the element values.
+ arrayElementValue.elementValuesAccept(classFile, annotation, this);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ // Remap the instruction, and get the old and the new instruction length.
+ int oldLength = cpInstruction.length(offset);
+
+ cpInstruction.cpIndex = remapCpIndex(cpInstruction.cpIndex);
+ cpInstruction.shrink();
+
+ int newLength = cpInstruction.length(offset);
+
+ // Is the code length changing?
+ if (newLength != oldLength ||
+ codeAttrInfoEditor.isModified())
+ {
+ // We have to go through the code attribute editor.
+ cpInstruction = new CpInstruction().copy(cpInstruction);
+
+ codeAttrInfoEditor.replaceInstruction(offset, cpInstruction);
+ }
+ else
+ {
+ // We can write the instruction directly.
+ cpInstruction.write(codeAttrInfo, offset);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Remaps all constant pool indices in the given array.
+ */
+ private void remapCpIndexArray(int[] array, int length)
+ {
+ for (int index = 0; index < length; index++)
+ {
+ array[index] = remapCpIndex(array[index]);
+ }
+ }
+
+
+ /**
+ * Returns the new constant pool index of the entry at the
+ * given index.
+ */
+ private int remapCpIndex(int cpIndex)
+ {
+ return cpIndexMap[cpIndex];
+ }
+}
diff --git a/src/proguard/classfile/editor/ConstantPoolSorter.java b/src/proguard/classfile/editor/ConstantPoolSorter.java
new file mode 100644
index 0000000..9291b5b
--- /dev/null
+++ b/src/proguard/classfile/editor/ConstantPoolSorter.java
@@ -0,0 +1,128 @@
+/* $Id: ConstantPoolSorter.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import java.util.Arrays;
+
+import proguard.classfile.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor sorts the constant pool entries of the classes that
+ * it visits. The sorting is based on the types of the constant pool entries
+ * in the first place, and on their contents in the second place.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantPoolSorter implements ClassFileVisitor
+{
+ private int[] cpIndexMap;
+ private ComparableCpInfo[] comparableConstantPool;
+ private ConstantPoolRemapper constantPoolRemapper;
+
+
+ /**
+ * Creates a new ConstantPoolSorter.
+ * @param codeLength an estimate of the maximum length of all the code that
+ * will be edited.
+ */
+ public ConstantPoolSorter(int codeLength)
+ {
+ constantPoolRemapper = new ConstantPoolRemapper(codeLength);
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Sort the constant pool and set up an index map.
+ sortConstantPool(programClassFile,
+ programClassFile.constantPool,
+ programClassFile.u2constantPoolCount);
+
+ // Remap all constant pool references.
+ constantPoolRemapper.setCpIndexMap(cpIndexMap);
+ constantPoolRemapper.visitProgramClassFile(programClassFile);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Sorts the given constant pool.
+ */
+ private void sortConstantPool(ClassFile classFile, CpInfo[] constantPool, int length)
+ {
+ if (cpIndexMap == null ||
+ cpIndexMap.length < length)
+ {
+ cpIndexMap = new int[length];
+ comparableConstantPool = new ComparableCpInfo[length];
+ }
+
+ // Initialize an array whose elements can be compared.
+ for (int oldIndex = 1; oldIndex < length; oldIndex++)
+ {
+ CpInfo cpInfo = constantPool[oldIndex];
+
+ // Long entries take up two entries, the second of which is null.
+ if (cpInfo == null)
+ {
+ cpInfo = constantPool[oldIndex-1];
+ }
+
+ comparableConstantPool[oldIndex] = new ComparableCpInfo(classFile,
+ oldIndex,
+ cpInfo);
+ }
+
+ // Sort the array.
+ Arrays.sort(comparableConstantPool, 1, length);
+
+ // Save the sorted elements.
+ CpInfo previousCpInfo = null;
+ for (int newIndex = 1; newIndex < length; newIndex++)
+ {
+ ComparableCpInfo comparableCpInfo = comparableConstantPool[newIndex];
+
+ // Fill out the map array.
+ int oldIndex = comparableCpInfo.getIndex();
+ cpIndexMap[oldIndex] = newIndex;
+
+ // Copy the sorted constant pool entry over to the constant pool.
+ // Long entries take up two entries, the second of which is null.
+ CpInfo cpInfo = comparableCpInfo.getCpInfo();
+ constantPool[newIndex] = cpInfo != previousCpInfo ?
+ cpInfo :
+ null;
+
+ previousCpInfo = cpInfo;
+ }
+ }
+}
diff --git a/src/proguard/classfile/editor/StackSizeUpdater.java b/src/proguard/classfile/editor/StackSizeUpdater.java
new file mode 100644
index 0000000..08cd042
--- /dev/null
+++ b/src/proguard/classfile/editor/StackSizeUpdater.java
@@ -0,0 +1,357 @@
+/* $Id: StackSizeUpdater.java,v 1.12 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This AttrInfoVisitor computes and updates the maximum stack size of the
+ * code attributes that it visits.
+ *
+ * @author Eric Lafortune
+ */
+class StackSizeUpdater
+implements AttrInfoVisitor,
+ InstructionVisitor,
+ ExceptionInfoVisitor
+{
+ //*
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG = true;
+ //*/
+
+
+ private boolean[] evaluated;
+
+ private boolean exitInstructionBlock;
+
+ private int stackSize;
+ private int maxStackSize;
+
+
+ /**
+ * Creates a new StackSizeUpdater.
+ * @param codeLength an estimate of the maximum length of all the code that
+ * will be visited.
+ */
+ public StackSizeUpdater(int codeLength)
+ {
+ evaluated = new boolean[codeLength];
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+// DEBUG =
+// classFile.getName().equals("abc/Def") &&
+// methodInfo.getName(classFile).equals("abc");
+
+ // Try to reuse the previous array.
+ int codeLength = codeAttrInfo.u4codeLength;
+ if (evaluated.length < codeLength)
+ {
+ evaluated = new boolean[codeLength];
+ }
+ else
+ {
+ for (int index = 0; index < codeLength; index++)
+ {
+ evaluated[index] = false;
+ }
+ }
+
+ // The initial stack is always empty.
+ stackSize = 0;
+ maxStackSize = 0;
+
+ // Evaluate the instruction block starting at the entry point of the method.
+ evaluateInstructionBlock(classFile, methodInfo, codeAttrInfo, 0);
+
+ // Evaluate the exception handlers.
+ codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
+
+ // Update the maximum stack size.
+ codeAttrInfo.u2maxStack = maxStackSize;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
+ {
+ byte opcode = simpleInstruction.opcode;
+
+ // Some simple instructions exit from the current instruction block.
+ exitInstructionBlock =
+ opcode == InstructionConstants.OP_IRETURN ||
+ opcode == InstructionConstants.OP_LRETURN ||
+ opcode == InstructionConstants.OP_FRETURN ||
+ opcode == InstructionConstants.OP_DRETURN ||
+ opcode == InstructionConstants.OP_ARETURN ||
+ opcode == InstructionConstants.OP_RETURN ||
+ opcode == InstructionConstants.OP_ATHROW;
+ }
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ // Constant pool instructions never end the current instruction block.
+ exitInstructionBlock = false;
+ }
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ byte opcode = variableInstruction.opcode;
+
+ // The ret instruction end the current instruction block.
+ exitInstructionBlock =
+ opcode == InstructionConstants.OP_RET;
+ }
+
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
+ {
+ byte opcode = branchInstruction.opcode;
+
+ // Evaluate the target instruction blocks.
+ evaluateInstructionBlock(classFile,
+ methodInfo,
+ codeAttrInfo,
+ offset +
+ branchInstruction.branchOffset);
+
+ // Evaluate the instructions after a subroutine branch.
+ if (opcode == InstructionConstants.OP_JSR ||
+ opcode == InstructionConstants.OP_JSR_W)
+ {
+ // We assume subroutine calls (jsr and jsr_w instructions) don't
+ // change the stack, other than popping the return value.
+ stackSize -= 1;
+
+ evaluateInstructionBlock(classFile,
+ methodInfo,
+ codeAttrInfo,
+ offset + branchInstruction.length(offset));
+ }
+
+ // Some branch instructions always end the current instruction block.
+ exitInstructionBlock =
+ opcode == InstructionConstants.OP_GOTO ||
+ opcode == InstructionConstants.OP_GOTO_W ||
+ opcode == InstructionConstants.OP_JSR ||
+ opcode == InstructionConstants.OP_JSR_W;
+ }
+
+
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ // Evaluate the target instruction blocks.
+ evaluateInstructionBlocks(classFile,
+ methodInfo,
+ codeAttrInfo,
+ offset,
+ tableSwitchInstruction.jumpOffsets,
+ tableSwitchInstruction.jumpOffsetCount,
+ tableSwitchInstruction.defaultOffset);
+
+ // The switch instruction always ends the current instruction block.
+ exitInstructionBlock = true;
+ }
+
+
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ // Evaluate the target instruction blocks.
+ evaluateInstructionBlocks(classFile,
+ methodInfo,
+ codeAttrInfo,
+ offset,
+ lookUpSwitchInstruction.jumpOffsets,
+ lookUpSwitchInstruction.jumpOffsetCount,
+ lookUpSwitchInstruction.defaultOffset);
+
+ // The switch instruction always ends the current instruction block.
+ exitInstructionBlock = true;
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, ExceptionInfo exceptionInfo)
+ {
+ // The stack size when entering the exception handler is always 1.
+ stackSize = 1;
+
+ // Evaluate the instruction block starting at the entry point of the
+ // exception handler.
+ evaluateInstructionBlock(classFile,
+ methodInfo,
+ codeAttrInfo,
+ exceptionInfo.u2handlerpc);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Evaluates the blocks of instructions starting at the given jump offsets.
+ */
+ private void evaluateInstructionBlocks(ClassFile classFile,
+ MethodInfo methodInfo,
+ CodeAttrInfo codeAttrInfo,
+ int instructionOffset,
+ int[] jumpOffsets,
+ int jumpOffsetCount,
+ int defaultOffset)
+ {
+ // The jump offset arrays may be reused, so we have to make a local copy.
+ int[] jumpOffsetsCopy = new int[jumpOffsetCount];
+ System.arraycopy(jumpOffsets, 0, jumpOffsetsCopy, 0, jumpOffsetCount);
+ jumpOffsets = jumpOffsetsCopy;
+
+ // Loop over all jump offsets.
+ for (int index = 0; index < jumpOffsetCount; index++)
+ {
+ // Evaluate the jump instruction block.
+ evaluateInstructionBlock(classFile,
+ methodInfo,
+ codeAttrInfo,
+ instructionOffset + jumpOffsets[index]);
+ }
+
+ // Also evaluate the default instruction block.
+ evaluateInstructionBlock(classFile,
+ methodInfo,
+ codeAttrInfo,
+ instructionOffset + defaultOffset);
+ }
+
+
+ /**
+ * Evaluates a block of instructions that hasn't been handled before,
+ * starting at the given offset and ending a branch instruction, a return
+ * instruction, or a throw instruction. Branch instructions are handled
+ * recursively.
+ */
+ private void evaluateInstructionBlock(ClassFile classFile,
+ MethodInfo methodInfo,
+ CodeAttrInfo codeAttrInfo,
+ int instructionOffset)
+ {
+ if (DEBUG)
+ {
+ System.out.println("--");
+ }
+
+ // Remember the initial stack size.
+ int initialStackSize = stackSize;
+
+ // Remember the maximum stack size.
+ if (maxStackSize < stackSize)
+ {
+ maxStackSize = stackSize;
+ }
+
+ // Evaluate any instructions that haven't been evaluated before.
+ while (!evaluated[instructionOffset])
+ {
+ // Mark the instruction as evaluated.
+ evaluated[instructionOffset] = true;
+
+ Instruction instruction = InstructionFactory.create(codeAttrInfo.code,
+ instructionOffset);
+
+ if (DEBUG)
+ {
+ int stackPushCount = instruction.stackPushCount(classFile);
+ int stackPopCount = instruction.stackPopCount(classFile);
+ System.out.println("["+instructionOffset+"]: "+
+ stackSize+" - "+
+ stackPopCount+" + "+
+ stackPushCount+" = "+
+ (stackSize+stackPushCount-stackPopCount)+": "+
+ instruction.toString());
+ }
+
+ // Compute the instruction's effect on the stack size.
+ stackSize += instruction.stackPushCount(classFile) -
+ instruction.stackPopCount(classFile);
+
+ // Remember the maximum stack size.
+ if (maxStackSize < stackSize)
+ {
+ maxStackSize = stackSize;
+ }
+
+ // Remember the next instruction offset.
+ int nextInstructionOffset = instructionOffset +
+ instruction.length(instructionOffset);
+
+ // Visit the instruction, in order to handle branches.
+ instruction.accept(classFile, methodInfo, codeAttrInfo, instructionOffset, this);
+
+ // Stop evaluating after a branch.
+ if (exitInstructionBlock)
+ {
+ break;
+ }
+
+ // Continue with the next instruction.
+ instructionOffset = nextInstructionOffset;
+
+ if (DEBUG)
+ {
+ if (evaluated[instructionOffset])
+ {
+ System.out.println("-- ("+instructionOffset+" already evaluated)");
+ }
+ }
+ }
+
+ // Restore the stack size for possible subsequent instruction blocks.
+ this.stackSize = initialStackSize;
+ }
+}
diff --git a/src/proguard/classfile/editor/package.html b/src/proguard/classfile/editor/package.html
new file mode 100644
index 0000000..d37f541
--- /dev/null
+++ b/src/proguard/classfile/editor/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains visitors to edit byte code.
+</body>
diff --git a/src/proguard/classfile/instruction/AllInstructionVisitor.java b/src/proguard/classfile/instruction/AllInstructionVisitor.java
new file mode 100644
index 0000000..2673a6b
--- /dev/null
+++ b/src/proguard/classfile/instruction/AllInstructionVisitor.java
@@ -0,0 +1,71 @@
+/* $Id: AllInstructionVisitor.java,v 1.5 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.AttrInfoVisitor;
+
+/**
+ * This AttrInfoVisitor lets a given InstructionVisitor visit all Instruction
+ * objects of the CodeAttrInfo objects it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllInstructionVisitor implements AttrInfoVisitor
+{
+ private InstructionVisitor instructionVisitor;
+
+
+ public AllInstructionVisitor(InstructionVisitor instructionVisitor)
+ {
+ this.instructionVisitor = instructionVisitor;
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ codeAttrInfo.instructionsAccept(classFile, methodInfo, instructionVisitor);
+ }
+}
diff --git a/src/proguard/classfile/instruction/BranchInstruction.java b/src/proguard/classfile/instruction/BranchInstruction.java
new file mode 100644
index 0000000..67d015d
--- /dev/null
+++ b/src/proguard/classfile/instruction/BranchInstruction.java
@@ -0,0 +1,133 @@
+/* $Id: BranchInstruction.java,v 1.14 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+/**
+ * This interface describes an instruction that branches to a given offset in
+ * the code.
+ *
+ * @author Eric Lafortune
+ */
+public class BranchInstruction extends Instruction
+{
+ public int branchOffset;
+
+
+ /**
+ * Creates an uninitialized BranchInstruction.
+ */
+ public BranchInstruction() {}
+
+
+ public BranchInstruction(byte opcode, int branchOffset)
+ {
+ this.opcode = opcode;
+ this.branchOffset = branchOffset;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param branchInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public BranchInstruction copy(BranchInstruction branchInstruction)
+ {
+ this.opcode = branchInstruction.opcode;
+ this.branchOffset = branchInstruction.branchOffset;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ // Is this a wide branch that can be replaced by a normal branch?
+ if (branchOffset << 16 >> 16 == branchOffset)
+ {
+ if (opcode == InstructionConstants.OP_GOTO_W)
+ {
+ opcode = InstructionConstants.OP_GOTO;
+ }
+ else if (opcode == InstructionConstants.OP_JSR_W)
+ {
+ opcode = InstructionConstants.OP_JSR;
+ }
+ }
+
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ branchOffset = readSignedValue(code, offset, branchOffsetSize());
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ writeValue(code, offset, branchOffset, branchOffsetSize());
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + branchOffsetSize();
+ }
+
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitBranchInstruction(classFile, methodInfo, codeAttrInfo, offset, this);
+ }
+
+
+ public String toString(int offset)
+ {
+ return "["+offset+"] "+getName()+" (offset="+branchOffset+", target="+(offset+branchOffset)+")";
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName()+" (offset="+branchOffset+")";
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Computes the appropriate branch offset size for this instruction.
+ */
+ private int branchOffsetSize()
+ {
+ return opcode == InstructionConstants.OP_GOTO_W ||
+ opcode == InstructionConstants.OP_JSR_W ? 4 :
+ 2;
+ }
+}
diff --git a/src/proguard/classfile/instruction/CpInstruction.java b/src/proguard/classfile/instruction/CpInstruction.java
new file mode 100644
index 0000000..f8caa07
--- /dev/null
+++ b/src/proguard/classfile/instruction/CpInstruction.java
@@ -0,0 +1,267 @@
+/* $Id: CpInstruction.java,v 1.19 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.util.ClassUtil;
+import proguard.classfile.visitor.CpInfoVisitor;
+
+/**
+ * This Instruction represents an instruction that refers to an entry in the
+ * constant pool.
+ *
+ * @author Eric Lafortune
+ */
+public class CpInstruction extends Instruction
+implements CpInfoVisitor
+{
+ public int cpIndex;
+ public int constant;
+
+
+ // Fields acting as return parameters for the CpInfoVisitor methods.
+ private int parameterStackDelta;
+ private int typeStackDelta;
+
+
+ /**
+ * Creates an uninitialized CpInstruction.
+ */
+ public CpInstruction() {}
+
+
+ /**
+ * Creates a new CpInstruction with the given opcode and constant pool index.
+ */
+ public CpInstruction(byte opcode, int cpIndex)
+ {
+ this(opcode, cpIndex, 0);
+ }
+
+
+ /**
+ * Creates a new CpInstruction with the given opcode, constant pool index,
+ * and constant.
+ */
+ public CpInstruction(byte opcode, int cpIndex, int constant)
+ {
+ this.opcode = opcode;
+ this.cpIndex = cpIndex;
+ this.constant = constant;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param cpInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public CpInstruction copy(CpInstruction cpInstruction)
+ {
+ this.opcode = cpInstruction.opcode;
+ this.cpIndex = cpInstruction.cpIndex;
+ this.constant = cpInstruction.constant;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ if (opcode == InstructionConstants.OP_LDC &&
+ cpIndex > 0xff)
+ {
+ opcode = InstructionConstants.OP_LDC_W;
+ }
+ else if (opcode == InstructionConstants.OP_LDC_W &&
+ cpIndex <= 0xff)
+ {
+ opcode = InstructionConstants.OP_LDC;
+ }
+
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ int cpIndexSize = cpIndexSize();
+ int constantSize = constantSize();
+
+ cpIndex = readValue(code, offset, cpIndexSize); offset += cpIndexSize;
+ constant = readValue(code, offset, constantSize);
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ int cpIndexSize = cpIndexSize();
+ int constantSize = constantSize();
+
+ writeValue(code, offset, cpIndex, cpIndexSize); offset += cpIndexSize;
+ writeValue(code, offset, constant, constantSize);
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + cpIndexSize() + constantSize();
+ }
+
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitCpInstruction(classFile, methodInfo, codeAttrInfo, offset, this);
+ }
+
+
+ public String toString(int offset)
+ {
+ return "["+offset+"] "+getName()+" (cpIndex="+cpIndex+")";
+ }
+
+
+ public int stackPopCount(ClassFile classFile)
+ {
+ int stackPopCount = super.stackPopCount(classFile);
+
+ // Some special cases.
+ switch (opcode)
+ {
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ // For each dimension, an integer size is popped from the stack.
+ stackPopCount += constant;
+ break;
+
+ case InstructionConstants.OP_PUTSTATIC:
+ case InstructionConstants.OP_PUTFIELD:
+ // The field value is be popped from the stack.
+ classFile.constantPoolEntryAccept(cpIndex, this);
+ stackPopCount += typeStackDelta;
+ break;
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ // The some parameters may be popped from the stack.
+ classFile.constantPoolEntryAccept(cpIndex, this);
+ stackPopCount += parameterStackDelta;
+ break;
+ }
+
+ return stackPopCount;
+ }
+
+
+ public int stackPushCount(ClassFile classFile)
+ {
+ int stackPushCount = super.stackPushCount(classFile);
+
+ // Some special cases.
+ switch (opcode)
+ {
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_GETFIELD:
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ // The field value or a return value may be pushed onto the stack.
+ classFile.constantPoolEntryAccept(cpIndex, this);
+ stackPushCount += typeStackDelta;
+ break;
+ }
+
+ return stackPushCount;
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ String type = fieldrefCpInfo.getType(classFile);
+
+ typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type));
+ }
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, interfaceMethodrefCpInfo);
+ }
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, methodrefCpInfo);
+ }
+
+ private void visitRefCpInfo(ClassFile classFile, RefCpInfo methodrefCpInfo)
+ {
+ String type = methodrefCpInfo.getType(classFile);
+
+ parameterStackDelta = ClassUtil.internalMethodParameterSize(type);
+ typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type));
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName()+" (cpIndex="+cpIndex+")";
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Computes the appropriate constant pool index size for this instruction.
+ */
+ private int cpIndexSize()
+ {
+ return opcode == InstructionConstants.OP_LDC ? 1 :
+ 2;
+ }
+
+
+ /**
+ * Computes the appropriate constant size for this instruction.
+ */
+ private int constantSize()
+ {
+ return opcode == InstructionConstants.OP_MULTIANEWARRAY ? 1 :
+ opcode == InstructionConstants.OP_INVOKEINTERFACE ? 2 :
+ 0;
+ }
+}
diff --git a/src/proguard/classfile/instruction/Instruction.java b/src/proguard/classfile/instruction/Instruction.java
new file mode 100644
index 0000000..e0f9b4f
--- /dev/null
+++ b/src/proguard/classfile/instruction/Instruction.java
@@ -0,0 +1,866 @@
+/* $Id: Instruction.java,v 1.22 2004/12/11 00:12:41 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+/**
+ * Base class for representing instructions.
+ *
+ * @author Eric Lafortune
+ */
+public abstract class Instruction
+{
+ // An array for marking Category 2 instructions.
+ private static final boolean[] IS_CATEGORY2 = new boolean[]
+ {
+ false, // nop
+ false, // aconst_null
+ false, // iconst_m1
+ false, // iconst_0
+ false, // iconst_1
+ false, // iconst_2
+ false, // iconst_3
+ false, // iconst_4
+ false, // iconst_5
+ true, // lconst_0
+ true, // lconst_1
+ false, // fconst_0
+ false, // fconst_1
+ false, // fconst_2
+ true, // dconst_0
+ true, // dconst_1
+ false, // bipush
+ false, // sipush
+ false, // ldc
+ false, // ldc_w
+ true, // ldc2_w
+ false, // iload
+ true, // lload
+ false, // fload
+ true, // dload
+ false, // aload
+ false, // iload_0
+ false, // iload_1
+ false, // iload_2
+ false, // iload_3
+ true, // lload_0
+ true, // lload_1
+ true, // lload_2
+ true, // lload_3
+ false, // fload_0
+ false, // fload_1
+ false, // fload_2
+ false, // fload_3
+ true, // dload_0
+ true, // dload_1
+ true, // dload_2
+ true, // dload_3
+ false, // aload_0
+ false, // aload_1
+ false, // aload_2
+ false, // aload_3
+ false, // iaload
+ true, // laload
+ false, // faload
+ true, // daload
+ false, // aaload
+ false, // baload
+ false, // caload
+ false, // saload
+ false, // istore
+ true, // lstore
+ false, // fstore
+ true, // dstore
+ false, // astore
+ false, // istore_0
+ false, // istore_1
+ false, // istore_2
+ false, // istore_3
+ true, // lstore_0
+ true, // lstore_1
+ true, // lstore_2
+ true, // lstore_3
+ false, // fstore_0
+ false, // fstore_1
+ false, // fstore_2
+ false, // fstore_3
+ true, // dstore_0
+ true, // dstore_1
+ true, // dstore_2
+ true, // dstore_3
+ false, // astore_0
+ false, // astore_1
+ false, // astore_2
+ false, // astore_3
+ false, // iastore
+ true, // lastore
+ false, // fastore
+ true, // dastore
+ false, // aastore
+ false, // bastore
+ false, // castore
+ false, // sastore
+ false, // pop
+ true, // pop2
+ false, // dup
+ false, // dup_x1
+ false, // dup_x2
+ true, // dup2
+ true, // dup2_x1
+ true, // dup2_x2
+ false, // swap
+ false, // iadd
+ true, // ladd
+ false, // fadd
+ true, // dadd
+ false, // isub
+ true, // lsub
+ false, // fsub
+ true, // dsub
+ false, // imul
+ true, // lmul
+ false, // fmul
+ true, // dmul
+ false, // idiv
+ true, // ldiv
+ false, // fdiv
+ true, // ddiv
+ false, // irem
+ true, // lrem
+ false, // frem
+ true, // drem
+ false, // ineg
+ true, // lneg
+ false, // fneg
+ true, // dneg
+ false, // ishl
+ true, // lshl
+ false, // ishr
+ true, // lshr
+ false, // iushr
+ true, // lushr
+ false, // iand
+ true, // land
+ false, // ior
+ true, // lor
+ false, // ixor
+ true, // lxor
+ false, // iinc
+ false, // i2l
+ false, // i2f
+ false, // i2d
+ true, // l2i
+ true, // l2f
+ true, // l2d
+ false, // f2i
+ false, // f2l
+ false, // f2d
+ true, // d2i
+ true, // d2l
+ true, // d2f
+ false, // i2b
+ false, // i2c
+ false, // i2s
+ true, // lcmp
+ false, // fcmpl
+ false, // fcmpg
+ true, // dcmpl
+ true, // dcmpg
+ false, // ifeq
+ false, // ifne
+ false, // iflt
+ false, // ifge
+ false, // ifgt
+ false, // ifle
+ false, // ificmpeq
+ false, // ificmpne
+ false, // ificmplt
+ false, // ificmpge
+ false, // ificmpgt
+ false, // ificmple
+ false, // ifacmpeq
+ false, // ifacmpne
+ false, // goto
+ false, // jsr
+ false, // ret
+ false, // tableswitch
+ false, // lookupswitch
+ false, // ireturn
+ true, // lreturn
+ false, // freturn
+ true, // dreturn
+ false, // areturn
+ false, // return
+ false, // getstatic
+ false, // putstatic
+ false, // getfield
+ false, // putfield
+ false, // invokevirtual
+ false, // invokespecial
+ false, // invokestatic
+ false, // invokeinterface
+ false, // unused
+ false, // new
+ false, // newarray
+ false, // anewarray
+ false, // arraylength
+ false, // athrow
+ false, // checkcast
+ false, // instanceof
+ false, // monitorenter
+ false, // monitorexit
+ false, // wide
+ false, // multianewarray
+ false, // ifnull
+ false, // ifnonnull
+ false, // goto_w
+ false, // jsr_w
+ };
+
+
+ // An array containing the fixed number of entries popped from the stack,
+ // for all instructions.
+ private static final int[] STACK_POP_COUNTS = new int[]
+ {
+ 0, // nop
+ 0, // aconst_null
+ 0, // iconst_m1
+ 0, // iconst_0
+ 0, // iconst_1
+ 0, // iconst_2
+ 0, // iconst_3
+ 0, // iconst_4
+ 0, // iconst_5
+ 0, // lconst_0
+ 0, // lconst_1
+ 0, // fconst_0
+ 0, // fconst_1
+ 0, // fconst_2
+ 0, // dconst_0
+ 0, // dconst_1
+ 0, // bipush
+ 0, // sipush
+ 0, // ldc
+ 0, // ldc_w
+ 0, // ldc2_w
+ 0, // iload
+ 0, // lload
+ 0, // fload
+ 0, // dload
+ 0, // aload
+ 0, // iload_0
+ 0, // iload_1
+ 0, // iload_2
+ 0, // iload_3
+ 0, // lload_0
+ 0, // lload_1
+ 0, // lload_2
+ 0, // lload_3
+ 0, // fload_0
+ 0, // fload_1
+ 0, // fload_2
+ 0, // fload_3
+ 0, // dload_0
+ 0, // dload_1
+ 0, // dload_2
+ 0, // dload_3
+ 0, // aload_0
+ 0, // aload_1
+ 0, // aload_2
+ 0, // aload_3
+ 2, // iaload
+ 2, // laload
+ 2, // faload
+ 2, // daload
+ 2, // aaload
+ 2, // baload
+ 2, // caload
+ 2, // saload
+ 1, // istore
+ 2, // lstore
+ 1, // fstore
+ 2, // dstore
+ 1, // astore
+ 1, // istore_0
+ 1, // istore_1
+ 1, // istore_2
+ 1, // istore_3
+ 2, // lstore_0
+ 2, // lstore_1
+ 2, // lstore_2
+ 2, // lstore_3
+ 1, // fstore_0
+ 1, // fstore_1
+ 1, // fstore_2
+ 1, // fstore_3
+ 2, // dstore_0
+ 2, // dstore_1
+ 2, // dstore_2
+ 2, // dstore_3
+ 1, // astore_0
+ 1, // astore_1
+ 1, // astore_2
+ 1, // astore_3
+ 3, // iastore
+ 4, // lastore
+ 3, // fastore
+ 4, // dastore
+ 3, // aastore
+ 3, // bastore
+ 3, // castore
+ 3, // sastore
+ 1, // pop
+ 2, // pop2
+ 0, // dup
+ 0, // dup_x1
+ 0, // dup_x2
+ 0, // dup2
+ 0, // dup2_x1
+ 0, // dup2_x2
+ 0, // swap
+ 2, // iadd
+ 4, // ladd
+ 2, // fadd
+ 4, // dadd
+ 2, // isub
+ 4, // lsub
+ 2, // fsub
+ 4, // dsub
+ 2, // imul
+ 4, // lmul
+ 2, // fmul
+ 4, // dmul
+ 2, // idiv
+ 4, // ldiv
+ 2, // fdiv
+ 4, // ddiv
+ 2, // irem
+ 4, // lrem
+ 2, // frem
+ 4, // drem
+ 1, // ineg
+ 2, // lneg
+ 1, // fneg
+ 2, // dneg
+ 2, // ishl
+ 3, // lshl
+ 2, // ishr
+ 3, // lshr
+ 2, // iushr
+ 3, // lushr
+ 2, // iand
+ 4, // land
+ 2, // ior
+ 4, // lor
+ 2, // ixor
+ 4, // lxor
+ 0, // iinc
+ 1, // i2l
+ 1, // i2f
+ 1, // i2d
+ 2, // l2i
+ 2, // l2f
+ 2, // l2d
+ 1, // f2i
+ 1, // f2l
+ 1, // f2d
+ 2, // d2i
+ 2, // d2l
+ 2, // d2f
+ 1, // i2b
+ 1, // i2c
+ 1, // i2s
+ 4, // lcmp
+ 2, // fcmpl
+ 2, // fcmpg
+ 4, // dcmpl
+ 4, // dcmpg
+ 1, // ifeq
+ 1, // ifne
+ 1, // iflt
+ 1, // ifge
+ 1, // ifgt
+ 1, // ifle
+ 2, // ificmpeq
+ 2, // ificmpne
+ 2, // ificmplt
+ 2, // ificmpge
+ 2, // ificmpgt
+ 2, // ificmple
+ 2, // ifacmpeq
+ 2, // ifacmpne
+ 0, // goto
+ 0, // jsr
+ 0, // ret
+ 1, // tableswitch
+ 1, // lookupswitch
+ 1, // ireturn
+ 2, // lreturn
+ 1, // freturn
+ 2, // dreturn
+ 1, // areturn
+ 0, // return
+ 0, // getstatic
+ 0, // putstatic
+ 1, // getfield
+ 1, // putfield
+ 1, // invokevirtual
+ 1, // invokespecial
+ 0, // invokestatic
+ 1, // invokeinterface
+ 0, // unused
+ 0, // new
+ 1, // newarray
+ 1, // anewarray
+ 1, // arraylength
+ 1, // athrow
+ 1, // checkcast
+ 1, // instanceof
+ 1, // monitorenter
+ 1, // monitorexit
+ 0, // wide
+ 0, // multianewarray
+ 1, // ifnull
+ 1, // ifnonnull
+ 0, // goto_w
+ 0, // jsr_w
+ };
+
+
+ // An array containing the fixed number of entries pushed onto the stack,
+ // for all instructions.
+ private static final int[] STACK_PUSH_COUNTS = new int[]
+ {
+ 0, // nop
+ 1, // aconst_null
+ 1, // iconst_m1
+ 1, // iconst_0
+ 1, // iconst_1
+ 1, // iconst_2
+ 1, // iconst_3
+ 1, // iconst_4
+ 1, // iconst_5
+ 2, // lconst_0
+ 2, // lconst_1
+ 1, // fconst_0
+ 1, // fconst_1
+ 1, // fconst_2
+ 2, // dconst_0
+ 2, // dconst_1
+ 1, // bipush
+ 1, // sipush
+ 1, // ldc
+ 1, // ldc_w
+ 2, // ldc2_w
+ 1, // iload
+ 2, // lload
+ 1, // fload
+ 2, // dload
+ 1, // aload
+ 1, // iload_0
+ 1, // iload_1
+ 1, // iload_2
+ 1, // iload_3
+ 2, // lload_0
+ 2, // lload_1
+ 2, // lload_2
+ 2, // lload_3
+ 1, // fload_0
+ 1, // fload_1
+ 1, // fload_2
+ 1, // fload_3
+ 2, // dload_0
+ 2, // dload_1
+ 2, // dload_2
+ 2, // dload_3
+ 1, // aload_0
+ 1, // aload_1
+ 1, // aload_2
+ 1, // aload_3
+ 1, // iaload
+ 2, // laload
+ 1, // faload
+ 2, // daload
+ 1, // aaload
+ 1, // baload
+ 1, // caload
+ 1, // saload
+ 0, // istore
+ 0, // lstore
+ 0, // fstore
+ 0, // dstore
+ 0, // astore
+ 0, // istore_0
+ 0, // istore_1
+ 0, // istore_2
+ 0, // istore_3
+ 0, // lstore_0
+ 0, // lstore_1
+ 0, // lstore_2
+ 0, // lstore_3
+ 0, // fstore_0
+ 0, // fstore_1
+ 0, // fstore_2
+ 0, // fstore_3
+ 0, // dstore_0
+ 0, // dstore_1
+ 0, // dstore_2
+ 0, // dstore_3
+ 0, // astore_0
+ 0, // astore_1
+ 0, // astore_2
+ 0, // astore_3
+ 0, // iastore
+ 0, // lastore
+ 0, // fastore
+ 0, // dastore
+ 0, // aastore
+ 0, // bastore
+ 0, // castore
+ 0, // sastore
+ 0, // pop
+ 0, // pop2
+ 1, // dup
+ 1, // dup_x1
+ 1, // dup_x2
+ 2, // dup2
+ 2, // dup2_x1
+ 2, // dup2_x2
+ 0, // swap
+ 1, // iadd
+ 2, // ladd
+ 1, // fadd
+ 2, // dadd
+ 1, // isub
+ 2, // lsub
+ 1, // fsub
+ 2, // dsub
+ 1, // imul
+ 2, // lmul
+ 1, // fmul
+ 2, // dmul
+ 1, // idiv
+ 2, // ldiv
+ 1, // fdiv
+ 2, // ddiv
+ 1, // irem
+ 2, // lrem
+ 1, // frem
+ 2, // drem
+ 1, // ineg
+ 2, // lneg
+ 1, // fneg
+ 2, // dneg
+ 1, // ishl
+ 2, // lshl
+ 1, // ishr
+ 2, // lshr
+ 1, // iushr
+ 2, // lushr
+ 1, // iand
+ 2, // land
+ 1, // ior
+ 2, // lor
+ 1, // ixor
+ 2, // lxor
+ 0, // iinc
+ 2, // i2l
+ 1, // i2f
+ 2, // i2d
+ 1, // l2i
+ 1, // l2f
+ 2, // l2d
+ 1, // f2i
+ 2, // f2l
+ 2, // f2d
+ 1, // d2i
+ 2, // d2l
+ 1, // d2f
+ 1, // i2b
+ 1, // i2c
+ 1, // i2s
+ 1, // lcmp
+ 1, // fcmpl
+ 1, // fcmpg
+ 1, // dcmpl
+ 1, // dcmpg
+ 0, // ifeq
+ 0, // ifne
+ 0, // iflt
+ 0, // ifge
+ 0, // ifgt
+ 0, // ifle
+ 0, // ificmpeq
+ 0, // ificmpne
+ 0, // ificmplt
+ 0, // ificmpge
+ 0, // ificmpgt
+ 0, // ificmple
+ 0, // ifacmpeq
+ 0, // ifacmpne
+ 0, // goto
+ 1, // jsr
+ 0, // ret
+ 0, // tableswitch
+ 0, // lookupswitch
+ 0, // ireturn
+ 0, // lreturn
+ 0, // freturn
+ 0, // dreturn
+ 0, // areturn
+ 0, // return
+ 0, // getstatic
+ 0, // putstatic
+ 0, // getfield
+ 0, // putfield
+ 0, // invokevirtual
+ 0, // invokespecial
+ 0, // invokestatic
+ 0, // invokeinterface
+ 0, // unused
+ 1, // new
+ 1, // newarray
+ 1, // anewarray
+ 1, // arraylength
+ 0, // athrow
+ 1, // checkcast
+ 1, // instanceof
+ 0, // monitorenter
+ 0, // monitorexit
+ 0, // wide
+ 1, // multianewarray
+ 0, // ifnull
+ 0, // ifnonnull
+ 0, // goto_w
+ 1, // jsr_w
+ };
+
+
+ public byte opcode;
+
+
+ /**
+ * Shrinks this instruction to its shortest possible form.
+ * @return this instruction.
+ */
+ public abstract Instruction shrink();
+
+
+
+ /**
+ * Writes the Instruction back to the data in the byte array.
+ */
+ public final void write(CodeAttrInfo codeAttrInfo, int offset)
+ {
+ byte[] code = codeAttrInfo.code;
+
+ // Write the wide opcode, if necessary.
+ if (isWide())
+ {
+ code[offset++] = InstructionConstants.OP_WIDE;
+ }
+
+ // Write the opcode.
+ code[offset++] = opcode;
+
+ // Write any additional arguments.
+ writeInfo(code, offset);
+ }
+
+
+ /**
+ * Returns whether the instruction is wide, i.e. preceded by a wide opcode.
+ * With the current specifications, only variable instructions can be wide.
+ */
+ protected boolean isWide()
+ {
+ return false;
+ }
+
+
+ /**
+ * Reads the data following the instruction opcode.
+ */
+ protected abstract void readInfo(byte[] code, int offset);
+
+
+ /**
+ * Writes data following the instruction opcode.
+ */
+ protected abstract void writeInfo(byte[] code, int offset);
+
+
+ /**
+ * Returns the length in bytes of the instruction.
+ */
+ public abstract int length(int offset);
+
+
+ /**
+ * Accepts the given visitor.
+ */
+ public abstract void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, InstructionVisitor instructionVisitor);
+
+
+ /**
+ * Returns a description of the instruction, at the given offset.
+ */
+ public abstract String toString(int offset);
+
+
+ /**
+ * Returns the name of the instruction.
+ */
+ public String getName()
+ {
+ return InstructionConstants.NAMES[opcode & 0xff];
+ }
+
+
+ /**
+ * Returns whether the instruction is a Category 2 instruction. This means
+ * that it operates on long or double arguments.
+ */
+ public boolean isCategory2()
+ {
+ return IS_CATEGORY2[opcode & 0xff];
+ }
+
+
+ /**
+ * Returns the number of entries popped from the stack during the execution
+ * of the instruction.
+ */
+ public int stackPopCount(ClassFile classFile)
+ {
+ return STACK_POP_COUNTS[opcode & 0xff];
+ }
+
+
+ /**
+ * Returns the number of entries pushed onto the stack during the execution
+ * of the instruction.
+ */
+ public int stackPushCount(ClassFile classFile)
+ {
+ return STACK_PUSH_COUNTS[opcode & 0xff];
+ }
+
+
+ // Small utility methods.
+
+ protected static int readByte(byte[] code, int offset)
+ {
+ return code[offset] & 0xff;
+ }
+
+ protected static int readShort(byte[] code, int offset)
+ {
+ return ((code[offset++] & 0xff) << 8) |
+ ( code[offset ] & 0xff );
+ }
+
+ protected static int readInt(byte[] code, int offset)
+ {
+ return ( code[offset++] << 24) |
+ ((code[offset++] & 0xff) << 16) |
+ ((code[offset++] & 0xff) << 8) |
+ ( code[offset ] & 0xff );
+ }
+
+ protected static int readValue(byte[] code, int offset, int valueSize)
+ {
+ switch (valueSize)
+ {
+ case 0: return 0;
+ case 1: return readByte( code, offset);
+ case 2: return readShort(code, offset);
+ case 4: return readInt( code, offset);
+ default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]");
+ }
+ }
+
+ protected static int readSignedByte(byte[] code, int offset)
+ {
+ return code[offset];
+ }
+
+ protected static int readSignedShort(byte[] code, int offset)
+ {
+ return (code[offset++] << 8) |
+ (code[offset ] & 0xff);
+ }
+
+ protected static int readSignedValue(byte[] code, int offset, int valueSize)
+ {
+ switch (valueSize)
+ {
+ case 0: return 0;
+ case 1: return readSignedByte( code, offset);
+ case 2: return readSignedShort(code, offset);
+ case 4: return readInt( code, offset);
+ default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]");
+ }
+ }
+
+ protected static void writeByte(byte[] code, int offset, int value)
+ {
+ if (value > 0xff)
+ {
+ throw new IllegalArgumentException("Byte value larger than 0xff ["+value+"]");
+ }
+
+ code[offset] = (byte)value;
+ }
+
+ protected static void writeShort(byte[] code, int offset, int value)
+ {
+ if (value > 0xffff)
+ {
+ throw new IllegalArgumentException("Short value larger than 0xffff ["+value+"]");
+ }
+
+ code[offset++] = (byte)(value >> 8);
+ code[offset ] = (byte)(value );
+ }
+
+ protected static void writeInt(byte[] code, int offset, int value)
+ {
+ code[offset++] = (byte)(value >> 24);
+ code[offset++] = (byte)(value >> 16);
+ code[offset++] = (byte)(value >> 8);
+ code[offset ] = (byte)(value );
+ }
+
+ protected static void writeValue(byte[] code, int offset, int value, int valueSize)
+ {
+ switch (valueSize)
+ {
+ case 0: break;
+ case 1: writeByte( code, offset, value); break;
+ case 2: writeShort(code, offset, value); break;
+ case 4: writeInt( code, offset, value); break;
+ default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]");
+ }
+ }
+}
diff --git a/src/proguard/classfile/instruction/InstructionConstants.java b/src/proguard/classfile/instruction/InstructionConstants.java
new file mode 100644
index 0000000..60e9fec
--- /dev/null
+++ b/src/proguard/classfile/instruction/InstructionConstants.java
@@ -0,0 +1,449 @@
+/* $Id: InstructionConstants.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+/**
+ * Representation of an instruction.
+ *
+ * @author Eric Lafortune
+ */
+public interface InstructionConstants
+{
+ public static final byte OP_NOP = 0;
+ public static final byte OP_ACONST_NULL = 1;
+ public static final byte OP_ICONST_M1 = 2;
+ public static final byte OP_ICONST_0 = 3;
+ public static final byte OP_ICONST_1 = 4;
+ public static final byte OP_ICONST_2 = 5;
+ public static final byte OP_ICONST_3 = 6;
+ public static final byte OP_ICONST_4 = 7;
+ public static final byte OP_ICONST_5 = 8;
+ public static final byte OP_LCONST_0 = 9;
+ public static final byte OP_LCONST_1 = 10;
+ public static final byte OP_FCONST_0 = 11;
+ public static final byte OP_FCONST_1 = 12;
+ public static final byte OP_FCONST_2 = 13;
+ public static final byte OP_DCONST_0 = 14;
+ public static final byte OP_DCONST_1 = 15;
+ public static final byte OP_BIPUSH = 16;
+ public static final byte OP_SIPUSH = 17;
+ public static final byte OP_LDC = 18;
+ public static final byte OP_LDC_W = 19;
+ public static final byte OP_LDC2_W = 20;
+ public static final byte OP_ILOAD = 21;
+ public static final byte OP_LLOAD = 22;
+ public static final byte OP_FLOAD = 23;
+ public static final byte OP_DLOAD = 24;
+ public static final byte OP_ALOAD = 25;
+ public static final byte OP_ILOAD_0 = 26;
+ public static final byte OP_ILOAD_1 = 27;
+ public static final byte OP_ILOAD_2 = 28;
+ public static final byte OP_ILOAD_3 = 29;
+ public static final byte OP_LLOAD_0 = 30;
+ public static final byte OP_LLOAD_1 = 31;
+ public static final byte OP_LLOAD_2 = 32;
+ public static final byte OP_LLOAD_3 = 33;
+ public static final byte OP_FLOAD_0 = 34;
+ public static final byte OP_FLOAD_1 = 35;
+ public static final byte OP_FLOAD_2 = 36;
+ public static final byte OP_FLOAD_3 = 37;
+ public static final byte OP_DLOAD_0 = 38;
+ public static final byte OP_DLOAD_1 = 39;
+ public static final byte OP_DLOAD_2 = 40;
+ public static final byte OP_DLOAD_3 = 41;
+ public static final byte OP_ALOAD_0 = 42;
+ public static final byte OP_ALOAD_1 = 43;
+ public static final byte OP_ALOAD_2 = 44;
+ public static final byte OP_ALOAD_3 = 45;
+ public static final byte OP_IALOAD = 46;
+ public static final byte OP_LALOAD = 47;
+ public static final byte OP_FALOAD = 48;
+ public static final byte OP_DALOAD = 49;
+ public static final byte OP_AALOAD = 50;
+ public static final byte OP_BALOAD = 51;
+ public static final byte OP_CALOAD = 52;
+ public static final byte OP_SALOAD = 53;
+ public static final byte OP_ISTORE = 54;
+ public static final byte OP_LSTORE = 55;
+ public static final byte OP_FSTORE = 56;
+ public static final byte OP_DSTORE = 57;
+ public static final byte OP_ASTORE = 58;
+ public static final byte OP_ISTORE_0 = 59;
+ public static final byte OP_ISTORE_1 = 60;
+ public static final byte OP_ISTORE_2 = 61;
+ public static final byte OP_ISTORE_3 = 62;
+ public static final byte OP_LSTORE_0 = 63;
+ public static final byte OP_LSTORE_1 = 64;
+ public static final byte OP_LSTORE_2 = 65;
+ public static final byte OP_LSTORE_3 = 66;
+ public static final byte OP_FSTORE_0 = 67;
+ public static final byte OP_FSTORE_1 = 68;
+ public static final byte OP_FSTORE_2 = 69;
+ public static final byte OP_FSTORE_3 = 70;
+ public static final byte OP_DSTORE_0 = 71;
+ public static final byte OP_DSTORE_1 = 72;
+ public static final byte OP_DSTORE_2 = 73;
+ public static final byte OP_DSTORE_3 = 74;
+ public static final byte OP_ASTORE_0 = 75;
+ public static final byte OP_ASTORE_1 = 76;
+ public static final byte OP_ASTORE_2 = 77;
+ public static final byte OP_ASTORE_3 = 78;
+ public static final byte OP_IASTORE = 79;
+ public static final byte OP_LASTORE = 80;
+ public static final byte OP_FASTORE = 81;
+ public static final byte OP_DASTORE = 82;
+ public static final byte OP_AASTORE = 83;
+ public static final byte OP_BASTORE = 84;
+ public static final byte OP_CASTORE = 85;
+ public static final byte OP_SASTORE = 86;
+ public static final byte OP_POP = 87;
+ public static final byte OP_POP2 = 88;
+ public static final byte OP_DUP = 89;
+ public static final byte OP_DUP_X1 = 90;
+ public static final byte OP_DUP_X2 = 91;
+ public static final byte OP_DUP2 = 92;
+ public static final byte OP_DUP2_X1 = 93;
+ public static final byte OP_DUP2_X2 = 94;
+ public static final byte OP_SWAP = 95;
+ public static final byte OP_IADD = 96;
+ public static final byte OP_LADD = 97;
+ public static final byte OP_FADD = 98;
+ public static final byte OP_DADD = 99;
+ public static final byte OP_ISUB = 100;
+ public static final byte OP_LSUB = 101;
+ public static final byte OP_FSUB = 102;
+ public static final byte OP_DSUB = 103;
+ public static final byte OP_IMUL = 104;
+ public static final byte OP_LMUL = 105;
+ public static final byte OP_FMUL = 106;
+ public static final byte OP_DMUL = 107;
+ public static final byte OP_IDIV = 108;
+ public static final byte OP_LDIV = 109;
+ public static final byte OP_FDIV = 110;
+ public static final byte OP_DDIV = 111;
+ public static final byte OP_IREM = 112;
+ public static final byte OP_LREM = 113;
+ public static final byte OP_FREM = 114;
+ public static final byte OP_DREM = 115;
+ public static final byte OP_INEG = 116;
+ public static final byte OP_LNEG = 117;
+ public static final byte OP_FNEG = 118;
+ public static final byte OP_DNEG = 119;
+ public static final byte OP_ISHL = 120;
+ public static final byte OP_LSHL = 121;
+ public static final byte OP_ISHR = 122;
+ public static final byte OP_LSHR = 123;
+ public static final byte OP_IUSHR = 124;
+ public static final byte OP_LUSHR = 125;
+ public static final byte OP_IAND = 126;
+ public static final byte OP_LAND = 127;
+ public static final byte OP_IOR = -128;
+ public static final byte OP_LOR = -127;
+ public static final byte OP_IXOR = -126;
+ public static final byte OP_LXOR = -125;
+ public static final byte OP_IINC = -124;
+ public static final byte OP_I2L = -123;
+ public static final byte OP_I2F = -122;
+ public static final byte OP_I2D = -121;
+ public static final byte OP_L2I = -120;
+ public static final byte OP_L2F = -119;
+ public static final byte OP_L2D = -118;
+ public static final byte OP_F2I = -117;
+ public static final byte OP_F2L = -116;
+ public static final byte OP_F2D = -115;
+ public static final byte OP_D2I = -114;
+ public static final byte OP_D2L = -113;
+ public static final byte OP_D2F = -112;
+ public static final byte OP_I2B = -111;
+ public static final byte OP_I2C = -110;
+ public static final byte OP_I2S = -109;
+ public static final byte OP_LCMP = -108;
+ public static final byte OP_FCMPL = -107;
+ public static final byte OP_FCMPG = -106;
+ public static final byte OP_DCMPL = -105;
+ public static final byte OP_DCMPG = -104;
+ public static final byte OP_IFEQ = -103;
+ public static final byte OP_IFNE = -102;
+ public static final byte OP_IFLT = -101;
+ public static final byte OP_IFGE = -100;
+ public static final byte OP_IFGT = -99;
+ public static final byte OP_IFLE = -98;
+ public static final byte OP_IFICMPEQ = -97;
+ public static final byte OP_IFICMPNE = -96;
+ public static final byte OP_IFICMPLT = -95;
+ public static final byte OP_IFICMPGE = -94;
+ public static final byte OP_IFICMPGT = -93;
+ public static final byte OP_IFICMPLE = -92;
+ public static final byte OP_IFACMPEQ = -91;
+ public static final byte OP_IFACMPNE = -90;
+ public static final byte OP_GOTO = -89;
+ public static final byte OP_JSR = -88;
+ public static final byte OP_RET = -87;
+ public static final byte OP_TABLESWITCH = -86;
+ public static final byte OP_LOOKUPSWITCH = -85;
+ public static final byte OP_IRETURN = -84;
+ public static final byte OP_LRETURN = -83;
+ public static final byte OP_FRETURN = -82;
+ public static final byte OP_DRETURN = -81;
+ public static final byte OP_ARETURN = -80;
+ public static final byte OP_RETURN = -79;
+ public static final byte OP_GETSTATIC = -78;
+ public static final byte OP_PUTSTATIC = -77;
+ public static final byte OP_GETFIELD = -76;
+ public static final byte OP_PUTFIELD = -75;
+ public static final byte OP_INVOKEVIRTUAL = -74;
+ public static final byte OP_INVOKESPECIAL = -73;
+ public static final byte OP_INVOKESTATIC = -72;
+ public static final byte OP_INVOKEINTERFACE = -71;
+// public static final byte OP_UNUSED = -70;
+ public static final byte OP_NEW = -69;
+ public static final byte OP_NEWARRAY = -68;
+ public static final byte OP_ANEWARRAY = -67;
+ public static final byte OP_ARRAYLENGTH = -66;
+ public static final byte OP_ATHROW = -65;
+ public static final byte OP_CHECKCAST = -64;
+ public static final byte OP_INSTANCEOF = -63;
+ public static final byte OP_MONITORENTER = -62;
+ public static final byte OP_MONITOREXIT = -61;
+ public static final byte OP_WIDE = -60;
+ public static final byte OP_MULTIANEWARRAY = -59;
+ public static final byte OP_IFNULL = -58;
+ public static final byte OP_IFNONNULL = -57;
+ public static final byte OP_GOTO_W = -56;
+ public static final byte OP_JSR_W = -55;
+
+
+ public static final String[] NAMES =
+ {
+ "nop",
+ "aconst_null",
+ "iconst_m1",
+ "iconst_0",
+ "iconst_1",
+ "iconst_2",
+ "iconst_3",
+ "iconst_4",
+ "iconst_5",
+ "lconst_0",
+ "lconst_1",
+ "fconst_0",
+ "fconst_1",
+ "fconst_2",
+ "dconst_0",
+ "dconst_1",
+ "bipush",
+ "sipush",
+ "ldc",
+ "ldc_w",
+ "ldc2_w",
+ "iload",
+ "lload",
+ "fload",
+ "dload",
+ "aload",
+ "iload_0",
+ "iload_1",
+ "iload_2",
+ "iload_3",
+ "lload_0",
+ "lload_1",
+ "lload_2",
+ "lload_3",
+ "fload_0",
+ "fload_1",
+ "fload_2",
+ "fload_3",
+ "dload_0",
+ "dload_1",
+ "dload_2",
+ "dload_3",
+ "aload_0",
+ "aload_1",
+ "aload_2",
+ "aload_3",
+ "iaload",
+ "laload",
+ "faload",
+ "daload",
+ "aaload",
+ "baload",
+ "caload",
+ "saload",
+ "istore",
+ "lstore",
+ "fstore",
+ "dstore",
+ "astore",
+ "istore_0",
+ "istore_1",
+ "istore_2",
+ "istore_3",
+ "lstore_0",
+ "lstore_1",
+ "lstore_2",
+ "lstore_3",
+ "fstore_0",
+ "fstore_1",
+ "fstore_2",
+ "fstore_3",
+ "dstore_0",
+ "dstore_1",
+ "dstore_2",
+ "dstore_3",
+ "astore_0",
+ "astore_1",
+ "astore_2",
+ "astore_3",
+ "iastore",
+ "lastore",
+ "fastore",
+ "dastore",
+ "aastore",
+ "bastore",
+ "castore",
+ "sastore",
+ "pop",
+ "pop2",
+ "dup",
+ "dup_x1",
+ "dup_x2",
+ "dup2",
+ "dup2_x1",
+ "dup2_x2",
+ "swap",
+ "iadd",
+ "ladd",
+ "fadd",
+ "dadd",
+ "isub",
+ "lsub",
+ "fsub",
+ "dsub",
+ "imul",
+ "lmul",
+ "fmul",
+ "dmul",
+ "idiv",
+ "ldiv",
+ "fdiv",
+ "ddiv",
+ "irem",
+ "lrem",
+ "frem",
+ "drem",
+ "ineg",
+ "lneg",
+ "fneg",
+ "dneg",
+ "ishl",
+ "lshl",
+ "ishr",
+ "lshr",
+ "iushr",
+ "lushr",
+ "iand",
+ "land",
+ "ior",
+ "lor",
+ "ixor",
+ "lxor",
+ "iinc",
+ "i2l",
+ "i2f",
+ "i2d",
+ "l2i",
+ "l2f",
+ "l2d",
+ "f2i",
+ "f2l",
+ "f2d",
+ "d2i",
+ "d2l",
+ "d2f",
+ "i2b",
+ "i2c",
+ "i2s",
+ "lcmp",
+ "fcmpl",
+ "fcmpg",
+ "dcmpl",
+ "dcmpg",
+ "ifeq",
+ "ifne",
+ "iflt",
+ "ifge",
+ "ifgt",
+ "ifle",
+ "ificmpeq",
+ "ificmpne",
+ "ificmplt",
+ "ificmpge",
+ "ificmpgt",
+ "ificmple",
+ "ifacmpeq",
+ "ifacmpne",
+ "goto",
+ "jsr",
+ "ret",
+ "tableswitch",
+ "lookupswitch",
+ "ireturn",
+ "lreturn",
+ "freturn",
+ "dreturn",
+ "areturn",
+ "return",
+ "getstatic",
+ "putstatic",
+ "getfield",
+ "putfield",
+ "invokevirtual",
+ "invokespecial",
+ "invokestatic",
+ "invokeinterface",
+ "unused",
+ "new",
+ "newarray",
+ "anewarray",
+ "arraylength",
+ "athrow",
+ "checkcast",
+ "instanceof",
+ "monitorenter",
+ "monitorexit",
+ "wide",
+ "multianewarray",
+ "ifnull",
+ "ifnonnull",
+ "goto_w",
+ "jsr_w",
+ };
+
+
+ public static final byte ARRAY_T_BOOLEAN = 4;
+ public static final byte ARRAY_T_CHAR = 5;
+ public static final byte ARRAY_T_FLOAT = 6;
+ public static final byte ARRAY_T_DOUBLE = 7;
+ public static final byte ARRAY_T_BYTE = 8;
+ public static final byte ARRAY_T_SHORT = 9;
+ public static final byte ARRAY_T_INT = 10;
+ public static final byte ARRAY_T_LONG = 11;
+}
diff --git a/src/proguard/classfile/instruction/InstructionFactory.java b/src/proguard/classfile/instruction/InstructionFactory.java
new file mode 100644
index 0000000..b381db2
--- /dev/null
+++ b/src/proguard/classfile/instruction/InstructionFactory.java
@@ -0,0 +1,310 @@
+/* $Id: InstructionFactory.java,v 1.5 2004/08/21 21:37:28 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+/**
+ * This class provides methods to create and reuse Instruction objects.
+ *
+ * @author Eric Lafortune
+ */
+public class InstructionFactory
+{
+ // Shared copies of Instruction objects, to avoid creating a lot of objects.
+ private static final SimpleInstruction simpleInstruction = new SimpleInstruction();
+ private static final CpInstruction cpInstruction = new CpInstruction();
+ private static final VariableInstruction variableInstruction = new VariableInstruction();
+ private static final BranchInstruction branchInstruction = new BranchInstruction();
+ private static final TableSwitchInstruction tableSwitchInstruction = new TableSwitchInstruction();
+ private static final LookUpSwitchInstruction lookUpSwitchInstruction = new LookUpSwitchInstruction();
+
+
+ /**
+ * Creates a new Instruction from the data in the byte array, starting
+ * at the given index.
+ */
+ public static Instruction create(byte[] code, int offset)
+ {
+ // We'll re-use the static Instruction objects.
+ Instruction instruction;
+
+ int index = offset;
+ byte opcode = code[index++];
+
+ boolean wide = false;
+ if (opcode == InstructionConstants.OP_WIDE)
+ {
+ opcode = code[index++];
+ wide = true;
+ }
+
+ switch (opcode)
+ {
+ // Simple instructions.
+ case InstructionConstants.OP_NOP:
+ case InstructionConstants.OP_ACONST_NULL:
+ case InstructionConstants.OP_ICONST_M1:
+ case InstructionConstants.OP_ICONST_0:
+ case InstructionConstants.OP_ICONST_1:
+ case InstructionConstants.OP_ICONST_2:
+ case InstructionConstants.OP_ICONST_3:
+ case InstructionConstants.OP_ICONST_4:
+ case InstructionConstants.OP_ICONST_5:
+ case InstructionConstants.OP_LCONST_0:
+ case InstructionConstants.OP_LCONST_1:
+ case InstructionConstants.OP_FCONST_0:
+ case InstructionConstants.OP_FCONST_1:
+ case InstructionConstants.OP_FCONST_2:
+ case InstructionConstants.OP_DCONST_0:
+ case InstructionConstants.OP_DCONST_1:
+
+ case InstructionConstants.OP_BIPUSH:
+ case InstructionConstants.OP_SIPUSH:
+
+ case InstructionConstants.OP_IALOAD:
+ case InstructionConstants.OP_LALOAD:
+ case InstructionConstants.OP_FALOAD:
+ case InstructionConstants.OP_DALOAD:
+ case InstructionConstants.OP_AALOAD:
+ case InstructionConstants.OP_BALOAD:
+ case InstructionConstants.OP_CALOAD:
+ case InstructionConstants.OP_SALOAD:
+
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_LASTORE:
+ case InstructionConstants.OP_FASTORE:
+ case InstructionConstants.OP_DASTORE:
+ case InstructionConstants.OP_AASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ case InstructionConstants.OP_POP:
+ case InstructionConstants.OP_POP2:
+ case InstructionConstants.OP_DUP:
+ case InstructionConstants.OP_DUP_X1:
+ case InstructionConstants.OP_DUP_X2:
+ case InstructionConstants.OP_DUP2:
+ case InstructionConstants.OP_DUP2_X1:
+ case InstructionConstants.OP_DUP2_X2:
+ case InstructionConstants.OP_SWAP:
+ case InstructionConstants.OP_IADD:
+ case InstructionConstants.OP_LADD:
+ case InstructionConstants.OP_FADD:
+ case InstructionConstants.OP_DADD:
+ case InstructionConstants.OP_ISUB:
+ case InstructionConstants.OP_LSUB:
+ case InstructionConstants.OP_FSUB:
+ case InstructionConstants.OP_DSUB:
+ case InstructionConstants.OP_IMUL:
+ case InstructionConstants.OP_LMUL:
+ case InstructionConstants.OP_FMUL:
+ case InstructionConstants.OP_DMUL:
+ case InstructionConstants.OP_IDIV:
+ case InstructionConstants.OP_LDIV:
+ case InstructionConstants.OP_FDIV:
+ case InstructionConstants.OP_DDIV:
+ case InstructionConstants.OP_IREM:
+ case InstructionConstants.OP_LREM:
+ case InstructionConstants.OP_FREM:
+ case InstructionConstants.OP_DREM:
+ case InstructionConstants.OP_INEG:
+ case InstructionConstants.OP_LNEG:
+ case InstructionConstants.OP_FNEG:
+ case InstructionConstants.OP_DNEG:
+ case InstructionConstants.OP_ISHL:
+ case InstructionConstants.OP_LSHL:
+ case InstructionConstants.OP_ISHR:
+ case InstructionConstants.OP_LSHR:
+ case InstructionConstants.OP_IUSHR:
+ case InstructionConstants.OP_LUSHR:
+ case InstructionConstants.OP_IAND:
+ case InstructionConstants.OP_LAND:
+ case InstructionConstants.OP_IOR:
+ case InstructionConstants.OP_LOR:
+ case InstructionConstants.OP_IXOR:
+ case InstructionConstants.OP_LXOR:
+
+ case InstructionConstants.OP_I2L:
+ case InstructionConstants.OP_I2F:
+ case InstructionConstants.OP_I2D:
+ case InstructionConstants.OP_L2I:
+ case InstructionConstants.OP_L2F:
+ case InstructionConstants.OP_L2D:
+ case InstructionConstants.OP_F2I:
+ case InstructionConstants.OP_F2L:
+ case InstructionConstants.OP_F2D:
+ case InstructionConstants.OP_D2I:
+ case InstructionConstants.OP_D2L:
+ case InstructionConstants.OP_D2F:
+ case InstructionConstants.OP_I2B:
+ case InstructionConstants.OP_I2C:
+ case InstructionConstants.OP_I2S:
+ case InstructionConstants.OP_LCMP:
+ case InstructionConstants.OP_FCMPL:
+ case InstructionConstants.OP_FCMPG:
+ case InstructionConstants.OP_DCMPL:
+ case InstructionConstants.OP_DCMPG:
+
+ case InstructionConstants.OP_IRETURN:
+ case InstructionConstants.OP_LRETURN:
+ case InstructionConstants.OP_FRETURN:
+ case InstructionConstants.OP_DRETURN:
+ case InstructionConstants.OP_ARETURN:
+ case InstructionConstants.OP_RETURN:
+
+ case InstructionConstants.OP_NEWARRAY:
+ case InstructionConstants.OP_ARRAYLENGTH:
+ case InstructionConstants.OP_ATHROW:
+
+ case InstructionConstants.OP_MONITORENTER:
+ case InstructionConstants.OP_MONITOREXIT:
+ instruction = simpleInstruction;
+ break;
+
+ // Instructions with a contant pool index.
+ case InstructionConstants.OP_LDC:
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_LDC2_W:
+
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_PUTSTATIC:
+ case InstructionConstants.OP_GETFIELD:
+ case InstructionConstants.OP_PUTFIELD:
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+
+ case InstructionConstants.OP_NEW:
+ case InstructionConstants.OP_ANEWARRAY:
+ case InstructionConstants.OP_CHECKCAST:
+ case InstructionConstants.OP_INSTANCEOF:
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ instruction = cpInstruction;
+ break;
+
+ // Instructions with a local variable index.
+ case InstructionConstants.OP_ILOAD:
+ case InstructionConstants.OP_LLOAD:
+ case InstructionConstants.OP_FLOAD:
+ case InstructionConstants.OP_DLOAD:
+ case InstructionConstants.OP_ALOAD:
+ case InstructionConstants.OP_ILOAD_0:
+ case InstructionConstants.OP_ILOAD_1:
+ case InstructionConstants.OP_ILOAD_2:
+ case InstructionConstants.OP_ILOAD_3:
+ case InstructionConstants.OP_LLOAD_0:
+ case InstructionConstants.OP_LLOAD_1:
+ case InstructionConstants.OP_LLOAD_2:
+ case InstructionConstants.OP_LLOAD_3:
+ case InstructionConstants.OP_FLOAD_0:
+ case InstructionConstants.OP_FLOAD_1:
+ case InstructionConstants.OP_FLOAD_2:
+ case InstructionConstants.OP_FLOAD_3:
+ case InstructionConstants.OP_DLOAD_0:
+ case InstructionConstants.OP_DLOAD_1:
+ case InstructionConstants.OP_DLOAD_2:
+ case InstructionConstants.OP_DLOAD_3:
+ case InstructionConstants.OP_ALOAD_0:
+ case InstructionConstants.OP_ALOAD_1:
+ case InstructionConstants.OP_ALOAD_2:
+ case InstructionConstants.OP_ALOAD_3:
+
+ case InstructionConstants.OP_ISTORE:
+ case InstructionConstants.OP_LSTORE:
+ case InstructionConstants.OP_FSTORE:
+ case InstructionConstants.OP_DSTORE:
+ case InstructionConstants.OP_ASTORE:
+ case InstructionConstants.OP_ISTORE_0:
+ case InstructionConstants.OP_ISTORE_1:
+ case InstructionConstants.OP_ISTORE_2:
+ case InstructionConstants.OP_ISTORE_3:
+ case InstructionConstants.OP_LSTORE_0:
+ case InstructionConstants.OP_LSTORE_1:
+ case InstructionConstants.OP_LSTORE_2:
+ case InstructionConstants.OP_LSTORE_3:
+ case InstructionConstants.OP_FSTORE_0:
+ case InstructionConstants.OP_FSTORE_1:
+ case InstructionConstants.OP_FSTORE_2:
+ case InstructionConstants.OP_FSTORE_3:
+ case InstructionConstants.OP_DSTORE_0:
+ case InstructionConstants.OP_DSTORE_1:
+ case InstructionConstants.OP_DSTORE_2:
+ case InstructionConstants.OP_DSTORE_3:
+ case InstructionConstants.OP_ASTORE_0:
+ case InstructionConstants.OP_ASTORE_1:
+ case InstructionConstants.OP_ASTORE_2:
+ case InstructionConstants.OP_ASTORE_3:
+
+ case InstructionConstants.OP_IINC:
+
+ case InstructionConstants.OP_RET:
+ variableInstruction.wide = wide;
+ instruction = variableInstruction;
+ break;
+
+ // Instructions with a branch offset operand.
+ case InstructionConstants.OP_IFEQ:
+ case InstructionConstants.OP_IFNE:
+ case InstructionConstants.OP_IFLT:
+ case InstructionConstants.OP_IFGE:
+ case InstructionConstants.OP_IFGT:
+ case InstructionConstants.OP_IFLE:
+ case InstructionConstants.OP_IFICMPEQ:
+ case InstructionConstants.OP_IFICMPNE:
+ case InstructionConstants.OP_IFICMPLT:
+ case InstructionConstants.OP_IFICMPGE:
+ case InstructionConstants.OP_IFICMPGT:
+ case InstructionConstants.OP_IFICMPLE:
+ case InstructionConstants.OP_IFACMPEQ:
+ case InstructionConstants.OP_IFACMPNE:
+ case InstructionConstants.OP_GOTO:
+ case InstructionConstants.OP_JSR:
+
+ case InstructionConstants.OP_IFNULL:
+ case InstructionConstants.OP_IFNONNULL:
+
+ case InstructionConstants.OP_GOTO_W:
+ case InstructionConstants.OP_JSR_W:
+ instruction = branchInstruction;
+ break;
+
+ // The tableswitch instruction.
+ case InstructionConstants.OP_TABLESWITCH:
+ instruction = tableSwitchInstruction;
+ break;
+
+ // The lookupswitch instruction.
+ case InstructionConstants.OP_LOOKUPSWITCH:
+ instruction = lookUpSwitchInstruction;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown instruction ["+opcode+"] at offset "+offset);
+ }
+
+ instruction.opcode = opcode;
+
+ instruction.readInfo(code, index);
+
+ return instruction;
+ }
+}
diff --git a/src/proguard/classfile/instruction/InstructionVisitor.java b/src/proguard/classfile/instruction/InstructionVisitor.java
new file mode 100644
index 0000000..3484c64
--- /dev/null
+++ b/src/proguard/classfile/instruction/InstructionVisitor.java
@@ -0,0 +1,41 @@
+/* $Id: InstructionVisitor.java,v 1.13 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>Instruction</code> objects.
+ *
+ * @author Eric Lafortune
+ */
+public interface InstructionVisitor
+{
+ public void visitSimpleInstruction( ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction);
+ public void visitVariableInstruction( ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction);
+ public void visitCpInstruction( ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction);
+ public void visitBranchInstruction( ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction);
+ public void visitTableSwitchInstruction( ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction);
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction);
+}
diff --git a/src/proguard/classfile/instruction/LookUpSwitchInstruction.java b/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
new file mode 100644
index 0000000..bb371f9
--- /dev/null
+++ b/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
@@ -0,0 +1,142 @@
+/* $Id: LookUpSwitchInstruction.java,v 1.6 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+/**
+ * This Instruction represents a simple instruction without variable arguments
+ * or constant pool references.
+ *
+ * @author Eric Lafortune
+ */
+public class LookUpSwitchInstruction extends Instruction
+{
+ public int defaultOffset;
+ public int jumpOffsetCount;
+ public int[] cases;
+ public int[] jumpOffsets;
+
+
+ /**
+ * Creates an uninitialized LookUpSwitchInstruction.
+ */
+ public LookUpSwitchInstruction() {}
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param lookUpSwitchInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public LookUpSwitchInstruction copy(LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ this.opcode = lookUpSwitchInstruction.opcode;
+ this.defaultOffset = lookUpSwitchInstruction.defaultOffset;
+ this.jumpOffsetCount = lookUpSwitchInstruction.jumpOffsetCount;
+ this.cases = lookUpSwitchInstruction.cases;
+ this.jumpOffsets = lookUpSwitchInstruction.jumpOffsets;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ // There aren't any ways to shrink this instruction.
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ // Skip up to three padding bytes.
+ offset += -offset & 3;
+
+ // Read the two 32-bit arguments.
+ defaultOffset = readInt(code, offset); offset += 4;
+ jumpOffsetCount = readInt(code, offset); offset += 4;
+
+ // Make sure there are sufficiently large match-offset tables.
+ if (jumpOffsets == null ||
+ jumpOffsets.length < jumpOffsetCount)
+ {
+ cases = new int[jumpOffsetCount];
+ jumpOffsets = new int[jumpOffsetCount];
+ }
+
+ // Read the matches-offset pairs.
+ for (int index = 0; index < jumpOffsetCount; index++)
+ {
+ cases[index] = readInt(code, offset); offset += 4;
+ jumpOffsets[index] = readInt(code, offset); offset += 4;
+ }
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ // Write up to three padding bytes.
+ while ((offset & 3) != 0)
+ {
+ writeByte(code, offset++, 0);
+ }
+
+ // Write the two 32-bit arguments.
+ writeInt(code, offset, defaultOffset); offset += 4;
+ writeInt(code, offset, jumpOffsetCount); offset += 4;
+
+ // Write the matches-offset pairs.
+ for (int index = 0; index < jumpOffsetCount; index++)
+ {
+ writeInt(code, offset, cases[index]); offset += 4;
+ writeInt(code, offset, jumpOffsets[index]); offset += 4;
+ }
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + (-(offset+1) & 3) + 8 + jumpOffsetCount * 8;
+ }
+
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitLookUpSwitchInstruction(classFile, methodInfo, codeAttrInfo, offset, this);
+ }
+
+
+ public String toString(int offset)
+ {
+ return "["+offset+"] "+getName()+" (switchCaseCount="+jumpOffsetCount+")";
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName()+" (switchCaseCount="+jumpOffsetCount+")";
+ }
+}
diff --git a/src/proguard/classfile/instruction/MultiInstructionVisitor.java b/src/proguard/classfile/instruction/MultiInstructionVisitor.java
new file mode 100644
index 0000000..5894285
--- /dev/null
+++ b/src/proguard/classfile/instruction/MultiInstructionVisitor.java
@@ -0,0 +1,138 @@
+/* $Id: MultiInstructionVisitor.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+
+/**
+ * This InstructionVisitor delegates all visits to each InstructionVisitor
+ * in a given list.
+ *
+ * @author Eric Lafortune
+ */
+public class MultiInstructionVisitor implements InstructionVisitor
+{
+ private static final int ARRAY_SIZE_INCREMENT = 5;
+
+ // Shared copies of Instruction objects, to avoid creating a lot of objects.
+ private final SimpleInstruction simpleInstruction = new SimpleInstruction();
+ private final CpInstruction cpInstruction = new CpInstruction();
+ private final VariableInstruction variableInstruction = new VariableInstruction();
+ private final BranchInstruction branchInstruction = new BranchInstruction();
+ private final TableSwitchInstruction tableSwitchInstruction = new TableSwitchInstruction();
+ private final LookUpSwitchInstruction lookUpSwitchInstruction = new LookUpSwitchInstruction();
+
+
+ private InstructionVisitor[] instructionVisitors;
+ private int instructionVisitorCount;
+
+
+ public MultiInstructionVisitor()
+ {
+ }
+
+
+ public MultiInstructionVisitor(InstructionVisitor[] instructionVisitors)
+ {
+ this.instructionVisitors = instructionVisitors;
+ this.instructionVisitorCount = instructionVisitors.length;
+ }
+
+
+ public void addInstructionVisitor(InstructionVisitor instructionVisitor)
+ {
+ ensureArraySize();
+
+ instructionVisitors[instructionVisitorCount++] = instructionVisitor;
+ }
+
+
+ private void ensureArraySize()
+ {
+ if (instructionVisitors == null)
+ {
+ instructionVisitors = new InstructionVisitor[ARRAY_SIZE_INCREMENT];
+ }
+ else if (instructionVisitors.length == instructionVisitorCount)
+ {
+ InstructionVisitor[] newInstructionVisitors =
+ new InstructionVisitor[instructionVisitorCount +
+ ARRAY_SIZE_INCREMENT];
+ System.arraycopy(instructionVisitors, 0,
+ newInstructionVisitors, 0,
+ instructionVisitorCount);
+ instructionVisitors = newInstructionVisitors;
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitSimpleInstruction(classFile, methodInfo, codeAttrInfo, offset, this.simpleInstruction.copy(simpleInstruction));
+ }
+ }
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitVariableInstruction(classFile, methodInfo, codeAttrInfo, offset, this.variableInstruction.copy(variableInstruction));
+ }
+ }
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitCpInstruction(classFile, methodInfo, codeAttrInfo, offset, this.cpInstruction.copy(cpInstruction));
+ }
+ }
+
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitBranchInstruction(classFile, methodInfo, codeAttrInfo, offset, this.branchInstruction.copy(branchInstruction));
+ }
+ }
+
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitTableSwitchInstruction(classFile, methodInfo, codeAttrInfo, offset, this.tableSwitchInstruction.copy(tableSwitchInstruction));
+ }
+ }
+
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitLookUpSwitchInstruction(classFile, methodInfo, codeAttrInfo, offset, this.lookUpSwitchInstruction.copy(lookUpSwitchInstruction));
+ }
+ }
+}
diff --git a/src/proguard/classfile/instruction/SimpleInstruction.java b/src/proguard/classfile/instruction/SimpleInstruction.java
new file mode 100644
index 0000000..90942a0
--- /dev/null
+++ b/src/proguard/classfile/instruction/SimpleInstruction.java
@@ -0,0 +1,182 @@
+/* $Id: SimpleInstruction.java,v 1.8 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+/**
+ * This Instruction represents a simple instruction without variable arguments
+ * or constant pool references.
+ *
+ * @author Eric Lafortune
+ */
+public class SimpleInstruction extends Instruction
+{
+ public int constant;
+
+
+ /**
+ * Creates an uninitialized SimpleInstruction.
+ */
+ public SimpleInstruction() {}
+
+
+ /**
+ * Creates a new SimpleInstruction with the given opcode.
+ */
+ public SimpleInstruction(byte opcode)
+ {
+ this(opcode, 0);
+ }
+
+
+ /**
+ * Creates a new SimpleInstruction with the given opcode and constant.
+ */
+ public SimpleInstruction(byte opcode, int constant)
+ {
+ this.opcode = opcode;
+ this.constant = constant;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param simpleInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public SimpleInstruction copy(SimpleInstruction simpleInstruction)
+ {
+ this.opcode = simpleInstruction.opcode;
+ this.constant = simpleInstruction.constant;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ // Is this a sipush instruction that can be a bipush instruction?
+ if (opcode == InstructionConstants.OP_SIPUSH &&
+ constant << 24 >> 24 == constant)
+ {
+ opcode = InstructionConstants.OP_BIPUSH;
+ }
+
+ // Is this a bipush instruction that can be an iconst instruction?
+ if (opcode == InstructionConstants.OP_BIPUSH &&
+ constant >= -1 &&
+ constant <= 5)
+ {
+ opcode = (byte)(InstructionConstants.OP_ICONST_0 + constant);
+ }
+
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ // Also initialize embedded constants that are different from 0.
+ switch (opcode)
+ {
+ case InstructionConstants.OP_ICONST_M1:
+ constant = -1;
+ break;
+
+ case InstructionConstants.OP_ICONST_1:
+ case InstructionConstants.OP_LCONST_1:
+ case InstructionConstants.OP_FCONST_1:
+ case InstructionConstants.OP_DCONST_1:
+ constant = 1;
+ break;
+
+ case InstructionConstants.OP_ICONST_2:
+ case InstructionConstants.OP_FCONST_2:
+ constant = 2;
+ break;
+
+ case InstructionConstants.OP_ICONST_3:
+ constant = 3;
+ break;
+
+ case InstructionConstants.OP_ICONST_4:
+ constant = 4;
+ break;
+
+ case InstructionConstants.OP_ICONST_5:
+ constant = 5;
+ break;
+
+ default:
+ constant = readSignedValue(code, offset, constantSize());
+ break;
+ }
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ writeValue(code, offset, constant, constantSize());
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + constantSize();
+ }
+
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitSimpleInstruction(classFile, methodInfo, codeAttrInfo, offset, this);
+ }
+
+
+ public String toString(int offset)
+ {
+ return "["+offset+"] "+getName()+" (constant="+constant+")";
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName()+" (constant="+constant+")";
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Computes the appropriate constant size for this instruction.
+ */
+ private int constantSize()
+ {
+ return opcode == InstructionConstants.OP_BIPUSH ||
+ opcode == InstructionConstants.OP_NEWARRAY ? 1 :
+ opcode == InstructionConstants.OP_SIPUSH ? 2 :
+ 0;
+ }
+}
diff --git a/src/proguard/classfile/instruction/TableSwitchInstruction.java b/src/proguard/classfile/instruction/TableSwitchInstruction.java
new file mode 100644
index 0000000..a2b269f
--- /dev/null
+++ b/src/proguard/classfile/instruction/TableSwitchInstruction.java
@@ -0,0 +1,145 @@
+/* $Id: TableSwitchInstruction.java,v 1.6 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+/**
+ * This Instruction represents a simple instruction without variable arguments
+ * or constant pool references.
+ *
+ * @author Eric Lafortune
+ */
+public class TableSwitchInstruction extends Instruction
+{
+ public int defaultOffset;
+ public int lowCase;
+ public int highCase;
+ public int jumpOffsetCount;
+ public int[] jumpOffsets;
+
+
+ /**
+ * Creates an uninitialized TableSwitchInstruction.
+ */
+ public TableSwitchInstruction() {}
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param tableSwitchInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public TableSwitchInstruction copy(TableSwitchInstruction tableSwitchInstruction)
+ {
+ this.opcode = tableSwitchInstruction.opcode;
+ this.defaultOffset = tableSwitchInstruction.defaultOffset;
+ this.lowCase = tableSwitchInstruction.lowCase;
+ this.highCase = tableSwitchInstruction.highCase;
+ this.jumpOffsetCount = tableSwitchInstruction.jumpOffsetCount;
+ this.jumpOffsets = tableSwitchInstruction.jumpOffsets;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ // There aren't any ways to shrink this instruction.
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ // Skip up to three padding bytes.
+ offset += -offset & 3;
+
+ // Read the three 32-bit arguments.
+ defaultOffset = readInt(code, offset); offset += 4;
+ lowCase = readInt(code, offset); offset += 4;
+ highCase = readInt(code, offset); offset += 4;
+
+ // Make sure there is a sufficiently large jump offset table.
+ jumpOffsetCount = highCase - lowCase + 1;
+ if (jumpOffsets == null ||
+ jumpOffsets.length < jumpOffsetCount)
+ {
+ jumpOffsets = new int[jumpOffsetCount];
+ }
+
+ // Read the jump offsets.
+ for (int index = 0; index < jumpOffsetCount; index++)
+ {
+ jumpOffsets[index] = readInt(code, offset); offset += 4;
+ }
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ // Write up to three padding bytes.
+ while ((offset & 3) != 0)
+ {
+ writeByte(code, offset++, 0);
+ }
+
+ // Write the three 32-bit arguments.
+ writeInt(code, offset, defaultOffset); offset += 4;
+ writeInt(code, offset, lowCase); offset += 4;
+ writeInt(code, offset, highCase); offset += 4;
+
+ // Write the jump offsets.
+ int length = highCase - lowCase + 1;
+ for (int index = 0; index < length; index++)
+ {
+ writeInt(code, offset, jumpOffsets[index]); offset += 4;
+ }
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + (-(offset+1) & 3) + 12 + (highCase - lowCase + 1) * 4;
+ }
+
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitTableSwitchInstruction(classFile, methodInfo, codeAttrInfo, offset, this);
+ }
+
+
+ public String toString(int offset)
+ {
+ return "["+offset+"] "+getName()+" (low="+lowCase+", high="+highCase+")";
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName()+" (low="+lowCase+", high="+highCase+")";
+ }
+}
diff --git a/src/proguard/classfile/instruction/VariableInstruction.java b/src/proguard/classfile/instruction/VariableInstruction.java
new file mode 100644
index 0000000..7b60f6b
--- /dev/null
+++ b/src/proguard/classfile/instruction/VariableInstruction.java
@@ -0,0 +1,224 @@
+/* $Id: VariableInstruction.java,v 1.17 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+/**
+ * This Instruction represents an instruction that refers to a variable on the
+ * local variable stack.
+ *
+ * @author Eric Lafortune
+ */
+public class VariableInstruction extends Instruction
+{
+ public boolean wide;
+ public int variableIndex;
+ public int constant;
+
+
+ /**
+ * Creates an uninitialized VariableInstruction.
+ */
+ public VariableInstruction() {}
+
+
+ public VariableInstruction(byte opcode,
+ int variableIndex)
+ {
+ this(opcode, variableIndex, 0);
+ }
+
+
+ public VariableInstruction(byte opcode,
+ int variableIndex,
+ int constant)
+ {
+ this.opcode = opcode;
+ this.variableIndex = variableIndex;
+ this.constant = constant;
+ this.wide = mustBeWide();
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param variableInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public VariableInstruction copy(VariableInstruction variableInstruction)
+ {
+ this.opcode = variableInstruction.opcode;
+ this.variableIndex = variableInstruction.variableIndex;
+ this.constant = variableInstruction.constant;
+ this.wide = variableInstruction.wide;
+
+ return this;
+ }
+
+
+ /**
+ * Returns whether this instruction loads the value of a variable onto the
+ * stack, or if it stores one.
+ */
+ public boolean isLoad()
+ {
+ // A load instruction can be recognized as follows.
+ // Note that this includes the ret instruction, which has a negative opcode.
+ // The iinc instruction is considered a store instruction.
+ return opcode < InstructionConstants.OP_ISTORE &&
+ opcode != InstructionConstants.OP_IINC;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ // Is this instruction pointing to a variable with index from 0 to 3?
+ if (variableIndex <= 3)
+ {
+ switch (opcode)
+ {
+ case InstructionConstants.OP_ILOAD: opcode = (byte)(InstructionConstants.OP_ILOAD_0 + variableIndex); break;
+ case InstructionConstants.OP_LLOAD: opcode = (byte)(InstructionConstants.OP_LLOAD_0 + variableIndex); break;
+ case InstructionConstants.OP_FLOAD: opcode = (byte)(InstructionConstants.OP_FLOAD_0 + variableIndex); break;
+ case InstructionConstants.OP_DLOAD: opcode = (byte)(InstructionConstants.OP_DLOAD_0 + variableIndex); break;
+ case InstructionConstants.OP_ALOAD: opcode = (byte)(InstructionConstants.OP_ALOAD_0 + variableIndex); break;
+
+ case InstructionConstants.OP_ISTORE: opcode = (byte)(InstructionConstants.OP_ISTORE_0 + variableIndex); break;
+ case InstructionConstants.OP_LSTORE: opcode = (byte)(InstructionConstants.OP_LSTORE_0 + variableIndex); break;
+ case InstructionConstants.OP_FSTORE: opcode = (byte)(InstructionConstants.OP_FSTORE_0 + variableIndex); break;
+ case InstructionConstants.OP_DSTORE: opcode = (byte)(InstructionConstants.OP_DSTORE_0 + variableIndex); break;
+ case InstructionConstants.OP_ASTORE: opcode = (byte)(InstructionConstants.OP_ASTORE_0 + variableIndex); break;
+ }
+ }
+
+ // Only make the instruction wide if necessary.
+ wide = mustBeWide();
+
+ return this;
+ }
+
+
+ protected boolean isWide()
+ {
+ return wide;
+ }
+
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ int variableIndexSize = variableIndexSize();
+ int constantSize = constantSize();
+
+ // Also initialize embedded variable indexes.
+ if (variableIndexSize == 0)
+ {
+ // An embedded variable index can be decoded as follows.
+ variableIndex = opcode < InstructionConstants.OP_ISTORE_0 ?
+ (opcode - InstructionConstants.OP_ILOAD_0 ) & 3 :
+ (opcode - InstructionConstants.OP_ISTORE_0) & 3;
+ }
+ else
+ {
+ variableIndex = readValue(code, offset, variableIndexSize); offset += variableIndexSize;
+ }
+
+ constant = readSignedValue(code, offset, constantSize);
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ int variableIndexSize = variableIndexSize();
+ int constantSize = constantSize();
+
+ writeValue(code, offset, variableIndex, variableIndexSize); offset += variableIndexSize;
+ writeValue(code, offset, constant, constantSize);
+ }
+
+
+ public int length(int offset)
+ {
+ return (wide ? 2 : 1) + variableIndexSize() + constantSize();
+ }
+
+
+ public void accept(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitVariableInstruction(classFile, methodInfo, codeAttrInfo, offset, this);
+ }
+
+
+ public String toString(int offset)
+ {
+ return "["+offset+"] "+getName()+(wide?"_w":"")+" (variableIndex="+variableIndex+", constant="+constant+")";
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName()+" (variableIndex="+variableIndex+", constant="+constant+")";
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether this instruction must be wide due to its variable index
+ * and constant.
+ */
+ private boolean mustBeWide()
+ {
+ return variableIndex > 0xff ||
+ (opcode == InstructionConstants.OP_IINC ? (constant < -128 ||
+ constant > 127) :
+ constant > 255);
+ }
+
+
+ /**
+ * Returns the appropriate variable index size for this instruction.
+ */
+ private int variableIndexSize()
+ {
+ return (opcode >= InstructionConstants.OP_ILOAD_0 &&
+ opcode <= InstructionConstants.OP_ALOAD_3) ||
+ (opcode >= InstructionConstants.OP_ISTORE_0 &&
+ opcode <= InstructionConstants.OP_ASTORE_3) ? 0 :
+ wide ? 2 :
+ 1;
+ }
+
+
+ /**
+ * Returns the appropriate constant size for this instruction.
+ */
+ private int constantSize()
+ {
+ return opcode == InstructionConstants.OP_IINC ? (wide ? 2 : 1) :
+ 0;
+ }
+}
diff --git a/src/proguard/classfile/instruction/package.html b/src/proguard/classfile/instruction/package.html
new file mode 100644
index 0000000..48c234e
--- /dev/null
+++ b/src/proguard/classfile/instruction/package.html
@@ -0,0 +1,9 @@
+<body>
+This package contains classes to represent Java bytecode instructions.
+<p>
+Not every instruction currently has its own class. Only groups of instructions
+that refer to the constant pool get their own representations.
+<p>
+While the package is sufficient for the current needs of the ProGuard
+application, it may very well be reorganised and extended in the future.
+</body>
diff --git a/src/proguard/classfile/package.html b/src/proguard/classfile/package.html
new file mode 100644
index 0000000..fad087c
--- /dev/null
+++ b/src/proguard/classfile/package.html
@@ -0,0 +1,15 @@
+<body>
+This package contains classes to represent the various elements of class files.
+<p>
+A class file is represented by the <code>{@link proguard.classfile.ClassFile
+ClassFile}</code> interface. This interface currently has two alternative
+representations:
+<ul>
+<li><code>{@link ProgramClassFile ProgramClassFile}</code>:
+ a complete representation that can be read, modified, and written back.
+<li><code>{@link LibraryClassFile LibraryClassFile}</code>:
+ an incomplete representation that can be only be read. It is however
+ more compact than <code>ProgramClassFile</code>, and sufficient for
+ analyzing class files from library jars.
+</ul>
+</body>
diff --git a/src/proguard/classfile/util/AccessUtil.java b/src/proguard/classfile/util/AccessUtil.java
new file mode 100644
index 0000000..af7c034
--- /dev/null
+++ b/src/proguard/classfile/util/AccessUtil.java
@@ -0,0 +1,99 @@
+/* $Id: AccessUtil.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+
+
+/**
+ * Utility methods for working with access flags. For convenience, this class
+ * defines access levels, in ascending order: <code>PRIVATE</code>,
+ * <code>PACKAGE_VISIBLE</code>, <code>PROTECTED</code>, and <code>PUBLIC</code>.
+ *
+ * @author Eric Lafortune
+ */
+public class AccessUtil
+{
+ public static final int PRIVATE = 0;
+ public static final int PACKAGE_VISIBLE = 1;
+ public static final int PROTECTED = 2;
+ public static final int PUBLIC = 3;
+
+
+ // The mask of access flags.
+ private static final int ACCESS_MASK =
+ ClassConstants.INTERNAL_ACC_PUBLIC |
+ ClassConstants.INTERNAL_ACC_PRIVATE |
+ ClassConstants.INTERNAL_ACC_PROTECTED;
+
+
+ /**
+ * Returns the corresponding access level of the given access flags.
+ * @param accessFlags the internal access flags.
+ * @return the corresponding access level: <code>PRIVATE</code>,
+ * <code>PACKAGE_VISIBLE</code>, <code>PROTECTED</code>, or
+ * <code>PUBLIC</code>.
+ */
+ public static int accessLevel(int accessFlags)
+ {
+ switch (accessFlags & ACCESS_MASK)
+ {
+ case ClassConstants.INTERNAL_ACC_PRIVATE: return PRIVATE;
+ default: return PACKAGE_VISIBLE;
+ case ClassConstants.INTERNAL_ACC_PROTECTED: return PROTECTED;
+ case ClassConstants.INTERNAL_ACC_PUBLIC: return PUBLIC;
+ }
+ }
+
+
+ /**
+ * Returns the corresponding access flags of the given access level.
+ * @param accessLevel the access level: <code>PRIVATE</code>,
+ * <code>PACKAGE_VISIBLE</code>, <code>PROTECTED</code>,
+ * or <code>PUBLIC</code>.
+ * @return the corresponding internal access flags, the internal access
+ * flags as a logical bit mask of <code>INTERNAL_ACC_PRIVATE</code>,
+ * <code>INTERNAL_ACC_PROTECTED</code>, and
+ * <code>INTERNAL_ACC_PUBLIC</code>.
+ */
+ public static int accessFlags(int accessLevel)
+ {
+ switch (accessLevel)
+ {
+ case PRIVATE: return ClassConstants.INTERNAL_ACC_PRIVATE;
+ default: return 0;
+ case PROTECTED: return ClassConstants.INTERNAL_ACC_PROTECTED;
+ case PUBLIC: return ClassConstants.INTERNAL_ACC_PUBLIC;
+ }
+ }
+
+
+ /**
+ * Replaces the access part of the given access flags.
+ * @param accessFlags the internal access flags.
+ * @param accessFlags the new internal access flags.
+ */
+ public static int replaceAccessFlags(int accessFlags, int newAccessFlags)
+ {
+ return (accessFlags & ~ACCESS_MASK) |
+ (newAccessFlags & ACCESS_MASK);
+ }
+}
diff --git a/src/proguard/classfile/util/ClassFileClassForNameReferenceInitializer.java b/src/proguard/classfile/util/ClassFileClassForNameReferenceInitializer.java
new file mode 100644
index 0000000..caeac24
--- /dev/null
+++ b/src/proguard/classfile/util/ClassFileClassForNameReferenceInitializer.java
@@ -0,0 +1,260 @@
+/* $Id: ClassFileClassForNameReferenceInitializer.java,v 1.14 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This InstructionVisitor initializes any special <code>Class.forName</code> or
+ * <code>.class</code> references of all class files it visits. More specifically,
+ * it fills out the references of String constant pool entries that refer to a
+ * class file in the program class pool.
+ * <p>
+ * It optionally prints notes if on usage of
+ * <code>(SomeClass)Class.forName(variable).newInstance()</code>.
+ * <p>
+ * The class file hierarchy must be initialized before using this visitor.
+ *
+ * @see ClassFileReferenceInitializer
+ *
+ * @author Eric Lafortune
+ */
+class ClassFileClassForNameReferenceInitializer
+implements InstructionVisitor,
+ CpInfoVisitor
+{
+ private ClassPool programClassPool;
+ private boolean note;
+
+ // Counter for notes.
+ private int noteCount;
+
+ // Fields to remember the previous StringCpInfo and MethodRefCpInfo objects
+ // while visiting all instructions (to find Class.forName, class$, and
+ // Class.newInstance invocations, and possible class casts afterwards).
+ private int ldcStringCpIndex = -1;
+ private int invokestaticMethodRefCpIndex = -1;
+ private int invokevirtualMethodRefCpIndex = -1;
+
+ private ClassForNameChecker classForNameChecker = new ClassForNameChecker();
+ private ClassNewInstanceChecker classNewInstanceChecker = new ClassNewInstanceChecker();
+
+
+ /**
+ * Creates a new ClassFileClassForNameReferenceInitializer that prints notes.
+ */
+ public ClassFileClassForNameReferenceInitializer(ClassPool programClassPool)
+ {
+ this(programClassPool, true);
+ }
+
+
+ /**
+ * Creates a new ClassFileClassForNameReferenceInitializer that optionally
+ * prints notes.
+ */
+ public ClassFileClassForNameReferenceInitializer(ClassPool programClassPool,
+ boolean note)
+ {
+ this.programClassPool = programClassPool;
+ this.note = note;
+ }
+
+
+ /**
+ * Returns the number of notes printed about occurrences of
+ * '<code>(SomeClass)Class.forName(variable).newInstance()</code>'.
+ */
+ public int getNoteCount()
+ {
+ return noteCount;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ // Just ignore generic instructions and reset the constant pool indices.
+ switch (variableInstruction.opcode)
+ {
+ case InstructionConstants.OP_ICONST_0:
+ case InstructionConstants.OP_ICONST_1:
+ // Still remember any loaded string; this instruction may be
+ // setting up the second argument for class$(String, boolean).
+ break;
+
+ default:
+ ldcStringCpIndex = -1;
+ break;
+ }
+
+ invokestaticMethodRefCpIndex = -1;
+ invokevirtualMethodRefCpIndex = -1;
+ }
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ int currentCpIndex = cpInstruction.cpIndex;
+
+ switch (cpInstruction.opcode)
+ {
+ case InstructionConstants.OP_LDC:
+ case InstructionConstants.OP_LDC_W:
+ // Are we loading a constant String?
+ int currentCpTag = classFile.getCpTag(currentCpIndex);
+ if (currentCpTag == ClassConstants.CONSTANT_String)
+ {
+ // Remember it; it might be the argument of
+ // Class.forName(String), class$(String), or
+ // class$(String, boolean).
+ ldcStringCpIndex = currentCpIndex;
+ }
+ invokestaticMethodRefCpIndex = -1;
+ invokevirtualMethodRefCpIndex = -1;
+ break;
+
+ case InstructionConstants.OP_INVOKESTATIC:
+ // Are we invoking a static method that might have a constant
+ // String argument?
+ if (ldcStringCpIndex > 0)
+ {
+ // Check whether the method reference points to Class.forName.
+ if (classForNameChecker.check(classFile, currentCpIndex))
+ {
+ // Fill out the class file reference in the String.
+ classFile.constantPoolEntryAccept(ldcStringCpIndex, this);
+ }
+
+ // We've dealt with this invocation, so we can forget about it.
+ invokestaticMethodRefCpIndex = -1;
+ }
+ else
+ {
+ // Remember it; it might still be a Class.forName with a
+ // variable String argument.
+ invokestaticMethodRefCpIndex = currentCpIndex;
+ }
+
+ ldcStringCpIndex = -1;
+ invokevirtualMethodRefCpIndex = -1;
+ break;
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ // Are we invoking a virtual method right after a static method?
+ if (invokestaticMethodRefCpIndex > 0)
+ {
+ // Remember it; it might be Class.newInstance after a Class.forName.
+ invokevirtualMethodRefCpIndex = currentCpIndex;
+ }
+ else
+ {
+ invokestaticMethodRefCpIndex = -1;
+ invokevirtualMethodRefCpIndex = -1;
+ }
+
+ ldcStringCpIndex = -1;
+ break;
+
+ case InstructionConstants.OP_CHECKCAST:
+ // Are we checking a cast right after a static method and a
+ // virtual method?
+ if (invokestaticMethodRefCpIndex > 0 &&
+ invokevirtualMethodRefCpIndex > 0)
+ {
+ // Check whether the first method reference points to Class.forName,
+ // and the second method reference to Class.newInstance.
+ if (classForNameChecker.check(classFile, invokestaticMethodRefCpIndex) &&
+ classNewInstanceChecker.check(classFile, invokevirtualMethodRefCpIndex))
+ {
+ // Note which class is being cast to.
+ classFile.constantPoolEntryAccept(currentCpIndex, this);
+ }
+ }
+
+ ldcStringCpIndex = -1;
+ invokestaticMethodRefCpIndex = -1;
+ invokevirtualMethodRefCpIndex = -1;
+ break;
+
+ default:
+ // Nothing interesting; just forget about previous indices.
+ ldcStringCpIndex = -1;
+ invokestaticMethodRefCpIndex = -1;
+ invokevirtualMethodRefCpIndex = -1;
+ break;
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ /**
+ * Fills out the link to the referenced ClassFile.
+ */
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ // Save a reference to the corresponding class file.
+ String externalClassName = stringCpInfo.getString(classFile);
+ String internalClassName = ClassUtil.internalClassName(externalClassName);
+
+ stringCpInfo.referencedClassFile = programClassPool.getClass(internalClassName);
+ }
+
+
+ /**
+ * Prints out a note about the class cast to this class, if applicable.
+ */
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ if (note)
+ {
+ noteCount++;
+ System.err.println("Note: " +
+ ClassUtil.externalClassName(classFile.getName()) +
+ " calls '(" +
+ ClassUtil.externalClassName(classCpInfo.getName(classFile)) +
+ ")Class.forName(variable).newInstance()'");
+ }
+ }
+}
diff --git a/src/proguard/classfile/util/ClassFileHierarchyInitializer.java b/src/proguard/classfile/util/ClassFileHierarchyInitializer.java
new file mode 100644
index 0000000..04941ec
--- /dev/null
+++ b/src/proguard/classfile/util/ClassFileHierarchyInitializer.java
@@ -0,0 +1,282 @@
+/* $Id: ClassFileHierarchyInitializer.java,v 1.10 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor initializes the class hierarchy of all class files that
+ * it visits.
+ * <p>
+ * Visited class files are added to the subclass list of their superclasses and
+ * interfaces. These subclass lists make it more convenient to travel down the
+ * class hierarchy.
+ * <p>
+ * Visited library class files get direct references to their superclasses and
+ * interfaces, replacing the superclass names and interface names. The direct
+ * references are equivalent to the names, but they are more efficient to work
+ * with.
+ * <p>
+ * This visitor optionally prints warnings if some items can't be found.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileHierarchyInitializer
+ implements ClassFileVisitor,
+ CpInfoVisitor
+{
+ // A visitor info flag to indicate the class file has been initialized.
+ private static final Object INITIALIZED = new Object();
+
+ private ClassPool programClassPool;
+ private ClassPool libraryClassPool;
+ private boolean warn;
+
+ // Counter for warnings.
+ private int warningCount;
+
+
+ /**
+ * Creates a new ClassFileReferenceInitializer that initializes the hierarchy
+ * of all visited class files, printing warnings if some classes can't be found.
+ */
+ public ClassFileHierarchyInitializer(ClassPool programClassPool,
+ ClassPool libraryClassPool)
+ {
+ this(programClassPool, libraryClassPool, true);
+ }
+
+
+ /**
+ * Creates a new ClassFileReferenceInitializer that initializes the hierarchy
+ * of all visited class files, optionally printing warnings if some classes
+ * can't be found.
+ */
+ public ClassFileHierarchyInitializer(ClassPool programClassPool,
+ ClassPool libraryClassPool,
+ boolean warn)
+ {
+ this.programClassPool = programClassPool;
+ this.libraryClassPool = libraryClassPool;
+ this.warn = warn;
+ }
+
+
+ /**
+ * Returns the number of warnings printed about unresolved references to
+ * superclasses or interfaces.
+ */
+ public int getWarningCount()
+ {
+ return warningCount;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Haven't we initialized this class before?
+ if (!isInitialized(programClassFile))
+ {
+ // Mark this class.
+ markAsInitialized(programClassFile);
+
+ if (programClassFile.u2superClass != 0)
+ {
+ programClassFile.constantPoolEntryAccept(programClassFile.u2superClass,
+ this);
+ }
+
+ // Add this class to the subclasses of its superclass.
+ if (programClassFile.u2superClass != 0)
+ {
+ addSubclass(programClassFile,
+ programClassFile.getSuperClass(),
+ programClassFile.getSuperName());
+ }
+
+ // Add this class to the subclasses of its interfaces.
+ for (int index = 0; index < programClassFile.u2interfacesCount; index++)
+ {
+ programClassFile.constantPoolEntryAccept(programClassFile.u2interfaces[index],
+ this);
+
+ addSubclass(programClassFile,
+ programClassFile.getInterface(index),
+ programClassFile.getInterfaceName(index));
+ }
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ // Haven't we initialized this class before?
+ if (!isInitialized(libraryClassFile))
+ {
+ // Mark this class.
+ markAsInitialized(libraryClassFile);
+
+ // Have a closer look at the superclass.
+ String superClassName = libraryClassFile.superClassName;
+ if (superClassName != null)
+ {
+ // Find and initialize the super class.
+ ClassFile superClass = findAndInitializeClass(superClassName);
+
+ // Add this class to the subclasses of its superclass,
+ addSubclass(libraryClassFile,
+ superClass,
+ superClassName);
+
+ // Keep a reference to the superclass.
+ libraryClassFile.superClass = superClass;
+ }
+
+ // Have a closer look at the interface classes.
+ if (libraryClassFile.interfaceNames != null)
+ {
+ String[] interfaceNames = libraryClassFile.interfaceNames;
+ ClassFile[] interfaceClasses = new ClassFile[interfaceNames.length];
+
+ for (int index = 0; index < interfaceNames.length; index++)
+ {
+ // Find and initialize the interface class.
+ String interfaceName = interfaceNames[index];
+ ClassFile interfaceClass = findAndInitializeClass(interfaceName);
+
+ // Add this class to the subclasses of the interface class.
+ addSubclass(libraryClassFile,
+ interfaceClass,
+ interfaceName);
+
+ // Keep a reference to the interface class.
+ interfaceClasses[index] = interfaceClass;
+ }
+
+ libraryClassFile.interfaceClasses = interfaceClasses;
+ }
+
+ // Discard the name Strings. From now on, we'll use the object
+ // references.
+ libraryClassFile.superClassName = null;
+ libraryClassFile.interfaceNames = null;
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ classCpInfo.referencedClassFile =
+ findAndInitializeClass(classCpInfo.getName(classFile));
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Finds and initializes a class with the given name.
+ *
+ * @see #findClass(String)
+ */
+ private ClassFile findAndInitializeClass(String name)
+ {
+ // Try to find the class file.
+ ClassFile referencedClassFile = findClass(name);
+
+ // Did we find the referenced class file in either class pool?
+ if (referencedClassFile != null)
+ {
+ // Initialize it.
+ referencedClassFile.accept(this);
+ }
+
+ return referencedClassFile;
+ }
+
+
+ /**
+ * Returns the class with the given name, either for the program class pool
+ * or from the library class pool, or <code>null</code> if it can't be found.
+ */
+ private ClassFile findClass(String name)
+ {
+ // First look for the class in the program class pool.
+ ClassFile classFile = programClassPool.getClass(name);
+
+ // Otherwise look for the class in the library class pool.
+ if (classFile == null)
+ {
+ classFile = libraryClassPool.getClass(name);
+ }
+
+ return classFile;
+ }
+
+
+ private static void markAsInitialized(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(INITIALIZED);
+ }
+
+
+ private static boolean isInitialized(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == INITIALIZED;
+ }
+
+
+ private void addSubclass(ClassFile subclass,
+ ClassFile classFile,
+ String className)
+ {
+ if (classFile != null)
+ {
+ classFile.addSubClass(subclass);
+ }
+ else if (warn)
+ {
+ // We didn't find the superclass or interface. Print a warning.
+ warningCount++;
+ System.err.println("Warning: " +
+ ClassUtil.externalClassName(subclass.getName()) +
+ ": can't find superclass or interface " +
+ ClassUtil.externalClassName(className));
+ }
+ }
+}
diff --git a/src/proguard/classfile/util/ClassFileReferenceInitializer.java b/src/proguard/classfile/util/ClassFileReferenceInitializer.java
new file mode 100644
index 0000000..717fcd2
--- /dev/null
+++ b/src/proguard/classfile/util/ClassFileReferenceInitializer.java
@@ -0,0 +1,523 @@
+/* $Id: ClassFileReferenceInitializer.java,v 1.28 2004/11/27 10:09:26 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor initializes the references of all class files that
+ * it visits.
+ * <p>
+ * All class constant pool entries get direct references to the corresponding
+ * classes. These references make it more convenient to travel up and across
+ * the class hierarchy.
+ * <p>
+ * All field and method reference constant pool entries get direct references
+ * to the corresponding classes, fields, and methods.
+ * <p>
+ * All name and type constant pool entries get a list of direct references to
+ * the classes listed in the type.
+ * <p>
+ * This visitor optionally prints warnings if some items can't be found, and
+ * notes on the usage of <code>(SomeClass)Class.forName(variable).newInstance()</code>.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileReferenceInitializer
+ implements ClassFileVisitor,
+ MemberInfoVisitor,
+ CpInfoVisitor,
+ AttrInfoVisitor,
+ //LocalVariableInfoVisitor,
+ //LocalVariableTypeInfoVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor
+{
+ // A reusable object for checking whether referenced methods are Class.forName,...
+ private ClassFileClassForNameReferenceInitializer classFileClassForNameReferenceInitializer;
+
+ private MemberFinder memberFinder = new MemberFinder();
+
+ private ClassPool programClassPool;
+ private ClassPool libraryClassPool;
+ private boolean warn;
+
+ // Counter for warnings.
+ private int warningCount;
+
+
+ /**
+ * Creates a new ClassFileReferenceInitializer that initializes the hierarchy
+ * of all visited class files, printing warnings if some classes can't be found.
+ */
+ public ClassFileReferenceInitializer(ClassPool programClassPool,
+ ClassPool libraryClassPool)
+ {
+ this(programClassPool, libraryClassPool, true, true);
+ }
+
+
+ /**
+ * Creates a new ClassFileReferenceInitializer that initializes the hierarchy
+ * of all visited class files, optionally printing warnings if some classes
+ * can't be found.
+ */
+ public ClassFileReferenceInitializer(ClassPool programClassPool,
+ ClassPool libraryClassPool,
+ boolean warn,
+ boolean note)
+ {
+ this.programClassPool = programClassPool;
+ this.libraryClassPool = libraryClassPool;
+ this.warn = warn;
+
+ classFileClassForNameReferenceInitializer =
+ new ClassFileClassForNameReferenceInitializer(programClassPool, note);
+ }
+
+
+ /**
+ * Returns the number of warnings printed about unresolved references to
+ * class members in program class files.
+ */
+ public int getWarningCount()
+ {
+ return warningCount;
+ }
+
+
+ /**
+ * Returns the number of notes printed about occurrences of
+ * '<code>(SomeClass)Class.forName(variable).newInstance()</code>'.
+ */
+ public int getNoteCount()
+ {
+ return classFileClassForNameReferenceInitializer.getNoteCount();
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Initialize the constant pool entries.
+ programClassFile.constantPoolEntriesAccept(this);
+
+ // Initialize all fields and methods.
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+
+ // Initialize the attributes.
+ programClassFile.attributesAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ programMemberInfo.referencedClassFiles =
+ findReferencedClasses(programMemberInfo.getDescriptor(programClassFile));
+
+ // Initialize the attributes.
+ programMemberInfo.attributesAccept(programClassFile, this);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ visitRefCpInfo(classFile, fieldrefCpInfo, true);
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, interfaceMethodrefCpInfo, false);
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, methodrefCpInfo, false);
+ }
+
+
+ private void visitRefCpInfo(ClassFile classFile, RefCpInfo refCpInfo, boolean isFieldRef)
+ {
+ String className = refCpInfo.getClassName(classFile);
+
+ // See if we can find the referenced class file.
+ // Unresolved references are assumed to refer to library class files
+ // that will not change anyway.
+ ClassFile referencedClassFile = findClass(className);
+
+ if (referencedClassFile != null)
+ {
+ String name = refCpInfo.getName(classFile);
+ String type = refCpInfo.getType(classFile);
+
+ // See if we can find the referenced class membver somewhere in the
+ // hierarchy.
+ refCpInfo.referencedMemberInfo = memberFinder.findMember(referencedClassFile,
+ name,
+ type,
+ isFieldRef);
+ refCpInfo.referencedClassFile = memberFinder.correspondingClassFile();
+
+ if (warn && refCpInfo.referencedMemberInfo == null)
+ {
+ // We've haven't found the class member anywhere in the hierarchy.
+ warningCount++;
+ System.err.println("Warning: " +
+ ClassUtil.externalClassName(classFile.getName()) +
+ ": can't find referenced " +
+ (isFieldRef ?
+ "field '" + ClassUtil.externalFullFieldDescription(0, name, type) :
+ "method '" + ClassUtil.externalFullMethodDescription(className, 0, name, type)) +
+ "' in class " +
+ ClassUtil.externalClassName(className));
+ }
+ }
+ }
+
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ classCpInfo.referencedClassFile =
+ findClass(classCpInfo.getName(classFile));
+ }
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ nameAndTypeCpInfo.referencedClassFiles =
+ findReferencedClasses(nameAndTypeCpInfo.getType(classFile));
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ String className = enclosingMethodAttrInfo.getClassName(classFile);
+
+ // See if we can find the referenced class file.
+ ClassFile referencedClassFile = findClass(className);
+
+ if (referencedClassFile == null)
+ {
+ // We couldn't find the enclosing class.
+ if (warn)
+ {
+ warningCount++;
+ System.err.println("Warning: " +
+ ClassUtil.externalClassName(classFile.getName()) +
+ ": can't find enclosing class " +
+ ClassUtil.externalClassName(className));
+ }
+
+ return;
+ }
+
+ // Make sure there is actually an enclosed method.
+ if (enclosingMethodAttrInfo.u2nameAndTypeIndex == 0)
+ {
+ return;
+ }
+
+ String name = enclosingMethodAttrInfo.getName(classFile);
+ String type = enclosingMethodAttrInfo.getType(classFile);
+
+ // See if we can find the method in the referenced class.
+ MethodInfo referencedMethodInfo = referencedClassFile.findMethod(name, type);
+
+ if (referencedMethodInfo == null)
+ {
+ // We couldn't find the enclosing method.
+ if (warn)
+ {
+ warningCount++;
+ System.err.println("Warning: " +
+ ClassUtil.externalClassName(classFile.getName()) +
+ ": can't find enclosing method '" +
+ ClassUtil.externalFullMethodDescription(className, 0, name, type) +
+ "' in class " +
+ ClassUtil.externalClassName(className));
+ }
+
+ return;
+ }
+
+ // Save the references.
+ enclosingMethodAttrInfo.referencedClassFile = referencedClassFile;
+ enclosingMethodAttrInfo.referencedMethodInfo = referencedMethodInfo;
+ }
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ codeAttrInfo.instructionsAccept(classFile, methodInfo, classFileClassForNameReferenceInitializer);
+ }
+
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ signatureAttrInfo.referencedClassFiles =
+ findReferencedClasses(classFile.getCpString(signatureAttrInfo.u2signatureIndex));
+ }
+
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ // Initialize the annotations.
+ runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ // Initialize the annotations.
+ runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ // Initialize the annotations.
+ runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ // Initialize the annotations.
+ runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ // Initialize the annotation.
+ annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+ {
+ localVariableInfo.referencedClassFile =
+ findClass(classFile.getCpString(localVariableInfo.u2descriptorIndex));
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ localVariableTypeInfo.referencedClassFiles =
+ findReferencedClasses(classFile.getCpString(localVariableTypeInfo.u2signatureIndex));
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(ClassFile classFile, Annotation annotation)
+ {
+ annotation.referencedClassFiles =
+ findReferencedClasses(classFile.getCpString(annotation.u2typeIndex));
+
+ // Initialize the element values.
+ annotation.elementValuesAccept(classFile, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ initializeElementValue(classFile, annotation, constantElementValue);
+ }
+
+
+ public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ initializeElementValue(classFile, annotation, enumConstantElementValue);
+
+ enumConstantElementValue.referencedClassFiles =
+ findReferencedClasses(classFile.getCpString(enumConstantElementValue.u2typeNameIndex));
+ }
+
+
+ public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
+ {
+ initializeElementValue(classFile, annotation, classElementValue);
+
+ classElementValue.referencedClassFiles =
+ findReferencedClasses(classFile.getCpString(classElementValue.u2classInfoIndex));
+ }
+
+
+ public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ initializeElementValue(classFile, annotation, annotationElementValue);
+
+ // Initialize the annotation.
+ annotationElementValue.annotationAccept(classFile, this);
+ }
+
+
+ public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ initializeElementValue(classFile, annotation, arrayElementValue);
+
+ // Initialize the element values.
+ arrayElementValue.elementValuesAccept(classFile, annotation, this);
+ }
+
+
+ /**
+ * Initializes the referenced method of an element value, if any.
+ */
+ private void initializeElementValue(ClassFile classFile, Annotation annotation, ElementValue elementValue)
+ {
+ // See if we have a referenced class file.
+ if (annotation != null &&
+ annotation.referencedClassFiles != null &&
+ elementValue.u2elementName != 0)
+ {
+ // See if we can find the method in the referenced class
+ // (ignoring the descriptor).
+ String name = classFile.getCpString(elementValue.u2elementName);
+
+ elementValue.referencedMethodInfo =
+ annotation.referencedClassFiles[0].findMethod(name, null);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns an array of class files referenced by the given descriptor, or
+ * <code>null</code> if there aren't any useful references.
+ */
+ private ClassFile[] findReferencedClasses(String descriptor)
+ {
+ DescriptorClassEnumeration enumeration =
+ new DescriptorClassEnumeration(descriptor);
+
+ int classCount = enumeration.classCount();
+ if (classCount > 0)
+ {
+ ClassFile[] referencedClassFiles = new ClassFile[classCount];
+
+ boolean foundReferencedClassFiles = false;
+
+ for (int index = 0; index < classCount; index++)
+ {
+ String name = enumeration.nextClassName();
+
+ ClassFile referencedClassFile = findClass(name);
+
+ if (referencedClassFile != null)
+ {
+ referencedClassFiles[index] = referencedClassFile;
+ foundReferencedClassFiles = true;
+ }
+ }
+
+ if (foundReferencedClassFiles)
+ {
+ return referencedClassFiles;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Returns the class with the given name, either for the program class pool
+ * or from the library class pool, or <code>null</code> if it can't be found.
+ */
+ private ClassFile findClass(String name)
+ {
+ // First look for the class in the program class pool.
+ ClassFile classFile = programClassPool.getClass(name);
+
+ // Otherwise look for the class in the library class pool.
+ if (classFile == null)
+ {
+ classFile = libraryClassPool.getClass(name);
+ }
+
+ return classFile;
+ }
+}
diff --git a/src/proguard/classfile/util/ClassForNameChecker.java b/src/proguard/classfile/util/ClassForNameChecker.java
new file mode 100644
index 0000000..83885b3
--- /dev/null
+++ b/src/proguard/classfile/util/ClassForNameChecker.java
@@ -0,0 +1,225 @@
+/* $Id: ClassForNameChecker.java,v 1.11 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This class can check whether method references point to <code>Class.forName</code>
+ * or <code>.class</code>.
+ *
+ * @author Eric Lafortune
+ */
+class ClassForNameChecker
+implements CpInfoVisitor,
+ MemberInfoVisitor,
+ AttrInfoVisitor,
+ InstructionVisitor
+{
+ // These fields acts as a return variables and status variables for the visitors.
+ private boolean isClassForNameInvocation;
+ private boolean insideDotClassMethod;
+ private boolean firstInstructionOk;
+
+
+ /**
+ * Creates a new ClassForNameChecker.
+ */
+ public ClassForNameChecker()
+ {
+ }
+
+
+ /**
+ * Checks whether the specified method reference points to
+ * <code>Class.forName</code> or <code>.class</code>.
+ * @param classFile the class file in which the method reference
+ * is located.
+ * @param methodrefCpInfoIndex the index of the method reference in the
+ * constant pool.
+ * @return a boolean that indicates whether the reference points to either
+ * method.
+ */
+ public boolean check(ClassFile classFile, int methodrefCpInfoIndex)
+ {
+ isClassForNameInvocation = false;
+
+ classFile.constantPoolEntryAccept(methodrefCpInfoIndex, this);
+
+ return isClassForNameInvocation;
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+ /**
+ * Checks whether the given method reference points to
+ * <code>Class.forName</code> or <code>.class</code>.
+ */
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ String className = methodrefCpInfo.getClassName(classFile);
+ String methodName = methodrefCpInfo.getName(classFile);
+ String methodType = methodrefCpInfo.getType(classFile);
+
+ // Is it a reference to "Class Class.forName(String)"?
+ isClassForNameInvocation =
+ className .equals(ClassConstants.INTERNAL_CLASS_NAME_JAVA_LANG_CLASS) &&
+ methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_CLASS_FOR_NAME) &&
+ methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_FOR_NAME);
+
+ if (isClassForNameInvocation || insideDotClassMethod)
+ {
+ return;
+ }
+
+ // Is it a reference to .class? This construct is typically implemented
+ // as (static) "Class class$(String)" or "Class class$(String, boolean)".
+ // First check the type, which has to be right to start with.
+ isClassForNameInvocation =
+ methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JAVAC) ||
+ methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_DOT_CLASS_JIKES);
+
+ if (!isClassForNameInvocation)
+ {
+ return;
+ }
+
+ // Then check if the method perhaps still has its original "class$" name.
+ isClassForNameInvocation =
+ methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_DOT_CLASS);
+
+ if (isClassForNameInvocation)
+ {
+ return;
+ }
+
+ // We're still not sure it's not a reference to .class, since the
+ // method name may have been changed or obfuscated.
+ // Perform a more detailed analysis by looking at the referenced method
+ // itself. Make sure we don't do this recursively.
+ insideDotClassMethod = true;
+ methodrefCpInfo.referencedMemberInfoAccept(this);
+ insideDotClassMethod = false;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+ /**
+ * Checks whether the given method is a .class implementation.
+ */
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ programMethodInfo.attributesAccept(programClassFile, this);
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ /**
+ * Checks whether the given code is an implementation of class$(String) or
+ * class$(String, boolean).
+ */
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ // Check whether the first instruction recalls the first argument of
+ // this method.
+ firstInstructionOk = false;
+ codeAttrInfo.instructionAccept(classFile, methodInfo, this, 0);
+
+ // Continue checking whether the second instruction invokes
+ // Class.forName.
+ if (firstInstructionOk)
+ {
+ codeAttrInfo.instructionAccept(classFile, methodInfo, this, 1);
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ /**
+ * Checks whether this is a valid first instruction for a .class implementation.
+ */
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ firstInstructionOk = variableInstruction.opcode == InstructionConstants.OP_ALOAD_0;
+ }
+
+ /**
+ * Checks whether this is a valid second instruction for a .class implementation.
+ */
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ if (firstInstructionOk &&
+ cpInstruction.opcode == InstructionConstants.OP_INVOKESTATIC)
+ {
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+ }
+ }
+}
diff --git a/src/proguard/classfile/util/ClassNewInstanceChecker.java b/src/proguard/classfile/util/ClassNewInstanceChecker.java
new file mode 100644
index 0000000..d1ffe43
--- /dev/null
+++ b/src/proguard/classfile/util/ClassNewInstanceChecker.java
@@ -0,0 +1,97 @@
+/* $Id: ClassNewInstanceChecker.java,v 1.7 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This class can check whether method references point to
+ * <code>Class.newInstance</code>.
+ *
+ * @author Eric Lafortune
+ */
+class ClassNewInstanceChecker
+implements CpInfoVisitor
+{
+ // This field acts as a return variable for the CpInfoVisitor.
+ private boolean isClassNewInstanceInvocation;
+
+
+ /**
+ * Creates a new ClassNewInstanceChecker.
+ */
+ public ClassNewInstanceChecker()
+ {
+ }
+
+
+ /**
+ * Checks whether the specified method reference points to
+ * <code>Class.newInstance</code>.
+ * @param classFile the class file in which the method reference
+ * is located.
+ * @param methodrefCpInfoIndex the index of the method reference in the
+ * constant pool.
+ * @return a boolean that indicates whether the reference points to the
+ * method.
+ */
+ public boolean check(ClassFile classFile, int methodrefCpInfoIndex)
+ {
+ isClassNewInstanceInvocation = false;
+
+ classFile.constantPoolEntryAccept(methodrefCpInfoIndex, this);
+
+ return isClassNewInstanceInvocation;
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+ /**
+ * Checks whether the given method reference points to
+ * <code>Class.newInstance</code>.
+ */
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ String className = methodrefCpInfo.getClassName(classFile);
+ String methodName = methodrefCpInfo.getName(classFile);
+ String methodType = methodrefCpInfo.getType(classFile);
+
+ // Is it a reference to "Object Class.newInstance()"?
+ isClassNewInstanceInvocation =
+ className .equals(ClassConstants.INTERNAL_CLASS_NAME_JAVA_LANG_CLASS) &&
+ methodName.equals(ClassConstants.INTERNAL_METHOD_NAME_NEW_INSTANCE) &&
+ methodType.equals(ClassConstants.INTERNAL_METHOD_TYPE_NEW_INSTANCE);
+ }
+}
diff --git a/src/proguard/classfile/util/ClassUtil.java b/src/proguard/classfile/util/ClassUtil.java
new file mode 100644
index 0000000..2367075
--- /dev/null
+++ b/src/proguard/classfile/util/ClassUtil.java
@@ -0,0 +1,935 @@
+/* $Id: ClassUtil.java,v 1.21 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+
+import java.io.*;
+import java.util.*;
+
+
+/**
+ * Utility methods for converting between internal and external representations
+ * of names and descriptions.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassUtil
+{
+ private static final String EMPTY_STRING = "";
+
+ private static final InternalTypeEnumeration internalTypeEnumeration = new InternalTypeEnumeration();
+ private static final ExternalTypeEnumeration externalTypeEnumeration = new ExternalTypeEnumeration();
+
+
+ /**
+ * Checks whether the given class file magic number is correct.
+ * @param magicNumber the magic number.
+ * @throws IOException when the magic number is incorrect.
+ */
+ public static void checkMagicNumber(int magicNumber) throws IOException
+ {
+ if (magicNumber != ClassConstants.MAGIC)
+ {
+ throw new IOException("Invalid magic number ["+Integer.toHexString(magicNumber)+"] in class file");
+ }
+ }
+
+
+ /**
+ * Checks whether the given class file version numbers are supported.
+ * @param majorVersionNumber the major version number.
+ * @param minorVersionNumber the minor version number.
+ * @throws IOException when the version is not supported.
+ */
+ public static void checkVersionNumbers(int majorVersionNumber, int minorVersionNumber) throws IOException
+ {
+ if (majorVersionNumber < ClassConstants.MAJOR_VERSION_MIN ||
+ (majorVersionNumber == ClassConstants.MAJOR_VERSION_MIN &&
+ minorVersionNumber < ClassConstants.MINOR_VERSION_MIN) ||
+ (majorVersionNumber == ClassConstants.MAJOR_VERSION_MAX &&
+ minorVersionNumber > ClassConstants.MINOR_VERSION_MAX) ||
+ majorVersionNumber > ClassConstants.MAJOR_VERSION_MAX)
+ {
+ throw new IOException("Unsupported version number ["+majorVersionNumber+"."+minorVersionNumber+"] for class file format");
+ }
+ }
+
+
+ /**
+ * Converts an external class name into an internal class name.
+ * @param externalClassName the external class name,
+ * e.g. "<code>java.lang.Object</code>"
+ * @return the internal class name,
+ * e.g. "<code>java/lang/Object</code>".
+ */
+ public static String internalClassName(String externalClassName)
+ {
+ return externalClassName.replace(ClassConstants.EXTERNAL_PACKAGE_SEPARATOR,
+ ClassConstants.INTERNAL_PACKAGE_SEPARATOR);
+ }
+
+
+ /**
+ * Converts an internal class description into an external class description.
+ * @param accessFlags the access flags of the class.
+ * @param internalClassName the internal class name,
+ * e.g. "<code>java/lang/Object</code>".
+ * @return the external class description,
+ * e.g. "<code>public java.lang.Object</code>".
+ */
+ public static String externalFullClassDescription(int accessFlags,
+ String internalClassName)
+ {
+ return externalClassAccessFlags(accessFlags) +
+ externalClassName(internalClassName);
+ }
+
+
+ /**
+ * Converts an internal class name into an external class name.
+ * @param internalClassName the internal class name,
+ * e.g. "<code>java/lang/Object</code>".
+ * @return the external class name,
+ * e.g. "<code>java.lang.Object</code>".
+ */
+ public static String externalClassName(String internalClassName)
+ {
+ return //internalClassName.startsWith(ClassConstants.INTERNAL_PACKAGE_JAVA_LANG) &&
+ //internalClassName.indexOf(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, ClassConstants.INTERNAL_PACKAGE_JAVA_LANG.length() + 1) < 0 ?
+ //internalClassName.substring(ClassConstants.INTERNAL_PACKAGE_JAVA_LANG.length()) :
+ internalClassName.replace(ClassConstants.INTERNAL_PACKAGE_SEPARATOR,
+ ClassConstants.EXTERNAL_PACKAGE_SEPARATOR);
+ }
+
+
+ /**
+ * Converts an internal class name into an external short class name, without
+ * package specification.
+ * @param externalClassName the external class name,
+ * e.g. "<code>java.lang.Object</code>"
+ * @return the external short class name,
+ * e.g. "<code>Object</code>".
+ */
+ public static String externalShortClassName(String externalClassName)
+ {
+ int index = externalClassName.lastIndexOf(ClassConstants.EXTERNAL_PACKAGE_SEPARATOR);
+ return externalClassName.substring(index+1);
+ }
+
+
+ /**
+ * Returns whether the given internal type is an array type.
+ * @param internalType the internal type,
+ * e.g. "<code>[[Ljava/lang/Object;</code>".
+ * @return <code>true</code> if the given type is an array type,
+ * <code>false</code> otherwise.
+ */
+ public static boolean isInternalArrayType(String internalType)
+ {
+ return internalType.length() > 1 &&
+ internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY;
+ }
+
+
+ /**
+ * Returns the number of dimensions of the given internal type.
+ * @param internalType the internal type,
+ * e.g. "<code>[[Ljava/lang/Object;</code>".
+ * @return the number of dimensions, e.g. 2.
+ */
+ public static int internalArrayTypeDimensionCount(String internalType)
+ {
+ int dimensions = 0;
+ while (internalType.charAt(dimensions) == ClassConstants.INTERNAL_TYPE_ARRAY)
+ {
+ dimensions++;
+ }
+
+ return dimensions;
+ }
+
+
+ /**
+ * Returns whether the given internal type is a plain primitive type
+ * (not void).
+ * @param internalType the internal type,
+ * e.g. "<code>I</code>".
+ * @return <code>true</code> if the given type is a class type,
+ * <code>false</code> otherwise.
+ */
+ public static boolean isInternalPrimitiveType(char internalType)
+ {
+ return internalType == ClassConstants.INTERNAL_TYPE_BOOLEAN ||
+ internalType == ClassConstants.INTERNAL_TYPE_BYTE ||
+ internalType == ClassConstants.INTERNAL_TYPE_CHAR ||
+ internalType == ClassConstants.INTERNAL_TYPE_SHORT ||
+ internalType == ClassConstants.INTERNAL_TYPE_INT ||
+ internalType == ClassConstants.INTERNAL_TYPE_FLOAT ||
+ internalType == ClassConstants.INTERNAL_TYPE_LONG ||
+ internalType == ClassConstants.INTERNAL_TYPE_DOUBLE;
+ }
+
+
+ /**
+ * Returns whether the given internal type is a plain class type
+ * (not an array type).
+ * @param internalType the internal type,
+ * e.g. "<code>Ljava/lang/Object;</code>".
+ * @return <code>true</code> if the given type is a class type,
+ * <code>false</code> otherwise.
+ */
+ public static boolean isInternalClassType(String internalType)
+ {
+ int length = internalType.length();
+ return length > 1 &&
+ internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_CLASS_START &&
+ internalType.charAt(length-1) == ClassConstants.INTERNAL_TYPE_CLASS_END;
+ }
+
+
+ /**
+ * Returns the internal element type of a given internal array type.
+ * @param internalArrayType the internal array type,
+ * e.g. "<code>[[Ljava/lang/Object;</code>" or
+ * "<code>[I</code>".
+ * @return the internal type of the array elements,
+ * e.g. "<code>Ljava/lang/Object;</code>" or
+ * "<code>I</code>".
+ */
+ public static String internalTypeFromArrayType(String internalArrayType)
+ {
+ int index = internalArrayType.lastIndexOf(ClassConstants.INTERNAL_TYPE_ARRAY);
+ return internalArrayType.substring(index+1);
+ }
+
+
+ /**
+ * Returns the internal class name of a given internal class type.
+ * @param internalClassType the internal class type,
+ * e.g. "<code>Ljava/lang/Object;</code>".
+ * @return the internal class name,
+ * e.g. "<code>java/lang/Object</code>".
+ */
+ public static String internalClassNameFromClassType(String internalClassType)
+ {
+ return internalClassType.substring(1, internalClassType.length()-1);
+ }
+
+
+ /**
+ * Returns the internal class name of any given internal type.
+ * The returned class name for primitive array types is
+ * "<code>java/lang/Object</code>".
+ * @param internalClassType the internal class type,
+ * e.g. "<code>Ljava/lang/Object;</code>" or
+ * "<code>[[I</code>".
+ * @return the internal class name,
+ * e.g. "<code>java/lang/Object</code>".
+ */
+ public static String internalClassNameFromType(String internalClassType)
+ {
+ // Is it an array type?
+ if (isInternalArrayType(internalClassType))
+ {
+ internalClassType = internalTypeFromArrayType(internalClassType);
+
+ // Is the array of a non-primitive type?
+ if (isInternalClassType(internalClassType))
+ {
+ internalClassType = internalClassNameFromClassType(internalClassType);
+ }
+ else
+ {
+ internalClassType = ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT;
+ }
+ }
+
+ return internalClassType;
+ }
+
+
+ /**
+ * Returns the internal type of the given internal method descriptor.
+ * @param internalMethodDescriptor the internal method descriptor,
+ * e.g. "<code>(II)Z</code>".
+ * @return the internal return type,
+ * e.g. "<code>Z</code>".
+ */
+ public static String internalMethodReturnType(String internalMethodDescriptor)
+ {
+ int index = internalMethodDescriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
+ return internalMethodDescriptor.substring(index + 1);
+ }
+
+
+ /**
+ * Returns the number of parameters of the given internal method descriptor.
+ * @param internalMethodDescriptor the internal method descriptor,
+ * e.g. "<code>(ID)Z</code>".
+ * @return the number of parameters,
+ * e.g. 2.
+ */
+ public static int internalMethodParameterCount(String internalMethodDescriptor)
+ {
+ internalTypeEnumeration.setDescriptor(internalMethodDescriptor);
+
+ int counter = 0;
+ while (internalTypeEnumeration.hasMoreTypes())
+ {
+ internalTypeEnumeration.nextType();
+
+ counter++;
+ }
+
+ return counter;
+ }
+
+
+ /**
+ * Returns the size taken up on the stack by the parameters of the given
+ * internal method descriptor. This accounts for long and double parameters
+ * taking up two spaces.
+ * @param internalMethodDescriptor the internal method descriptor,
+ * e.g. "<code>(ID)Z</code>".
+ * @return the size taken up on the stack,
+ * e.g. 3.
+ */
+ public static int internalMethodParameterSize(String internalMethodDescriptor)
+ {
+ internalTypeEnumeration.setDescriptor(internalMethodDescriptor);
+
+ int size = 0;
+ while (internalTypeEnumeration.hasMoreTypes())
+ {
+ String internalType = internalTypeEnumeration.nextType();
+
+ size += internalTypeSize(internalType);
+ }
+
+ return size;
+ }
+
+
+ /**
+ * Returns the size taken up on the stack by the given internal type.
+ * The size is 1, except for long and double types, for which it is 2,
+ * and for the void type, for which 0 is returned
+ * @param internalType the internal type,
+ * e.g. "<code>I</code>".
+ * @return the size taken up on the stack,
+ * e.g. 1.
+ */
+ public static int internalTypeSize(String internalType)
+ {
+ if (internalType.length() == 1)
+ {
+ char internalPrimitiveType = internalType.charAt(0);
+ if (internalPrimitiveType == ClassConstants.INTERNAL_TYPE_LONG ||
+ internalPrimitiveType == ClassConstants.INTERNAL_TYPE_DOUBLE)
+ {
+ return 2;
+ }
+ else if (internalPrimitiveType == ClassConstants.INTERNAL_TYPE_VOID)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+
+
+ /**
+ * Converts an external type into an internal type.
+ * @param externalType the external type,
+ * e.g. "<code>java.lang.Object[][]</code>" or
+ * "<code>int[]</code>".
+ * @return the internal type,
+ * e.g. "<code>[[Ljava/lang/Object;</code>" or
+ * "<code>[I</code>".
+ */
+ public static String internalType(String externalType)
+ {
+ // Strip the array part, if any.
+ int dimensionCount = externalArrayTypeDimensionCount(externalType);
+ if (dimensionCount > 0)
+ {
+ externalType = externalType.substring(0, externalType.length() - dimensionCount * ClassConstants.EXTERNAL_TYPE_ARRAY.length());
+ }
+
+ // Analyze the actual type part.
+ char internalTypeChar =
+ externalType.equals(ClassConstants.EXTERNAL_TYPE_VOID ) ?
+ ClassConstants.INTERNAL_TYPE_VOID :
+ externalType.equals(ClassConstants.EXTERNAL_TYPE_BOOLEAN) ?
+ ClassConstants.INTERNAL_TYPE_BOOLEAN :
+ externalType.equals(ClassConstants.EXTERNAL_TYPE_BYTE ) ?
+ ClassConstants.INTERNAL_TYPE_BYTE :
+ externalType.equals(ClassConstants.EXTERNAL_TYPE_CHAR ) ?
+ ClassConstants.INTERNAL_TYPE_CHAR :
+ externalType.equals(ClassConstants.EXTERNAL_TYPE_SHORT ) ?
+ ClassConstants.INTERNAL_TYPE_SHORT :
+ externalType.equals(ClassConstants.EXTERNAL_TYPE_INT ) ?
+ ClassConstants.INTERNAL_TYPE_INT :
+ externalType.equals(ClassConstants.EXTERNAL_TYPE_FLOAT ) ?
+ ClassConstants.INTERNAL_TYPE_FLOAT :
+ externalType.equals(ClassConstants.EXTERNAL_TYPE_LONG ) ?
+ ClassConstants.INTERNAL_TYPE_LONG :
+ externalType.equals(ClassConstants.EXTERNAL_TYPE_DOUBLE ) ?
+ ClassConstants.INTERNAL_TYPE_DOUBLE :
+ externalType.equals("%" ) ?
+ '%' :
+ (char)0;
+
+ String internalType =
+ internalTypeChar != 0 ? ("" + internalTypeChar) :
+ (ClassConstants.INTERNAL_TYPE_CLASS_START +
+ internalClassName(externalType) +
+ ClassConstants.INTERNAL_TYPE_CLASS_END);
+
+ // Prepend the array part, if any.
+ for (int count = 0; count < dimensionCount; count++)
+ {
+ internalType = ClassConstants.INTERNAL_TYPE_ARRAY + internalType;
+ }
+
+ return internalType;
+ }
+
+
+ /**
+ * Returns the number of dimensions of the given external type.
+ * @param externalType the external type,
+ * e.g. "<code>[[Ljava/lang/Object;</code>".
+ * @return the number of dimensions, e.g. 2.
+ */
+ public static int externalArrayTypeDimensionCount(String externalType)
+ {
+ int dimensions = 0;
+ int length = ClassConstants.EXTERNAL_TYPE_ARRAY.length();
+ int offset = externalType.length() - length;
+ while (externalType.regionMatches(offset,
+ ClassConstants.EXTERNAL_TYPE_ARRAY,
+ 0,
+ length))
+ {
+ dimensions++;
+ offset -= length;
+ }
+
+ return dimensions;
+ }
+
+
+ /**
+ * Converts an internal type into an external type.
+ * @param internalType the internal type,
+ * e.g. "<code>[[Ljava/lang/Object;</code>" or
+ * "<code>[I</code>".
+ * @return the external type,
+ * e.g. "<code>java.lang.Object[][]</code>" or
+ * "<code>int[]</code>".
+ */
+ public static String externalType(String internalType)
+ {
+ // Strip the array part, if any.
+ int dimensionCount = internalArrayTypeDimensionCount(internalType);
+ if (dimensionCount > 0)
+ {
+ internalType = internalType.substring(dimensionCount);
+ }
+
+ // Analyze the actual type part.
+ char internalTypeChar = internalType.charAt(0);
+
+ String externalType =
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_VOID ?
+ ClassConstants.EXTERNAL_TYPE_VOID :
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_BOOLEAN ?
+ ClassConstants.EXTERNAL_TYPE_BOOLEAN :
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_BYTE ?
+ ClassConstants.EXTERNAL_TYPE_BYTE :
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_CHAR ?
+ ClassConstants.EXTERNAL_TYPE_CHAR :
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_SHORT ?
+ ClassConstants.EXTERNAL_TYPE_SHORT :
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_INT ?
+ ClassConstants.EXTERNAL_TYPE_INT :
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_FLOAT ?
+ ClassConstants.EXTERNAL_TYPE_FLOAT :
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_LONG ?
+ ClassConstants.EXTERNAL_TYPE_LONG :
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_DOUBLE ?
+ ClassConstants.EXTERNAL_TYPE_DOUBLE :
+ internalTypeChar == ClassConstants.INTERNAL_TYPE_CLASS_START ?
+ externalClassName(internalType.substring(1, internalType.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_END))) :
+ null;
+
+ if (externalType == null)
+ {
+ throw new IllegalArgumentException("Unknown type ["+internalType+"]");
+ }
+
+ // Append the array part, if any.
+ for (int count = 0; count < dimensionCount; count++)
+ {
+ externalType = externalType + ClassConstants.EXTERNAL_TYPE_ARRAY;
+ }
+
+ return externalType;
+ }
+
+
+ /**
+ * Returns whether the given internal descriptor String represents a method
+ * descriptor.
+ * @param internalDescriptor the internal descriptor String,
+ * e.g. "<code>(II)Z</code>".
+ * @return <code>true</code> if the given String is a method descriptor,
+ * <code>false</code> otherwise.
+ */
+ public static boolean isInternalMethodDescriptor(String internalDescriptor)
+ {
+ return internalDescriptor.charAt(0) == ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN;
+ }
+
+
+ /**
+ * Returns whether the given member String represents an external method
+ * name with arguments.
+ * @param externalMemberNameAndArguments the external member String,
+ * e.g. "<code>myField</code>" or
+ * e.g. "<code>myMethod(int,int)</code>".
+ * @return <code>true</code> if the given String refers to a method,
+ * <code>false</code> otherwise.
+ */
+ public static boolean isExternalMethodNameAndArguments(String externalMemberNameAndArguments)
+ {
+ return externalMemberNameAndArguments.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN) > 0;
+ }
+
+
+ /**
+ * Returns the name part of the given external method name and arguments.
+ * @param externalMethodNameAndArguments the external method name and arguments,
+ * e.g. "<code>myMethod(int,int)</code>".
+ * @return the name part of the String, e.g. "<code>myMethod</code>".
+ */
+ public static String externalMethodName(String externalMethodNameAndArguments)
+ {
+ externalTypeEnumeration.setDescriptor(externalMethodNameAndArguments);
+ return externalTypeEnumeration.methodName();
+ }
+
+
+ /**
+ * Converts the given external method return type and name and arguments to
+ * an internal method descriptor.
+ * @param externalReturnType the external method return type,
+ * e.g. "<code>boolean</code>".
+ * @param externalMethodNameAndArguments the external method name and arguments,
+ * e.g. "<code>myMethod(int,int)</code>".
+ * @return the internal method descriptor,
+ * e.g. "<code>(II)Z</code>".
+ */
+ public static String internalMethodDescriptor(String externalReturnType,
+ String externalMethodNameAndArguments)
+ {
+ StringBuffer internalMethodDescriptor = new StringBuffer();
+ internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN);
+
+ externalTypeEnumeration.setDescriptor(externalMethodNameAndArguments);
+ while (externalTypeEnumeration.hasMoreTypes())
+ {
+ internalMethodDescriptor.append(internalType(externalTypeEnumeration.nextType()));
+ }
+
+ internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
+ internalMethodDescriptor.append(internalType(externalReturnType));
+
+ return internalMethodDescriptor.toString();
+ }
+
+
+ /**
+ * Converts the given external method return type and List of arguments to
+ * an internal method descriptor.
+ * @param externalReturnType the external method return type,
+ * e.g. "<code>boolean</code>".
+ * @param externalArguments the external method arguments,
+ * e.g. <code>{ "int", "int" }</code>.
+ * @return the internal method descriptor,
+ * e.g. "<code>(II)Z</code>".
+ */
+ public static String internalMethodDescriptor(String externalReturnType,
+ List externalArguments)
+ {
+ StringBuffer internalMethodDescriptor = new StringBuffer();
+ internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN);
+
+ for (int index = 0; index < externalArguments.size(); index++)
+ {
+ internalMethodDescriptor.append(internalType((String)externalArguments.get(index)));
+ }
+
+ internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
+ internalMethodDescriptor.append(internalType(externalReturnType));
+
+ return internalMethodDescriptor.toString();
+ }
+
+
+ /**
+ * Converts an internal field description into an external full field description.
+ * @param accessFlags the access flags of the field.
+ * @param fieldName the field name,
+ * e.g. "<code>myField</code>".
+ * @param internalFieldDescriptor the internal field descriptor,
+ * e.g. "<code>Z</code>".
+ * @return the external full field description,
+ * e.g. "<code>public boolean myField</code>".
+ */
+ public static String externalFullFieldDescription(int accessFlags,
+ String fieldName,
+ String internalFieldDescriptor)
+ {
+ return externalFieldAccessFlags(accessFlags) +
+ externalType(internalFieldDescriptor) +
+ " " +
+ fieldName;
+ }
+
+
+ /**
+ * Converts an internal method description into an external full method description.
+ * @param internalClassName the internal name of the class of the method,
+ * e.g. "<code>mypackage/MyClass</code>".
+ * @param accessFlags the access flags of the method.
+ * @param internalMethodName the internal method name,
+ * e.g. "<code>myMethod</code>" or
+ * "<code><init></code>".
+ * @param internalMethodDescriptor the internal method descriptor,
+ * e.g. "<code>(II)Z</code>".
+ * @return the external full method description,
+ * e.g. "<code>public boolean myMethod(int,int)</code>" or
+ * "<code>public MyClass(int,int)</code>".
+ */
+ public static String externalFullMethodDescription(String internalClassName,
+ int accessFlags,
+ String internalMethodName,
+ String internalMethodDescriptor)
+ {
+ return externalMethodAccessFlags(accessFlags) +
+ externalMethodReturnTypeAndName(internalClassName,
+ internalMethodName,
+ internalMethodDescriptor) +
+ ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN +
+ externalMethodArguments(internalMethodDescriptor) +
+ ClassConstants.EXTERNAL_METHOD_ARGUMENTS_CLOSE;
+ }
+
+
+ /**
+ * Converts internal class access flags into an external access description.
+ * @param accessFlags the class access flags.
+ * @return the external class access description,
+ * e.g. "<code>public final </code>".
+ */
+ public static String externalClassAccessFlags(int accessFlags)
+ {
+ return externalClassAccessFlags(accessFlags, "");
+ }
+
+
+ /**
+ * Converts internal class access flags into an external access description.
+ * @param accessFlags the class access flags.
+ * @param prefix a prefix that is added to each access modifier.
+ * @return the external class access description,
+ * e.g. "<code>public final </code>".
+ */
+ public static String externalClassAccessFlags(int accessFlags, String prefix)
+ {
+ if (accessFlags == 0)
+ {
+ return EMPTY_STRING;
+ }
+
+ StringBuffer string = new StringBuffer(50);
+
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_INTERFACE) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_INTERFACE).append(" ");
+ }
+ else
+ {
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ABSTRACT).append(" ");
+ }
+ }
+
+ return string.toString();
+ }
+
+
+ /**
+ * Converts internal field access flags into an external access description.
+ * @param accessFlags the field access flags.
+ * @return the external field access description,
+ * e.g. "<code>public volatile </code>".
+ */
+ public static String externalFieldAccessFlags(int accessFlags)
+ {
+ return externalFieldAccessFlags(accessFlags, "");
+ }
+
+
+ /**
+ * Converts internal field access flags into an external access description.
+ * @param accessFlags the field access flags.
+ * @param prefix a prefix that is added to each access modifier.
+ * @return the external field access description,
+ * e.g. "<code>public volatile </code>".
+ */
+ public static String externalFieldAccessFlags(int accessFlags, String prefix)
+ {
+ if (accessFlags == 0)
+ {
+ return EMPTY_STRING;
+ }
+
+ StringBuffer string = new StringBuffer(50);
+
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PRIVATE).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PROTECTED).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STATIC).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_VOLATILE) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_VOLATILE).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_TRANSIENT) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_TRANSIENT).append(" ");
+ }
+
+ return string.toString();
+ }
+
+
+ /**
+ * Converts internal method access flags into an external access description.
+ * @param accessFlags the method access flags.
+ * @return the external method access description,
+ * e.g. "<code>public synchronized </code>".
+ */
+ public static String externalMethodAccessFlags(int accessFlags)
+ {
+ return externalMethodAccessFlags(accessFlags, "");
+ }
+
+
+ /**
+ * Converts internal method access flags into an external access description.
+ * @param accessFlags the method access flags.
+ * @param prefix a prefix that is added to each access modifier.
+ * @return the external method access description,
+ * e.g. "public synchronized ".
+ */
+ public static String externalMethodAccessFlags(int accessFlags, String prefix)
+ {
+ if (accessFlags == 0)
+ {
+ return EMPTY_STRING;
+ }
+
+ StringBuffer string = new StringBuffer(50);
+
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PRIVATE).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PROTECTED).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STATIC).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNCHRONIZED) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_NATIVE) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_NATIVE).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ABSTRACT).append(" ");
+ }
+ if ((accessFlags & ClassConstants.INTERNAL_ACC_STRICT) != 0)
+ {
+ string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STRICT).append(" ");
+ }
+
+ return string.toString();
+ }
+
+
+ /**
+ * Converts an internal method descriptor into an external method return type.
+ * @param internalMethodDescriptor the internal method descriptor,
+ * e.g. "<code>(II)Z</code>".
+ * @return the external method return type,
+ * e.g. "<code>boolean</code>".
+ */
+ public static String externalMethodReturnType(String internalMethodDescriptor)
+ {
+ return externalType(internalMethodReturnType(internalMethodDescriptor));
+ }
+
+
+ /**
+ * Converts an internal class name, method name, and method descriptor to
+ * an external method return type and name.
+ * @param internalClassName the internal name of the class of the method,
+ * e.g. "<code>mypackage/MyClass</code>".
+ * @param internalMethodName the internal method name,
+ * e.g. "<code>myMethod</code>" or
+ * "<code><init></code>".
+ * @param internalMethodDescriptor the internal method descriptor,
+ * e.g. "<code>(II)Z</code>".
+ * @return the external method return type and name,
+ * e.g. "<code>boolean myMethod</code>" or
+ * "<code>MyClass</code>".
+ */
+ private static String externalMethodReturnTypeAndName(String internalClassName,
+ String internalMethodName,
+ String internalMethodDescriptor)
+ {
+ return internalMethodName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ?
+ (ClassUtil.externalShortClassName(
+ ClassUtil.externalClassName(internalClassName))) :
+ (ClassUtil.externalMethodReturnType(internalMethodDescriptor) +
+ " " +
+ internalMethodName);
+ }
+
+
+ /**
+ * Converts an internal method descriptor into an external method argument
+ * description.
+ * @param internalMethodDescriptor the internal method descriptor,
+ * e.g. "<code>(II)Z</code>".
+ * @return the external method argument description,
+ * e.g. "<code>int,int</code>".
+ */
+ public static String externalMethodArguments(String internalMethodDescriptor)
+ {
+ StringBuffer externalMethodNameAndArguments = new StringBuffer();
+
+ internalTypeEnumeration.setDescriptor(internalMethodDescriptor);
+ while (internalTypeEnumeration.hasMoreTypes())
+ {
+ externalMethodNameAndArguments.append(externalType(internalTypeEnumeration.nextType()));
+ if (internalTypeEnumeration.hasMoreTypes())
+ {
+ externalMethodNameAndArguments.append(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_SEPARATOR);
+ }
+ }
+
+ return externalMethodNameAndArguments.toString();
+ }
+
+
+ /**
+ * Returns the internal package name of the given internal class name.
+ * @param internalClassName the internal class name,
+ * e.g. "<code>java/lang/Object</code>".
+ * @return the internal package name,
+ * e.g. "<code>java/lang</code>".
+ */
+ public static String internalPackageName(String internalClassName)
+ {
+ int lastSeparatorIndex = internalClassName.lastIndexOf(ClassConstants.INTERNAL_PACKAGE_SEPARATOR);
+ if (lastSeparatorIndex < 0)
+ {
+ lastSeparatorIndex = 0;
+ }
+
+ return internalClassName.substring(0, lastSeparatorIndex);
+ }
+
+
+ /**
+ * Returns the external package name of the given external class name.
+ * @param externalClassName the external class name,
+ * e.g. "<code>java.lang.Object</code>".
+ * @return the external package name,
+ * e.g. "<code>java.lang</code>".
+ */
+ public static String externalPackageName(String externalClassName)
+ {
+ int lastSeparatorIndex = externalClassName.lastIndexOf(ClassConstants.EXTERNAL_PACKAGE_SEPARATOR);
+ if (lastSeparatorIndex < 0)
+ {
+ lastSeparatorIndex = 0;
+ }
+
+ return externalClassName.substring(0, lastSeparatorIndex);
+ }
+}
diff --git a/src/proguard/classfile/util/DescriptorClassEnumeration.java b/src/proguard/classfile/util/DescriptorClassEnumeration.java
new file mode 100644
index 0000000..b0055fd
--- /dev/null
+++ b/src/proguard/classfile/util/DescriptorClassEnumeration.java
@@ -0,0 +1,165 @@
+/* $Id: DescriptorClassEnumeration.java,v 1.10 2004/11/26 22:53:15 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+
+/**
+ * A <code>DescriptorClassEnumeration</code> provides an enumeration of all
+ * classes mentioned in a given descriptor string.
+ * <p>
+ * A <code>DescriptorClassEnumeration</code> object can be reused for processing
+ * different subsequent descriptors, by means of the <code>setDescriptor</code>
+ * method.
+ *
+ * @author Eric Lafortune
+ */
+public class DescriptorClassEnumeration
+{
+ private String descriptor;
+ private int index;
+
+
+ public DescriptorClassEnumeration(String descriptor)
+ {
+ setDescriptor(descriptor);
+ }
+
+
+ DescriptorClassEnumeration()
+ {
+ }
+
+
+ void setDescriptor(String descriptor)
+ {
+ this.descriptor = descriptor;
+
+ reset();
+ }
+
+
+ public void reset()
+ {
+ index = 0;
+ }
+
+
+ /**
+ * Returns the number of classes contained in the descriptor. This
+ * is the number of class names that the enumeration will return.
+ */
+ public int classCount()
+ {
+ int count = 0;
+
+ while (nextClassNameStartIndex() >= 0)
+ {
+ count++;
+
+ nextClassNameEndIndex();
+ }
+
+ index = 0;
+
+ return count;
+ }
+
+
+ public boolean hasMoreClassNames()
+ {
+ return index >= 0 && nextClassNameStartIndex() >= 0;
+ }
+
+
+ public String nextFluff()
+ {
+ int fluffStartIndex = index;
+ int fluffEndIndex = nextClassNameStartIndex() + 1;
+
+ // There may be fluff at the end of the descriptor.
+ if (fluffEndIndex == 0)
+ {
+ fluffEndIndex = descriptor.length();
+ }
+
+ return descriptor.substring(fluffStartIndex, fluffEndIndex);
+ }
+
+
+ public String nextClassName()
+ {
+ int classNameStartIndex = nextClassNameStartIndex() + 1;
+ int classNameEndIndex = nextClassNameEndIndex();
+
+ return descriptor.substring(classNameStartIndex, classNameEndIndex);
+ }
+
+
+ private int nextClassNameStartIndex()
+ {
+ index = descriptor.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START, index);
+
+ return index;
+ }
+
+
+ private int nextClassNameEndIndex()
+ {
+ while (++index < descriptor.length())
+ {
+ char c = descriptor.charAt(index);
+ if (c == ClassConstants.INTERNAL_TYPE_CLASS_END ||
+ c == ClassConstants.INTERNAL_TYPE_GENERIC_START)
+ {
+ return index;
+ }
+ }
+
+ throw new IllegalArgumentException("Missing class name terminator in descriptor ["+descriptor+"]");
+ }
+
+
+
+
+ /**
+ * A main method for testing the class name enumeration.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ System.out.println("Descriptor ["+args[0]+"]");
+ DescriptorClassEnumeration enumeration = new DescriptorClassEnumeration(args[0]);
+ System.out.println("Class count = "+enumeration.classCount());
+ System.out.println(" Fluff: ["+enumeration.nextFluff()+"]");
+ while (enumeration.hasMoreClassNames())
+ {
+ System.out.println(" Name: ["+enumeration.nextClassName()+"]");
+ System.out.println(" Fluff: ["+enumeration.nextFluff()+"]");
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/classfile/util/ExternalTypeEnumeration.java b/src/proguard/classfile/util/ExternalTypeEnumeration.java
new file mode 100644
index 0000000..c1648db
--- /dev/null
+++ b/src/proguard/classfile/util/ExternalTypeEnumeration.java
@@ -0,0 +1,106 @@
+/* $Id: ExternalTypeEnumeration.java,v 1.9 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+
+
+/**
+ * An <code>ExternalTypeEnumeration</code> provides an enumeration of all
+ * types listed in a given external descriptor string. The method name can
+ * be retrieved separately.
+ * <p>
+ * A <code>ExternalTypeEnumeration</code> object can be reused for processing
+ * different subsequent descriptors, by means of the <code>setDescriptor</code>
+ * method.
+ *
+ * @author Eric Lafortune
+ */
+public class ExternalTypeEnumeration
+{
+ private String descriptor;
+ private int index;
+
+
+ public ExternalTypeEnumeration(String descriptor)
+ {
+ setDescriptor(descriptor);
+ }
+
+
+ ExternalTypeEnumeration()
+ {
+ }
+
+
+ void setDescriptor(String descriptor)
+ {
+ this.descriptor = descriptor;
+
+ reset();
+ }
+
+
+ public void reset()
+ {
+ index = descriptor.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN) + 1;
+
+ if (index < 1)
+ {
+ throw new IllegalArgumentException("Missing opening parenthesis in descriptor ["+descriptor+"]");
+ }
+ }
+
+
+ public boolean hasMoreTypes()
+ {
+ return index < descriptor.length() - 1;
+ }
+
+
+ public String nextType()
+ {
+ int startIndex = index;
+
+ // Find the next separating comma.
+ index = descriptor.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_SEPARATOR,
+ startIndex);
+
+ // Otherwise find the closing parenthesis.
+ if (index < 0)
+ {
+ index = descriptor.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_CLOSE,
+ startIndex);
+ if (index < 0)
+ {
+ throw new IllegalArgumentException("Missing closing parenthesis in descriptor ["+descriptor+"]");
+ }
+ }
+
+ return descriptor.substring(startIndex, index++).trim();
+ }
+
+
+ public String methodName()
+ {
+ return descriptor.substring(0, descriptor.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN)).trim();
+ }
+}
diff --git a/src/proguard/classfile/util/InternalTypeEnumeration.java b/src/proguard/classfile/util/InternalTypeEnumeration.java
new file mode 100644
index 0000000..f60b5b6
--- /dev/null
+++ b/src/proguard/classfile/util/InternalTypeEnumeration.java
@@ -0,0 +1,108 @@
+/* $Id: InternalTypeEnumeration.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+
+
+/**
+ * An <code>InternalTypeEnumeration</code> provides an enumeration of all
+ * types listed in a given internal descriptor string. The return type can
+ * retrieved separately.
+ * <p>
+ * A <code>InternalTypeEnumeration</code> object can be reused for processing
+ * different subsequent descriptors, by means of the <code>setDescriptor</code>
+ * method.
+ *
+ * @author Eric Lafortune
+ */
+public class InternalTypeEnumeration
+{
+ private String descriptor;
+ private int index;
+
+
+ public InternalTypeEnumeration(String descriptor)
+ {
+ setDescriptor(descriptor);
+ }
+
+
+ public InternalTypeEnumeration()
+ {
+ }
+
+
+ void setDescriptor(String descriptor)
+ {
+ this.descriptor = descriptor;
+
+ reset();
+ }
+
+
+ public void reset()
+ {
+ index = descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN) + 1;
+
+ if (index < 1)
+ {
+ throw new IllegalArgumentException("Missing opening parenthesis in descriptor ["+descriptor+"]");
+ }
+ }
+
+
+ public boolean hasMoreTypes()
+ {
+ return descriptor.charAt(index) != ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE;
+ }
+
+
+ public String nextType()
+ {
+ int startIndex = index;
+
+ // Include all leading array characters.
+ while (descriptor.charAt(index) == ClassConstants.INTERNAL_TYPE_ARRAY)
+ {
+ index++;
+ }
+
+ // Class types consist of an entire string.
+ if (descriptor.charAt(index) == ClassConstants.INTERNAL_TYPE_CLASS_START)
+ {
+ index = descriptor.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_END,
+ index + 1);
+ if (index < 0)
+ {
+ throw new IllegalArgumentException("Missing closing class type in descriptor ["+descriptor+"]");
+ }
+ }
+
+ return descriptor.substring(startIndex, ++index);
+ }
+
+
+ public String returnType()
+ {
+ return descriptor.substring(descriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE) + 1);
+ }
+}
diff --git a/src/proguard/classfile/util/MemberFinder.java b/src/proguard/classfile/util/MemberFinder.java
new file mode 100644
index 0000000..27b6451
--- /dev/null
+++ b/src/proguard/classfile/util/MemberFinder.java
@@ -0,0 +1,236 @@
+/* $Id: MemberFinder.java,v 1.4 2004/12/18 20:22:42 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.util;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This class provides methods to find class members in a given class or in its
+ * hierarchy.
+ *
+ * @author Eric Lafortune
+ */
+public class MemberFinder
+ implements MemberInfoVisitor
+{
+ private static class MemberFoundException extends IllegalArgumentException {};
+ private static final MemberFoundException MEMBER_FOUND = new MemberFoundException();
+
+ private ClassFile classFile;
+ private MemberInfo memberInfo;
+
+
+ /**
+ * Finds the field with the given name and descriptor in the given
+ * class file or its hierarchy.
+ */
+ public FieldInfo findField(ClassFile classFile, String name, String descriptor)
+ {
+ return (FieldInfo)findMember(classFile, name, descriptor, true);
+ }
+
+
+ /**
+ * Finds the method with the given name and descriptor in the given
+ * class file or its hierarchy.
+ */
+ public MethodInfo findMethod(ClassFile classFile, String name, String descriptor)
+ {
+ return (MethodInfo)findMember(classFile, name, descriptor, false);
+ }
+
+
+ /**
+ * Finds the class member with the given name and descriptor in the given
+ * class file or its hierarchy.
+ */
+ public MemberInfo findMember(ClassFile classFile,
+ String name,
+ String descriptor,
+ boolean isField)
+ {
+ // For efficiency, first see if we can find the method in the
+ // referenced class itself.
+ this.classFile = classFile;
+ this.memberInfo = isField ?
+ (MemberInfo)classFile.findField(name, descriptor) :
+ (MemberInfo)classFile.findMethod(name, descriptor);
+
+ if (memberInfo == null)
+ {
+ // We didn't find the method yet. Organize a search in the hierarchy
+ // of superclasses and interfaces. This can happen with classes
+ // compiled with "-target 1.2" or higher (the default in JDK 1.4).
+ try
+ {
+ this.classFile = null;
+ this.memberInfo = null;
+ classFile.hierarchyAccept(false, true, true, false,
+ isField ?
+ (ClassFileVisitor)new NamedFieldVisitor(name, descriptor,
+ new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this)) :
+ (ClassFileVisitor)new NamedMethodVisitor(name, descriptor,
+ new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this)));
+ }
+ catch (MemberFoundException ex)
+ {
+ }
+ }
+
+ return memberInfo;
+ }
+
+
+ /**
+ * Returns the corresponding class file of the most recently found class
+ * member.
+ */
+ public ClassFile correspondingClassFile()
+ {
+ return classFile;
+ }
+
+
+ /**
+ * Returns whether the given method is overridden anywhere down the class
+ * hierarchy.
+ */
+ public boolean isOverriden(ClassFile classFile,
+ MethodInfo methodInfo)
+ {
+ String name = methodInfo.getName(classFile);
+ String descriptor = methodInfo.getDescriptor(classFile);
+
+ // Go looking for the method down the class hierarchy.
+ try
+ {
+ this.classFile = null;
+ this.memberInfo = null;
+ classFile.hierarchyAccept(false, false, false, true,
+ new NamedMethodVisitor(name, descriptor,
+ new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this)));
+ }
+ catch (MemberFoundException ex)
+ {
+ // We've found an overriding method.
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether the given field is shadowed anywhere down the class
+ * hierarchy.
+ */
+ public boolean isShadowed(ClassFile classFile,
+ FieldInfo fieldInfo)
+ {
+ String name = fieldInfo.getName(classFile);
+ String descriptor = fieldInfo.getDescriptor(classFile);
+
+ // Go looking for the method down the class hierarchy.
+ try
+ {
+ this.classFile = null;
+ this.memberInfo = null;
+ classFile.hierarchyAccept(false, false, false, true,
+ new NamedFieldVisitor(name, descriptor,
+ new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this)));
+ }
+ catch (MemberFoundException ex)
+ {
+ // We've found an overriding method.
+ return true;
+ }
+
+ return false;
+ }
+
+
+// // Implementations for ClassFileVisitor.
+//
+// public void visitProgramClassFile(ProgramClassFile programClassFile)
+// {
+// visitClassFile(programClassFile);
+// }
+//
+//
+// public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+// {
+// visitClassFile(libraryClassFile);
+// }
+//
+//
+// private void visitClassFile(ClassFile classFile)
+// {
+// if (memberInfo == null)
+// {
+// memberInfo = isField ?
+// (MemberInfo)classFile.findField(name, descriptor) :
+// (MemberInfo)classFile.findMethod(name, descriptor);
+//
+// if (memberInfo != null)
+// {
+// this.classFile = classFile;
+// }
+// }
+// }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ visitMemberInfo(libraryClassFile, libraryFieldInfo);
+ }
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ visitMemberInfo(libraryClassFile, libraryMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ClassFile classFile, MemberInfo memberInfo)
+ {
+ this.classFile = classFile;
+ this.memberInfo = memberInfo;
+
+ throw MEMBER_FOUND;
+ }
+}
diff --git a/src/proguard/classfile/util/package.html b/src/proguard/classfile/util/package.html
new file mode 100644
index 0000000..b1b881e
--- /dev/null
+++ b/src/proguard/classfile/util/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains utility classes for processing class files.
+</body>
diff --git a/src/proguard/classfile/visitor/AllClassFileVisitor.java b/src/proguard/classfile/visitor/AllClassFileVisitor.java
new file mode 100644
index 0000000..64e28f6
--- /dev/null
+++ b/src/proguard/classfile/visitor/AllClassFileVisitor.java
@@ -0,0 +1,47 @@
+/* $Id: AllClassFileVisitor.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This ClassPoolVisitor lets a given ClassFileVisitor visit all ClassFile
+ * objects of the class pools it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllClassFileVisitor implements ClassPoolVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+
+
+ public AllClassFileVisitor(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ public void visitClassPool(ClassPool classPool)
+ {
+ classPool.classFilesAccept(classFileVisitor);
+ }
+}
diff --git a/src/proguard/classfile/visitor/AllCpInfoVisitor.java b/src/proguard/classfile/visitor/AllCpInfoVisitor.java
new file mode 100644
index 0000000..d23a284
--- /dev/null
+++ b/src/proguard/classfile/visitor/AllCpInfoVisitor.java
@@ -0,0 +1,52 @@
+/* $Id: AllCpInfoVisitor.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This ClassFileVisitor lets a given CpInfoVisitor visit all constant pool
+ * entries of the program class files it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllCpInfoVisitor implements ClassFileVisitor
+{
+ private CpInfoVisitor cpInfoVisitor;
+
+
+ public AllCpInfoVisitor(CpInfoVisitor cpInfoVisitor)
+ {
+ this.cpInfoVisitor = cpInfoVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ programClassFile.constantPoolEntriesAccept(cpInfoVisitor);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+}
diff --git a/src/proguard/classfile/visitor/AllFieldVisitor.java b/src/proguard/classfile/visitor/AllFieldVisitor.java
new file mode 100644
index 0000000..ac23349
--- /dev/null
+++ b/src/proguard/classfile/visitor/AllFieldVisitor.java
@@ -0,0 +1,55 @@
+/* $Id: AllFieldVisitor.java,v 1.12 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This ClassFileVisitor lets a given MemberInfoVisitor visit all FieldMemberInfo
+ * objects of the class files it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllFieldVisitor implements ClassFileVisitor
+{
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ public AllFieldVisitor(MemberInfoVisitor memberInfoVisitor)
+ {
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ programClassFile.fieldsAccept(memberInfoVisitor);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ libraryClassFile.fieldsAccept(memberInfoVisitor);
+ }
+}
diff --git a/src/proguard/classfile/visitor/AllMemberInfoVisitor.java b/src/proguard/classfile/visitor/AllMemberInfoVisitor.java
new file mode 100644
index 0000000..e24d744
--- /dev/null
+++ b/src/proguard/classfile/visitor/AllMemberInfoVisitor.java
@@ -0,0 +1,57 @@
+/* $Id: AllMemberInfoVisitor.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This ClassFileVisitor lets a given MemberInfoVisitor visit all MemberInfo
+ * objects of the class files it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllMemberInfoVisitor implements ClassFileVisitor
+{
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ public AllMemberInfoVisitor(MemberInfoVisitor memberInfoVisitor)
+ {
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ programClassFile.fieldsAccept(memberInfoVisitor);
+ programClassFile.methodsAccept(memberInfoVisitor);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ libraryClassFile.fieldsAccept(memberInfoVisitor);
+ libraryClassFile.methodsAccept(memberInfoVisitor);
+ }
+}
diff --git a/src/proguard/classfile/visitor/AllMethodVisitor.java b/src/proguard/classfile/visitor/AllMethodVisitor.java
new file mode 100644
index 0000000..e259ee4
--- /dev/null
+++ b/src/proguard/classfile/visitor/AllMethodVisitor.java
@@ -0,0 +1,55 @@
+/* $Id: AllMethodVisitor.java,v 1.12 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This ClassFileVisitor lets a given MemberInfoVisitor visit all MethodMemberInfo
+ * objects of the class files it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllMethodVisitor implements ClassFileVisitor
+{
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ public AllMethodVisitor(MemberInfoVisitor memberInfoVisitor)
+ {
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ programClassFile.methodsAccept(memberInfoVisitor);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ libraryClassFile.methodsAccept(memberInfoVisitor);
+ }
+}
diff --git a/src/proguard/classfile/visitor/BottomClassFileFilter.java b/src/proguard/classfile/visitor/BottomClassFileFilter.java
new file mode 100644
index 0000000..2af242a
--- /dev/null
+++ b/src/proguard/classfile/visitor/BottomClassFileFilter.java
@@ -0,0 +1,69 @@
+/* $Id: BottomClassFileFilter.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> delegates its visits to another given
+ * <code>ClassFileVisitor</code>, but only when visiting class files that don't
+ * have any subclasses.
+ *
+ * @author Eric Lafortune
+ */
+public class BottomClassFileFilter implements ClassFileVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+
+
+ /**
+ * Creates a new ProgramClassFileFilter.
+ * @param classFileVisitor the <code>ClassFileVisitor</code> to which visits
+ * will be delegated.
+ */
+ public BottomClassFileFilter(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Is this a bottom class in the class hierarchy?
+ if (programClassFile.subClasses == null)
+ {
+ classFileVisitor.visitProgramClassFile(programClassFile);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ // Is this a bottom class in the class hierarchy?
+ if (libraryClassFile.subClasses == null)
+ {
+ classFileVisitor.visitLibraryClassFile(libraryClassFile);
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/ClassFileAccessFilter.java b/src/proguard/classfile/visitor/ClassFileAccessFilter.java
new file mode 100644
index 0000000..35848c1
--- /dev/null
+++ b/src/proguard/classfile/visitor/ClassFileAccessFilter.java
@@ -0,0 +1,88 @@
+/* $Id: ClassFileAccessFilter.java,v 1.6 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> delegates its visits to another given
+ * <code>ClassFileVisitor</code>, but only when the visited class file
+ * has the proper access flags.
+ *
+ * @see ClassConstants
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileAccessFilter implements ClassFileVisitor
+{
+ private int requiredSetAccessFlags;
+ private int requiredUnsetAccessFlags;
+ private ClassFileVisitor classFileVisitor;
+
+
+ /**
+ * Creates a new ClassFileAccessFilter.
+ * @param requiredSetAccessFlags the class access flags that should be
+ * set.
+ * @param requiredUnsetAccessFlags the class access flags that should be
+ * unset.
+ * @param classFileVisitor the <code>ClassFileVisitor</code> to
+ * which visits will be delegated.
+ */
+ public ClassFileAccessFilter(int requiredSetAccessFlags,
+ int requiredUnsetAccessFlags,
+ ClassFileVisitor classFileVisitor)
+ {
+ this.requiredSetAccessFlags = requiredSetAccessFlags;
+ this.requiredUnsetAccessFlags = requiredUnsetAccessFlags;
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ if (accepted(programClassFile.getAccessFlags()))
+ {
+ classFileVisitor.visitProgramClassFile(programClassFile);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ if (accepted(libraryClassFile.getAccessFlags()))
+ {
+ classFileVisitor.visitLibraryClassFile(libraryClassFile);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private boolean accepted(int accessFlags)
+ {
+ return (requiredSetAccessFlags & ~accessFlags) == 0 &&
+ (requiredUnsetAccessFlags & accessFlags) == 0;
+ }
+}
diff --git a/src/proguard/classfile/visitor/ClassFileCleaner.java b/src/proguard/classfile/visitor/ClassFileCleaner.java
new file mode 100644
index 0000000..a80348e
--- /dev/null
+++ b/src/proguard/classfile/visitor/ClassFileCleaner.java
@@ -0,0 +1,368 @@
+/* $Id: ClassFileCleaner.java,v 1.17 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+
+/**
+ * This <code>ClassFileVisitor</code> removes all visitor information of the
+ * class files it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileCleaner
+ implements ClassFileVisitor,
+ CpInfoVisitor,
+ MemberInfoVisitor,
+ AttrInfoVisitor,
+ ExceptionInfoVisitor,
+ InnerClassesInfoVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor
+{
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ clean(programClassFile);
+
+ programClassFile.constantPoolEntriesAccept(this);
+
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+
+ programClassFile.attributesAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ clean(libraryClassFile);
+
+ libraryClassFile.fieldsAccept(this);
+ libraryClassFile.methodsAccept(this);
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ clean(classCpInfo);
+ }
+
+
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo)
+ {
+ clean(doubleCpInfo);
+ }
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ clean(fieldrefCpInfo);
+ }
+
+
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo)
+ {
+ clean(floatCpInfo);
+ }
+
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo)
+ {
+ clean(integerCpInfo);
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ clean(interfaceMethodrefCpInfo);
+ }
+
+
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo)
+ {
+ clean(longCpInfo);
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ clean(methodrefCpInfo);
+ }
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ clean(nameAndTypeCpInfo);
+ }
+
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ clean(stringCpInfo);
+ }
+
+
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
+ {
+ clean(utf8CpInfo);
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ clean(programMemberInfo);
+
+ programMemberInfo.attributesAccept(programClassFile, this);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ clean(libraryFieldInfo);
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ clean(libraryMethodInfo);
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo)
+ {
+ clean(unknownAttrInfo);
+ }
+
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ clean(innerClassesAttrInfo);
+
+ innerClassesAttrInfo.innerClassEntriesAccept(classFile, this);
+ }
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ clean(enclosingMethodAttrInfo);
+ }
+
+
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo)
+ {
+ clean(constantValueAttrInfo);
+ }
+
+
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo)
+ {
+ clean(exceptionsAttrInfo);
+
+ exceptionsAttrInfo.exceptionEntriesAccept((ProgramClassFile)classFile, this);
+ }
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ clean(codeAttrInfo);
+
+ codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
+ codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+ }
+
+
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo)
+ {
+ clean(lineNumberTableAttrInfo);
+ }
+
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ clean(localVariableTableAttrInfo);
+ }
+
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ clean(localVariableTypeTableAttrInfo);
+ }
+
+
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+ {
+ clean(sourceFileAttrInfo);
+ }
+
+
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
+ {
+ clean(sourceDirAttrInfo);
+ }
+
+
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo)
+ {
+ clean(deprecatedAttrInfo);
+ }
+
+
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo)
+ {
+ clean(syntheticAttrInfo);
+ }
+
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ clean(signatureAttrInfo);
+ }
+
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ clean(runtimeVisibleAnnotationsAttrInfo);
+
+ runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ clean(runtimeInvisibleAnnotationsAttrInfo);
+
+ runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ clean(runtimeVisibleParameterAnnotationsAttrInfo);
+
+ runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ clean(runtimeInvisibleParameterAnnotationsAttrInfo);
+
+ runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ clean(annotationDefaultAttrInfo);
+
+ annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(ClassFile classFile, InnerClassesInfo innerClassesInfo)
+ {
+ clean(innerClassesInfo);
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, ExceptionInfo exceptionInfo)
+ {
+ clean(exceptionInfo);
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(ClassFile classFile, Annotation annotation)
+ {
+ clean(annotation);
+
+ annotation.elementValuesAccept(classFile, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ clean(constantElementValue);
+ }
+
+
+ public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ clean(enumConstantElementValue);
+ }
+
+
+ public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
+ {
+ clean(classElementValue);
+ }
+
+
+ public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ clean(annotationElementValue);
+
+ annotationElementValue.annotationAccept(classFile, this);
+ }
+
+
+ public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ clean(arrayElementValue);
+ }
+
+
+ // Small utility methods.
+
+ private void clean(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(null);
+ }
+}
diff --git a/src/proguard/classfile/visitor/ClassFileHierarchyTraveler.java b/src/proguard/classfile/visitor/ClassFileHierarchyTraveler.java
new file mode 100644
index 0000000..c263058
--- /dev/null
+++ b/src/proguard/classfile/visitor/ClassFileHierarchyTraveler.java
@@ -0,0 +1,91 @@
+/* $Id: ClassFileHierarchyTraveler.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> lets a given <code>ClassFileVisitor</code>
+ * optionally travel to the visited class, its superclass, its interfaces, and
+ * its subclasses.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileHierarchyTraveler implements ClassFileVisitor
+{
+ private boolean visitThisClass;
+ private boolean visitSuperClass;
+ private boolean visitInterfaces;
+ private boolean visitSubclasses;
+
+ private ClassFileVisitor classFileVisitor;
+
+
+ /**
+ * Creates a new ClassFileHierarchyTraveler.
+ * @param visitThisClass specifies whether to visit the originally visited
+ * classes.
+ * @param visitSuperClass specifies whether to visit the super classes of
+ * the visited classes.
+ * @param visitInterfaces specifies whether to visit the interfaces of
+ * the visited classes.
+ * @param visitSubclasses specifies whether to visit the subclasses of
+ * the visited classes.
+ * @param classFileVisitor the <code>ClassFileVisitor</code> to
+ * which visits will be delegated.
+ */
+ public ClassFileHierarchyTraveler(boolean visitThisClass,
+ boolean visitSuperClass,
+ boolean visitInterfaces,
+ boolean visitSubclasses,
+ ClassFileVisitor classFileVisitor)
+ {
+ this.visitThisClass = visitThisClass;
+ this.visitSuperClass = visitSuperClass;
+ this.visitInterfaces = visitInterfaces;
+ this.visitSubclasses = visitSubclasses;
+
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ programClassFile.hierarchyAccept(visitThisClass,
+ visitSuperClass,
+ visitInterfaces,
+ visitSubclasses,
+ classFileVisitor);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ libraryClassFile.hierarchyAccept(visitThisClass,
+ visitSuperClass,
+ visitInterfaces,
+ visitSubclasses,
+ classFileVisitor);
+ }
+}
diff --git a/src/proguard/classfile/visitor/ClassFileMemberInfoVisitor.java b/src/proguard/classfile/visitor/ClassFileMemberInfoVisitor.java
new file mode 100644
index 0000000..19fd93a
--- /dev/null
+++ b/src/proguard/classfile/visitor/ClassFileMemberInfoVisitor.java
@@ -0,0 +1,88 @@
+/* $Id: ClassFileMemberInfoVisitor.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This MemberInfoVisitor delegates all visits to a given ClassFileVisitor.
+ * The latter visits the class file of each visited class member, although
+ * never twice in a row.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileMemberInfoVisitor implements MemberInfoVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+
+ private ClassFile lastVisitedClassFile;
+
+
+ public ClassFileMemberInfoVisitor(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ if (!programClassFile.equals(lastVisitedClassFile))
+ {
+ classFileVisitor.visitProgramClassFile(programClassFile);
+
+ lastVisitedClassFile = programClassFile;
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ if (!programClassFile.equals(lastVisitedClassFile))
+ {
+ classFileVisitor.visitProgramClassFile(programClassFile);
+
+ lastVisitedClassFile = programClassFile;
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ if (!libraryClassFile.equals(lastVisitedClassFile))
+ {
+ classFileVisitor.visitLibraryClassFile(libraryClassFile);
+
+ lastVisitedClassFile = libraryClassFile;
+ }
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ if (!libraryClassFile.equals(lastVisitedClassFile))
+ {
+ classFileVisitor.visitLibraryClassFile(libraryClassFile);
+
+ lastVisitedClassFile = libraryClassFile;
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/ClassFileNameFilter.java b/src/proguard/classfile/visitor/ClassFileNameFilter.java
new file mode 100644
index 0000000..96e8e17
--- /dev/null
+++ b/src/proguard/classfile/visitor/ClassFileNameFilter.java
@@ -0,0 +1,81 @@
+/* $Id: ClassFileNameFilter.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.util.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> delegates its visits to another given
+ * <code>ClassFileVisitor</code>, but only when the visited class file
+ * has a name that matches a given regular expression.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileNameFilter implements ClassFileVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+ private StringMatcher regularExpressionMatcher;
+
+
+ /**
+ * Creates a new ClassFileNameFilter.
+ * @param classFileVisitor the <code>ClassFileVisitor</code> to which visits
+ * will be delegated.
+ * @param regularExpression the regular expression against which class names
+ * will be matched.
+ */
+ public ClassFileNameFilter(ClassFileVisitor classFileVisitor,
+ String regularExpression)
+ {
+ this.classFileVisitor = classFileVisitor;
+ this.regularExpressionMatcher = new ClassNameMatcher(regularExpression);
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ if (accepted(programClassFile.getName()))
+ {
+ classFileVisitor.visitProgramClassFile(programClassFile);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ if (accepted(libraryClassFile.getName()))
+ {
+ classFileVisitor.visitLibraryClassFile(libraryClassFile);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private boolean accepted(String name)
+ {
+ return regularExpressionMatcher.matches(name);
+ }
+}
diff --git a/src/proguard/classfile/visitor/ClassFilePrinter.java b/src/proguard/classfile/visitor/ClassFilePrinter.java
new file mode 100644
index 0000000..8d1268b
--- /dev/null
+++ b/src/proguard/classfile/visitor/ClassFilePrinter.java
@@ -0,0 +1,677 @@
+/* $Id: ClassFilePrinter.java,v 1.30 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+
+import java.io.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> prints out the complete internal
+ * structure of the class files it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFilePrinter
+ implements ClassFileVisitor,
+ CpInfoVisitor,
+ MemberInfoVisitor,
+ AttrInfoVisitor,
+ ExceptionInfoVisitor,
+ InnerClassesInfoVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor,
+ InstructionVisitor
+{
+ private static final String INDENTATION = " ";
+
+ private PrintStream ps;
+ private int indentation;
+
+
+ /**
+ * Creates a new ClassFilePrinter that prints to <code>System.out</code>.
+ */
+ public ClassFilePrinter()
+ {
+ this(System.out);
+ }
+
+
+ /**
+ * Creates a new ClassFilePrinter that prints to the given
+ * <code>PrintStream</code>.
+ */
+ public ClassFilePrinter(PrintStream printStream)
+ {
+ ps = printStream;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ println("_____________________________________________________________________");
+ println(visitorInfo(programClassFile) + " CLASS: " + programClassFile.getName());
+ println("Access: " + ClassUtil.externalClassAccessFlags(programClassFile.u2accessFlags) + "(" + Integer.toHexString(programClassFile.u2accessFlags) + ")");
+ println("Minor version: " + Integer.toHexString(programClassFile.u2minorVersion));
+ println("Major version: " + Integer.toHexString(programClassFile.u2majorVersion));
+ println("Access: " + Integer.toHexString(programClassFile.u2accessFlags));
+ println("Superclass: " + programClassFile.getSuperName());
+ println();
+
+ println("Interfaces (count = " + programClassFile.u2interfacesCount + "):");
+ indent();
+ for (int i = 0; i < programClassFile.u2interfacesCount; i++)
+ {
+ println("+ " + programClassFile.getCpClassNameString(programClassFile.u2interfaces[i]));
+ }
+ outdent();
+ println();
+
+ println("Constant Pool (count = " + programClassFile.u2constantPoolCount + "):");
+ indent();
+ programClassFile.constantPoolEntriesAccept(this);
+ outdent();
+ println();
+
+ println("Fields (count = " + programClassFile.u2fieldsCount + "):");
+ indent();
+ programClassFile.fieldsAccept(this);
+ outdent();
+ println();
+
+ println("Methods (count = " + programClassFile.u2methodsCount + "):");
+ indent();
+ programClassFile.methodsAccept(this);
+ outdent();
+ println();
+
+ println("Class file attributes (count = " + programClassFile.u2attributesCount + "):");
+ indent();
+ programClassFile.attributesAccept(this);
+ outdent();
+ println();
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ println("_____________________________________________________________________");
+ println(visitorInfo(libraryClassFile) + " LIBRARY CLASS: " + libraryClassFile.getName());
+ println("Access: " + ClassUtil.externalClassAccessFlags(libraryClassFile.u2accessFlags) + "(" + Integer.toHexString(libraryClassFile.u2accessFlags) + ")");
+ println("Superclass: " + libraryClassFile.getSuperName());
+ println();
+
+ println("Interfaces (count = " + libraryClassFile.interfaceClasses.length + "):");
+ for (int i = 0; i < libraryClassFile.interfaceClasses.length; i++)
+ {
+ println(" + " + libraryClassFile.interfaceClasses[i].getName());
+ }
+
+ println("Fields (count = " + libraryClassFile.fields.length + "):");
+ libraryClassFile.fieldsAccept(this);
+
+ println("Methods (count = " + libraryClassFile.methods.length + "):");
+ libraryClassFile.methodsAccept(this);
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ println(visitorInfo(classCpInfo) + " Class [" +
+ classFile.getCpString(classCpInfo.u2nameIndex) + "]");
+ }
+
+
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo)
+ {
+ println(visitorInfo(doubleCpInfo) + " Double [" +
+ Double.longBitsToDouble(((long)doubleCpInfo.u4highBytes << 32) |
+ (long)doubleCpInfo.u4lowBytes) + "]");
+ }
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ println(visitorInfo(fieldrefCpInfo) + " Fieldref [" +
+ classFile.getCpClassNameString(fieldrefCpInfo.u2classIndex) + "." +
+ classFile.getCpNameString(fieldrefCpInfo.u2nameAndTypeIndex) + " " +
+ classFile.getCpTypeString(fieldrefCpInfo.u2nameAndTypeIndex) + "]");
+ }
+
+
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo)
+ {
+ println(visitorInfo(floatCpInfo) + " Float [" +
+ Float.intBitsToFloat(floatCpInfo.u4bytes) + "]");
+ }
+
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo)
+ {
+ println(visitorInfo(integerCpInfo) + " Integer [" +
+ integerCpInfo.u4bytes + "]");
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ println(visitorInfo(interfaceMethodrefCpInfo) + " InterfaceMethodref [" +
+ classFile.getCpClassNameString(interfaceMethodrefCpInfo.u2classIndex) + "." +
+ classFile.getCpNameString(interfaceMethodrefCpInfo.u2nameAndTypeIndex) + " " +
+ classFile.getCpTypeString(interfaceMethodrefCpInfo.u2nameAndTypeIndex) + "]");
+ }
+
+
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo)
+ {
+ println(visitorInfo(longCpInfo) + " Long [" +
+ (((long)longCpInfo.u4highBytes << 32) |
+ (long)longCpInfo.u4lowBytes) + "]");
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ println(visitorInfo(methodrefCpInfo) + " Methodref [" +
+ classFile.getCpClassNameString(methodrefCpInfo.u2classIndex) + "." +
+ classFile.getCpNameString(methodrefCpInfo.u2nameAndTypeIndex) + " " +
+ classFile.getCpTypeString(methodrefCpInfo.u2nameAndTypeIndex) + "]");
+ }
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ println(visitorInfo(nameAndTypeCpInfo) + " NameAndType [" +
+ classFile.getCpString(nameAndTypeCpInfo.u2nameIndex) + " " +
+ classFile.getCpString(nameAndTypeCpInfo.u2descriptorIndex) + "]");
+ }
+
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ println(visitorInfo(stringCpInfo) + " String [" +
+ classFile.getCpString(stringCpInfo.u2stringIndex) + "]");
+ }
+
+
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
+ {
+ println(visitorInfo(utf8CpInfo) + " Utf8 [" +
+ utf8CpInfo.getString() + "]");
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ println(visitorInfo(programMemberInfo) + " " +
+ programClassFile.getCpString(programMemberInfo.u2nameIndex) + " " +
+ programClassFile.getCpString(programMemberInfo.u2descriptorIndex));
+
+ if (programMemberInfo.u2attributesCount > 0)
+ {
+ indent();
+ println("Class member attributes (count = " + programMemberInfo.u2attributesCount + "):");
+ programMemberInfo.attributesAccept(programClassFile, this);
+ outdent();
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ visitLibraryMemberInfo(libraryClassFile, libraryFieldInfo);
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ visitLibraryMemberInfo(libraryClassFile, libraryMethodInfo);
+ }
+
+
+ private void visitLibraryMemberInfo(LibraryClassFile libraryClassFile, LibraryMemberInfo libraryMemberInfo)
+ {
+ println(visitorInfo(libraryMemberInfo) + " " +
+ libraryMemberInfo.getName(libraryClassFile) + " " +
+ libraryMemberInfo.getDescriptor(libraryClassFile));
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+ // Note that attributes are typically only referenced once, so we don't
+ // test if they are marked already.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo)
+ {
+ println(visitorInfo(unknownAttrInfo) +
+ " Unknown attribute (" + classFile.getCpString(unknownAttrInfo.u2attrNameIndex) + ")");
+ }
+
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ println(visitorInfo(innerClassesAttrInfo) +
+ " Inner classes attribute (count = " + innerClassesAttrInfo.u2numberOfClasses + ")");
+
+ indent();
+ innerClassesAttrInfo.innerClassEntriesAccept(classFile, this);
+ outdent();
+ }
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ println(visitorInfo(enclosingMethodAttrInfo) +
+ " Enclosing method attribute [" +
+ classFile.getCpClassNameString(enclosingMethodAttrInfo.u2classIndex) +
+ (enclosingMethodAttrInfo.u2nameAndTypeIndex == 0 ? "" : "." +
+ classFile.getCpNameString(enclosingMethodAttrInfo.u2nameAndTypeIndex) + " " +
+ classFile.getCpTypeString(enclosingMethodAttrInfo.u2nameAndTypeIndex)) + "]");
+ }
+
+
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo)
+ {
+ println(visitorInfo(constantValueAttrInfo) +
+ " Constant value attribute:");
+
+ classFile.constantPoolEntryAccept(constantValueAttrInfo.u2constantValueIndex, this);
+ }
+
+
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo)
+ {
+ println(visitorInfo(exceptionsAttrInfo) +
+ " Exceptions attribute (count = " + exceptionsAttrInfo.u2numberOfExceptions + ")");
+
+ indent();
+ exceptionsAttrInfo.exceptionEntriesAccept((ProgramClassFile)classFile, this);
+ outdent();
+ }
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ println(visitorInfo(codeAttrInfo) +
+ " Code attribute instructions (code length = "+ codeAttrInfo.u4codeLength +
+ ", locals = "+ codeAttrInfo.u2maxLocals +
+ ", stack = "+ codeAttrInfo.u2maxStack + "):");
+
+ indent();
+
+ codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
+
+ println("Code attribute exceptions (count = " +
+ codeAttrInfo.u2exceptionTableLength + "):");
+
+ codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
+
+ println("Code attribute attributes (attribute count = " +
+ codeAttrInfo.u2attributesCount + "):");
+
+ codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+
+ outdent();
+ }
+
+
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo)
+ {
+ println(visitorInfo(lineNumberTableAttrInfo) +
+ " Line number table attribute (count = " +
+ lineNumberTableAttrInfo.u2lineNumberTableLength + ")");
+ // ...
+ }
+
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ println(visitorInfo(localVariableTableAttrInfo) +
+ " Local variable table attribute (count = " +
+ localVariableTableAttrInfo.u2localVariableTableLength + ")");
+ // ...
+ }
+
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ println(visitorInfo(localVariableTypeTableAttrInfo) +
+ " Local variable type table attribute (count = "+
+ localVariableTypeTableAttrInfo.u2localVariableTypeTableLength + ")");
+ // ...
+ }
+
+
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+ {
+ println(visitorInfo(sourceFileAttrInfo) +
+ " Source file attribute:");
+
+ indent();
+ classFile.constantPoolEntryAccept(sourceFileAttrInfo.u2sourceFileIndex, this);
+ outdent();
+ }
+
+
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
+ {
+ println(visitorInfo(sourceDirAttrInfo) +
+ " Source dir attribute:");
+
+ indent();
+ classFile.constantPoolEntryAccept(sourceDirAttrInfo.u2sourceDirIndex, this);
+ outdent();
+ }
+
+
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo)
+ {
+ println(visitorInfo(deprecatedAttrInfo) +
+ " Deprecated attribute");
+ }
+
+
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo)
+ {
+ println(visitorInfo(syntheticAttrInfo) +
+ " Synthetic attribute");
+ }
+
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ println(visitorInfo(signatureAttrInfo) +
+ " Signature attribute:");
+
+ indent();
+ classFile.constantPoolEntryAccept(signatureAttrInfo.u2signatureIndex, this);
+ outdent();
+ }
+
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ println(visitorInfo(runtimeVisibleAnnotationsAttrInfo) +
+ " Runtime visible annotation attribute:");
+
+ indent();
+ runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ outdent();
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ println(visitorInfo(runtimeInvisibleAnnotationsAttrInfo) +
+ " Runtime invisible annotation attribute:");
+
+ indent();
+ runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ outdent();
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ println(visitorInfo(runtimeVisibleParameterAnnotationsAttrInfo) +
+ " Runtime visible parameter annotation attribute:");
+
+ indent();
+ runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ outdent();
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ println(visitorInfo(runtimeInvisibleParameterAnnotationsAttrInfo) +
+ " Runtime invisible parameter annotation attribute:");
+
+ indent();
+ runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ outdent();
+ }
+
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ println(visitorInfo(annotationDefaultAttrInfo) +
+ " Annotation default attribute:");
+
+ indent();
+ annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+ outdent();
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(ClassFile classFile, InnerClassesInfo innerClassesInfo)
+ {
+ println(visitorInfo(innerClassesInfo) +
+ " InnerClassesInfo:");
+
+ indent();
+ if (innerClassesInfo.u2innerClassInfoIndex != 0)
+ {
+ classFile.constantPoolEntryAccept(innerClassesInfo.u2innerClassInfoIndex, this);
+ }
+
+ if (innerClassesInfo.u2outerClassInfoIndex != 0)
+ {
+ classFile.constantPoolEntryAccept(innerClassesInfo.u2outerClassInfoIndex, this);
+ }
+
+ if (innerClassesInfo.u2innerNameIndex != 0)
+ {
+ classFile.constantPoolEntryAccept(innerClassesInfo.u2innerNameIndex, this);
+ }
+ outdent();
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(ClassFile classFile, Annotation annotation)
+ {
+ println(visitorInfo(annotation) +
+ " Annotation [" + classFile.getCpString(annotation.u2typeIndex) + "]:");
+
+ indent();
+ annotation.elementValuesAccept(classFile, this);
+ outdent();
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ println(visitorInfo(constantElementValue) +
+ " Constant element value [" +
+ (constantElementValue.u2elementName == 0 ? "(default)" :
+ classFile.getCpString(constantElementValue.u2elementName)) + "]");
+
+ indent();
+ classFile.constantPoolEntryAccept(constantElementValue.u2constantValueIndex, this);
+ outdent();
+ }
+
+
+ public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ println(visitorInfo(enumConstantElementValue) +
+ " Enum constant element value [" +
+ (enumConstantElementValue.u2elementName == 0 ? "(default)" :
+ classFile.getCpString(enumConstantElementValue.u2elementName)) + ", " +
+ classFile.getCpString(enumConstantElementValue.u2typeNameIndex) + ", " +
+ classFile.getCpString(enumConstantElementValue.u2constantNameIndex) + "]");
+ }
+
+
+ public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
+ {
+ println(visitorInfo(classElementValue) +
+ " Class element value [" +
+ (classElementValue.u2elementName == 0 ? "(default)" :
+ classFile.getCpString(classElementValue.u2elementName)) + ", " +
+ classFile.getCpString(classElementValue.u2classInfoIndex) + "]");
+ }
+
+
+ public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ println(visitorInfo(annotationElementValue) +
+ " Annotation element value [" +
+ (annotationElementValue.u2elementName == 0 ? "(default)" :
+ classFile.getCpString(annotationElementValue.u2elementName)) + "]:");
+
+ indent();
+ annotationElementValue.annotationAccept(classFile, this);
+ outdent();
+ }
+
+
+ public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ println(visitorInfo(arrayElementValue) +
+ " Array element value [" +
+ (arrayElementValue.u2elementName == 0 ? "(default)" :
+ classFile.getCpString(arrayElementValue.u2elementName)) + "]:");
+
+ indent();
+ arrayElementValue.elementValuesAccept(classFile, annotation, this);
+ outdent();
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
+ {
+ println(InstructionFactory.create(codeAttrInfo.code, offset).toString(offset));
+ }
+
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ println(InstructionFactory.create(codeAttrInfo.code, offset).toString(offset));
+ }
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ println(InstructionFactory.create(codeAttrInfo.code, offset).toString(offset));
+
+ indent();
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+ outdent();
+ }
+
+
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
+ {
+ println(InstructionFactory.create(codeAttrInfo.code, offset).toString(offset));
+ }
+
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ println(InstructionFactory.create(codeAttrInfo.code, offset).toString(offset));
+ }
+
+
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ println(InstructionFactory.create(codeAttrInfo.code, offset).toString(offset));
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, ExceptionInfo exceptionInfo)
+ {
+ println(visitorInfo(exceptionInfo) +
+ " ExceptionInfo:");
+
+ if (exceptionInfo.u2catchType != 0)
+ {
+ classFile.constantPoolEntryAccept(exceptionInfo.u2catchType, this);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private void indent()
+ {
+ indentation++;
+ }
+
+ private void outdent()
+ {
+ indentation--;
+ }
+
+ private void println()
+ {
+ ps.println();
+ }
+
+ private void println(String string)
+ {
+ for (int i = 0; i < indentation; i++)
+ {
+ ps.print(INDENTATION);
+ }
+
+ ps.println(string);
+ }
+
+
+ private String visitorInfo(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == null ? "-" : "+";
+ }
+}
diff --git a/src/proguard/classfile/visitor/ClassFileVisitor.java b/src/proguard/classfile/visitor/ClassFileVisitor.java
new file mode 100644
index 0000000..7723f7a
--- /dev/null
+++ b/src/proguard/classfile/visitor/ClassFileVisitor.java
@@ -0,0 +1,36 @@
+/* $Id: ClassFileVisitor.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>ClassFile</code> objects.
+ *
+ * @author Eric Lafortune
+ */
+public interface ClassFileVisitor
+{
+ public void visitProgramClassFile(ProgramClassFile programClassFile);
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile);
+}
diff --git a/src/proguard/classfile/visitor/ClassPoolFiller.java b/src/proguard/classfile/visitor/ClassPoolFiller.java
new file mode 100644
index 0000000..19ac0c9
--- /dev/null
+++ b/src/proguard/classfile/visitor/ClassPoolFiller.java
@@ -0,0 +1,69 @@
+/* $Id: ClassPoolFiller.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.util.ClassUtil;
+
+
+/**
+ * This ClassFileVisitor collects all the class files it visits in a given
+ * class pool.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassPoolFiller implements ClassFileVisitor
+{
+ private ClassPool classPool;
+ private boolean note;
+
+
+ public ClassPoolFiller(ClassPool classPool,
+ boolean note)
+ {
+ this.classPool = classPool;
+ this.note = note;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ ClassFile previousClassFile = classPool.addClass(programClassFile);
+ if (previousClassFile != null &&
+ note)
+ {
+ System.err.println("Note: duplicate definition of program class [" + ClassUtil.externalClassName(programClassFile.getName()) + "]");
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ ClassFile previousClassFile = classPool.addClass(libraryClassFile);
+ if (previousClassFile != null &&
+ note)
+ {
+ System.err.println("Note: duplicate definition of library class [" + ClassUtil.externalClassName(libraryClassFile.getName()) + "]");
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/ClassPoolVisitor.java b/src/proguard/classfile/visitor/ClassPoolVisitor.java
new file mode 100644
index 0000000..111c6d9
--- /dev/null
+++ b/src/proguard/classfile/visitor/ClassPoolVisitor.java
@@ -0,0 +1,37 @@
+/* $Id: ClassPoolVisitor.java,v 1.9 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>ClassPool</code> objects. Note that there is only a single
+ * implementation of <code>ClassPool</code>, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Eric Lafortune
+ */
+public interface ClassPoolVisitor
+{
+ public void visitClassPool(ClassPool classPool);
+}
diff --git a/src/proguard/classfile/visitor/ConcreteClassFileDownTraveler.java b/src/proguard/classfile/visitor/ConcreteClassFileDownTraveler.java
new file mode 100644
index 0000000..bba9771
--- /dev/null
+++ b/src/proguard/classfile/visitor/ConcreteClassFileDownTraveler.java
@@ -0,0 +1,100 @@
+/* $Id: ConcreteClassFileDownTraveler.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> lets a given <code>ClassFileVisitor</code>
+ * travel to the first concrete subclasses down in its hierarchy of abstract
+ * classes and concrete classes.
+ *
+ * @author Eric Lafortune
+ */
+public class ConcreteClassFileDownTraveler
+ implements ClassFileVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+
+
+ /**
+ * Creates a new ConcreteClassFileDownTraveler.
+ * @param classFileVisitor the <code>ClassFileVisitor</code> to
+ * which visits will be delegated.
+ */
+ public ConcreteClassFileDownTraveler(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Is this an abstract class or an interface?
+ if ((programClassFile.getAccessFlags() &
+ (ClassConstants.INTERNAL_ACC_INTERFACE |
+ ClassConstants.INTERNAL_ACC_ABSTRACT)) != 0)
+ {
+ // Travel down the hierarchy.
+ ClassFile[] subClasses = programClassFile.subClasses;
+ if (subClasses != null)
+ {
+ for (int i = 0; i < subClasses.length; i++)
+ {
+ subClasses[i].accept(this);
+ }
+ }
+ }
+ else
+ {
+ // Visit the class file. Don't descend any further.
+ programClassFile.accept(classFileVisitor);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ // Is this an abstract class or interface?
+ if ((libraryClassFile.getAccessFlags() &
+ (ClassConstants.INTERNAL_ACC_INTERFACE |
+ ClassConstants.INTERNAL_ACC_ABSTRACT)) != 0)
+ {
+ // Travel down the hierarchy.
+ ClassFile[] subClasses = libraryClassFile.subClasses;
+ if (subClasses != null)
+ {
+ for (int i = 0; i < subClasses.length; i++)
+ {
+ subClasses[i].accept(this);
+ }
+ }
+ }
+ else
+ {
+ // Visit the class file. Don't descend any further.
+ libraryClassFile.accept(classFileVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/CpInfoVisitor.java b/src/proguard/classfile/visitor/CpInfoVisitor.java
new file mode 100644
index 0000000..c4b190b
--- /dev/null
+++ b/src/proguard/classfile/visitor/CpInfoVisitor.java
@@ -0,0 +1,45 @@
+/* $Id: CpInfoVisitor.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of <code>CpInfo</code>
+ * objects.
+ *
+ * @author Eric Lafortune
+ */
+public interface CpInfoVisitor
+{
+ public void visitIntegerCpInfo( ClassFile classFile, IntegerCpInfo integerCpInfo);
+ public void visitLongCpInfo( ClassFile classFile, LongCpInfo longCpInfo);
+ public void visitFloatCpInfo( ClassFile classFile, FloatCpInfo floatCpInfo);
+ public void visitDoubleCpInfo( ClassFile classFile, DoubleCpInfo doubleCpInfo);
+ public void visitStringCpInfo( ClassFile classFile, StringCpInfo stringCpInfo);
+ public void visitUtf8CpInfo( ClassFile classFile, Utf8CpInfo utf8CpInfo);
+ public void visitFieldrefCpInfo( ClassFile classFile, FieldrefCpInfo fieldrefCpInfo);
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo);
+ public void visitMethodrefCpInfo( ClassFile classFile, MethodrefCpInfo methodrefCpInfo);
+ public void visitClassCpInfo( ClassFile classFile, ClassCpInfo classCpInfo);
+ public void visitNameAndTypeCpInfo( ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo);
+}
diff --git a/src/proguard/classfile/visitor/LibraryClassFileFilter.java b/src/proguard/classfile/visitor/LibraryClassFileFilter.java
new file mode 100644
index 0000000..203dd17
--- /dev/null
+++ b/src/proguard/classfile/visitor/LibraryClassFileFilter.java
@@ -0,0 +1,60 @@
+/* $Id: LibraryClassFileFilter.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> delegates its visits to another given
+ * <code>ClassFileVisitor</code>, but only when visiting library class files.
+ *
+ * @author Eric Lafortune
+ */
+public class LibraryClassFileFilter implements ClassFileVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+
+
+ /**
+ * Creates a new LibraryClassFileFilter.
+ * @param classFileVisitor the <code>ClassFileVisitor</code> to which visits
+ * will be delegated.
+ */
+ public LibraryClassFileFilter(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Don't delegate visits to program class files.
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ classFileVisitor.visitLibraryClassFile(libraryClassFile);
+ }
+}
diff --git a/src/proguard/classfile/visitor/LibraryMemberInfoFilter.java b/src/proguard/classfile/visitor/LibraryMemberInfoFilter.java
new file mode 100644
index 0000000..9d32e2e
--- /dev/null
+++ b/src/proguard/classfile/visitor/LibraryMemberInfoFilter.java
@@ -0,0 +1,73 @@
+/* $Id: LibraryMemberInfoFilter.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This <code>MemberInfoVisitor</code> delegates its visits to another given
+ * <code>MemberInfoVisitor</code>, but only when visiting members of library
+ * class files.
+ *
+ * @author Eric Lafortune
+ */
+public class LibraryMemberInfoFilter implements MemberInfoVisitor
+{
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ /**
+ * Creates a new ProgramMemberInfoFilter.
+ * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which
+ * visits will be delegated.
+ */
+ public LibraryMemberInfoFilter(MemberInfoVisitor memberInfoVisitor)
+ {
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ // Don't delegate visits to program members.
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ // Don't delegate visits to program members.
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, libraryFieldInfo);
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
+ }
+}
diff --git a/src/proguard/classfile/visitor/LineNumberInfoVisitor.java b/src/proguard/classfile/visitor/LineNumberInfoVisitor.java
new file mode 100644
index 0000000..61a2083
--- /dev/null
+++ b/src/proguard/classfile/visitor/LineNumberInfoVisitor.java
@@ -0,0 +1,38 @@
+/* $Id: LineNumberInfoVisitor.java,v 1.9 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>LineNumberInfo</code> objects. Note that there is only a single
+ * implementation of <code>LineNumberInfo</code>, such that this interface
+ * is not strictly necessary as a visitor.
+ *
+ * @author Eric Lafortune
+ */
+public interface LineNumberInfoVisitor
+{
+ public void visitLineNumberInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberInfo lineNumberInfo);
+}
diff --git a/src/proguard/classfile/visitor/MemberInfoAccessFilter.java b/src/proguard/classfile/visitor/MemberInfoAccessFilter.java
new file mode 100644
index 0000000..0c8ac62
--- /dev/null
+++ b/src/proguard/classfile/visitor/MemberInfoAccessFilter.java
@@ -0,0 +1,122 @@
+/* $Id: MemberInfoAccessFilter.java,v 1.6 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This <code>MemberInfoVisitor</code> delegates its visits to another given
+ * <code>MemberInfoVisitor</code>, but only when the visited member
+ * has the proper access flags.
+ * <p>
+ * If conflicting access flags (public/private/protected) are specified,
+ * having one of them set will be considered sufficient.
+ *
+ * @see ClassConstants
+ *
+ * @author Eric Lafortune
+ */
+public class MemberInfoAccessFilter
+ implements MemberInfoVisitor
+{
+ // A mask of conflicting access flags. These are interpreted in a special
+ // way if more of them are required at the same time. In that case, one
+ // of them being set is sufficient.
+ private static final int ACCESS_MASK =
+ ClassConstants.INTERNAL_ACC_PUBLIC |
+ ClassConstants.INTERNAL_ACC_PRIVATE |
+ ClassConstants.INTERNAL_ACC_PROTECTED;
+
+ private int requiredSetAccessFlags;
+ private int requiredUnsetAccessFlags;
+ private int requiredOneSetAccessFlags;
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ /**
+ * Creates a new MemberInfoAccessFilter.
+ * @param requiredSetAccessFlags the class access flags that should be
+ * set.
+ * @param requiredUnsetAccessFlags the class access flags that should be
+ * unset.
+ * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to
+ * which visits will be delegated.
+ */
+ public MemberInfoAccessFilter(int requiredSetAccessFlags,
+ int requiredUnsetAccessFlags,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ this.requiredSetAccessFlags = requiredSetAccessFlags & ~ACCESS_MASK;
+ this.requiredUnsetAccessFlags = requiredUnsetAccessFlags;
+ this.requiredOneSetAccessFlags = requiredSetAccessFlags & ACCESS_MASK;
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ if (accepted(programFieldInfo.getAccessFlags()))
+ {
+ memberInfoVisitor.visitProgramFieldInfo(programClassFile, programFieldInfo);
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ if (accepted(programMethodInfo.getAccessFlags()))
+ {
+ memberInfoVisitor.visitProgramMethodInfo(programClassFile, programMethodInfo);
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ if (accepted(libraryFieldInfo.getAccessFlags()))
+ {
+ memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, libraryFieldInfo);
+ }
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ if (accepted(libraryMethodInfo.getAccessFlags()))
+ {
+ memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private boolean accepted(int accessFlags)
+ {
+ return (requiredSetAccessFlags & ~accessFlags) == 0 &&
+ (requiredUnsetAccessFlags & accessFlags) == 0 &&
+ (requiredOneSetAccessFlags == 0 ||
+ (requiredOneSetAccessFlags & accessFlags) != 0);
+ }
+}
diff --git a/src/proguard/classfile/visitor/MemberInfoDescriptorFilter.java b/src/proguard/classfile/visitor/MemberInfoDescriptorFilter.java
new file mode 100644
index 0000000..3475e46
--- /dev/null
+++ b/src/proguard/classfile/visitor/MemberInfoDescriptorFilter.java
@@ -0,0 +1,99 @@
+/* $Id: MemberInfoDescriptorFilter.java,v 1.9 2004/11/27 10:09:26 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.util.*;
+
+
+/**
+ * This <code>MemberInfoVisitor</code> delegates its visits to another given
+ * <code>MemberInfoVisitor</code>, but only when the visited member
+ * has a descriptor that matches a given regular expression.
+ *
+ * @author Eric Lafortune
+ */
+public class MemberInfoDescriptorFilter implements MemberInfoVisitor
+{
+ private StringMatcher regularExpressionMatcher;
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ /**
+ * Creates a new MemberInfoDescriptorFilter.
+ * @param regularExpression the regular expression against which class names
+ * will be matched.
+ * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which visits
+ * will be delegated.
+ */
+ public MemberInfoDescriptorFilter(String regularExpression,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ this.regularExpressionMatcher = new ClassNameMatcher(regularExpression);
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ if (accepted(programFieldInfo.getDescriptor(programClassFile)))
+ {
+ memberInfoVisitor.visitProgramFieldInfo(programClassFile, programFieldInfo);
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ if (accepted(programMethodInfo.getDescriptor(programClassFile)))
+ {
+ memberInfoVisitor.visitProgramMethodInfo(programClassFile, programMethodInfo);
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ if (accepted(libraryFieldInfo.getDescriptor(libraryClassFile)))
+ {
+ memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, libraryFieldInfo);
+ }
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ if (accepted(libraryMethodInfo.getDescriptor(libraryClassFile)))
+ {
+ memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private boolean accepted(String name)
+ {
+ return regularExpressionMatcher.matches(name);
+ }
+}
diff --git a/src/proguard/classfile/visitor/MemberInfoNameFilter.java b/src/proguard/classfile/visitor/MemberInfoNameFilter.java
new file mode 100644
index 0000000..1da77ed
--- /dev/null
+++ b/src/proguard/classfile/visitor/MemberInfoNameFilter.java
@@ -0,0 +1,99 @@
+/* $Id: MemberInfoNameFilter.java,v 1.9 2004/11/27 10:09:26 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.util.*;
+
+
+/**
+ * This <code>MemberInfoVisitor</code> delegates its visits to another given
+ * <code>MemberInfoVisitor</code>, but only when the visited member
+ * has a name that matches a given regular expression.
+ *
+ * @author Eric Lafortune
+ */
+public class MemberInfoNameFilter implements MemberInfoVisitor
+{
+ private StringMatcher regularExpressionMatcher;
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ /**
+ * Creates a new MemberInfoNameFilter.
+ * @param regularExpression the regular expression against which class names
+ * will be matched.
+ * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which visits
+ * will be delegated.
+ */
+ public MemberInfoNameFilter(String regularExpression,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ this.regularExpressionMatcher = new ClassNameMatcher(regularExpression);
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ if (accepted(programFieldInfo.getName(programClassFile)))
+ {
+ memberInfoVisitor.visitProgramFieldInfo(programClassFile, programFieldInfo);
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ if (accepted(programMethodInfo.getName(programClassFile)))
+ {
+ memberInfoVisitor.visitProgramMethodInfo(programClassFile, programMethodInfo);
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ if (accepted(libraryFieldInfo.getName(libraryClassFile)))
+ {
+ memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, libraryFieldInfo);
+ }
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ if (accepted(libraryMethodInfo.getName(libraryClassFile)))
+ {
+ memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private boolean accepted(String name)
+ {
+ return regularExpressionMatcher.matches(name);
+ }
+}
diff --git a/src/proguard/classfile/visitor/MemberInfoVisitor.java b/src/proguard/classfile/visitor/MemberInfoVisitor.java
new file mode 100644
index 0000000..1a36ebd
--- /dev/null
+++ b/src/proguard/classfile/visitor/MemberInfoVisitor.java
@@ -0,0 +1,40 @@
+/* $Id: MemberInfoVisitor.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>ProgramMemberInfo</code> objects and <code>LibraryMemberInfo</code>
+ * objects.
+ *
+ * @author Eric Lafortune
+ */
+public interface MemberInfoVisitor
+{
+ public void visitProgramFieldInfo( ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo);
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo);
+
+ public void visitLibraryFieldInfo( LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo);
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo);
+}
diff --git a/src/proguard/classfile/visitor/MultiClassFileVisitor.java b/src/proguard/classfile/visitor/MultiClassFileVisitor.java
new file mode 100644
index 0000000..ac6abc1
--- /dev/null
+++ b/src/proguard/classfile/visitor/MultiClassFileVisitor.java
@@ -0,0 +1,97 @@
+/* $Id: MultiClassFileVisitor.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This ClassFileVisitor delegates all visits to each ClassFileVisitor
+ * in a given list.
+ *
+ * @author Eric Lafortune
+ */
+public class MultiClassFileVisitor implements ClassFileVisitor
+{
+ private static final int ARRAY_SIZE_INCREMENT = 5;
+
+ private ClassFileVisitor[] classFileVisitors;
+ private int classFileVisitorCount;
+
+
+ public MultiClassFileVisitor()
+ {
+ }
+
+
+ public MultiClassFileVisitor(ClassFileVisitor[] classFileVisitors)
+ {
+ this.classFileVisitors = classFileVisitors;
+ this.classFileVisitorCount = classFileVisitors.length;
+ }
+
+
+ public void addClassFileVisitor(ClassFileVisitor classFileVisitor)
+ {
+ ensureArraySize();
+
+ classFileVisitors[classFileVisitorCount++] = classFileVisitor;
+ }
+
+
+ private void ensureArraySize()
+ {
+ if (classFileVisitors == null)
+ {
+ classFileVisitors = new ClassFileVisitor[ARRAY_SIZE_INCREMENT];
+ }
+ else if (classFileVisitors.length == classFileVisitorCount)
+ {
+ ClassFileVisitor[] newClassFileVisitors =
+ new ClassFileVisitor[classFileVisitorCount +
+ ARRAY_SIZE_INCREMENT];
+ System.arraycopy(classFileVisitors, 0,
+ newClassFileVisitors, 0,
+ classFileVisitorCount);
+ classFileVisitors = newClassFileVisitors;
+ }
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ for (int i = 0; i < classFileVisitorCount; i++)
+ {
+ classFileVisitors[i].visitProgramClassFile(programClassFile);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ for (int i = 0; i < classFileVisitorCount; i++)
+ {
+ classFileVisitors[i].visitLibraryClassFile(libraryClassFile);
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/MultiClassPoolVisitor.java b/src/proguard/classfile/visitor/MultiClassPoolVisitor.java
new file mode 100644
index 0000000..dbc3696
--- /dev/null
+++ b/src/proguard/classfile/visitor/MultiClassPoolVisitor.java
@@ -0,0 +1,88 @@
+/* $Id: MultiClassPoolVisitor.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This ClassPoolVisitor delegates all visits to each ClassPoolVisitor
+ * in a given list.
+ *
+ * @author Eric Lafortune
+ */
+public class MultiClassPoolVisitor implements ClassPoolVisitor
+{
+ private static final int ARRAY_SIZE_INCREMENT = 5;
+
+ private ClassPoolVisitor[] classPoolVisitors;
+ private int classPoolVisitorCount;
+
+
+ public MultiClassPoolVisitor()
+ {
+ }
+
+
+ public MultiClassPoolVisitor(ClassPoolVisitor[] classPoolVisitors)
+ {
+ this.classPoolVisitors = classPoolVisitors;
+ this.classPoolVisitorCount = classPoolVisitors.length;
+ }
+
+
+ public void addClassPoolVisitor(ClassPoolVisitor classPoolVisitor)
+ {
+ ensureArraySize();
+
+ classPoolVisitors[classPoolVisitorCount++] = classPoolVisitor;
+ }
+
+
+ private void ensureArraySize()
+ {
+ if (classPoolVisitors == null)
+ {
+ classPoolVisitors = new ClassPoolVisitor[ARRAY_SIZE_INCREMENT];
+ }
+ else if (classPoolVisitors.length == classPoolVisitorCount)
+ {
+ ClassPoolVisitor[] newClassPoolVisitors =
+ new ClassPoolVisitor[classPoolVisitorCount +
+ ARRAY_SIZE_INCREMENT];
+ System.arraycopy(classPoolVisitors, 0,
+ newClassPoolVisitors, 0,
+ classPoolVisitorCount);
+ classPoolVisitors = newClassPoolVisitors;
+ }
+ }
+
+
+ // Implementations for ClassPoolVisitor.
+
+ public void visitClassPool(ClassPool classPool)
+ {
+ for (int i = 0; i < classPoolVisitorCount; i++)
+ {
+ classPoolVisitors[i].visitClassPool(classPool);
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/MultiMemberInfoVisitor.java b/src/proguard/classfile/visitor/MultiMemberInfoVisitor.java
new file mode 100644
index 0000000..5f4dda1
--- /dev/null
+++ b/src/proguard/classfile/visitor/MultiMemberInfoVisitor.java
@@ -0,0 +1,113 @@
+/* $Id: MultiMemberInfoVisitor.java,v 1.11 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This MemberInfoVisitor delegates all visits to each MemberInfoVisitor
+ * in a given list.
+ *
+ * @author Eric Lafortune
+ */
+public class MultiMemberInfoVisitor implements MemberInfoVisitor
+{
+ private static final int ARRAY_SIZE_INCREMENT = 5;
+
+ private MemberInfoVisitor[] memberInfoVisitors;
+ private int memberInfoVisitorCount;
+
+
+ public MultiMemberInfoVisitor()
+ {
+ }
+
+
+ public MultiMemberInfoVisitor(MemberInfoVisitor[] memberInfoVisitors)
+ {
+ this.memberInfoVisitors = memberInfoVisitors;
+ this.memberInfoVisitorCount = memberInfoVisitors.length;
+ }
+
+
+ public void addMemberInfoVisitor(MemberInfoVisitor memberInfoVisitor)
+ {
+ ensureArraySize();
+
+ memberInfoVisitors[memberInfoVisitorCount++] = memberInfoVisitor;
+ }
+
+
+ private void ensureArraySize()
+ {
+ if (memberInfoVisitors == null)
+ {
+ memberInfoVisitors = new MemberInfoVisitor[ARRAY_SIZE_INCREMENT];
+ }
+ else if (memberInfoVisitors.length == memberInfoVisitorCount)
+ {
+ MemberInfoVisitor[] newMemberInfoVisitors =
+ new MemberInfoVisitor[memberInfoVisitorCount +
+ ARRAY_SIZE_INCREMENT];
+ System.arraycopy(memberInfoVisitors, 0,
+ newMemberInfoVisitors, 0,
+ memberInfoVisitorCount);
+ memberInfoVisitors = newMemberInfoVisitors;
+ }
+ }
+
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ for (int i = 0; i < memberInfoVisitorCount; i++)
+ {
+ memberInfoVisitors[i].visitProgramFieldInfo(programClassFile, programFieldInfo);
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ for (int i = 0; i < memberInfoVisitorCount; i++)
+ {
+ memberInfoVisitors[i].visitProgramMethodInfo(programClassFile, programMethodInfo);
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ for (int i = 0; i < memberInfoVisitorCount; i++)
+ {
+ memberInfoVisitors[i].visitLibraryFieldInfo(libraryClassFile, libraryFieldInfo);
+ }
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ for (int i = 0; i < memberInfoVisitorCount; i++)
+ {
+ memberInfoVisitors[i].visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/NamedClassFileVisitor.java b/src/proguard/classfile/visitor/NamedClassFileVisitor.java
new file mode 100644
index 0000000..550487c
--- /dev/null
+++ b/src/proguard/classfile/visitor/NamedClassFileVisitor.java
@@ -0,0 +1,55 @@
+/* $Id: NamedClassFileVisitor.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This class visits ClassFile objects with the given name.
+ *
+ * @author Eric Lafortune
+ */
+public class NamedClassFileVisitor implements ClassPoolVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+ private String name;
+
+
+ public NamedClassFileVisitor(ClassFileVisitor classFileVisitor,
+ String name)
+ {
+ this.classFileVisitor = classFileVisitor;
+ this.name = name;
+ }
+
+
+ public void visitClassPool(ClassPool classPool)
+ {
+ try
+ {
+ classPool.classFileAccept(classFileVisitor, name);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/NamedFieldVisitor.java b/src/proguard/classfile/visitor/NamedFieldVisitor.java
new file mode 100644
index 0000000..c1884db
--- /dev/null
+++ b/src/proguard/classfile/visitor/NamedFieldVisitor.java
@@ -0,0 +1,59 @@
+/* $Id: NamedFieldVisitor.java,v 1.11 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This class visits ProgramMemberInfo objects referring to fields, identified by
+ * a name and descriptor pair.
+ *
+ * @author Eric Lafortune
+ */
+public class NamedFieldVisitor implements ClassFileVisitor
+{
+ private String name;
+ private String descriptor;
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ public NamedFieldVisitor(String name,
+ String descriptor,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ this.name = name;
+ this.descriptor = descriptor;
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ programClassFile.fieldAccept(name, descriptor, memberInfoVisitor);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ libraryClassFile.fieldAccept(name, descriptor, memberInfoVisitor);
+ }
+}
diff --git a/src/proguard/classfile/visitor/NamedMethodVisitor.java b/src/proguard/classfile/visitor/NamedMethodVisitor.java
new file mode 100644
index 0000000..fdaed64
--- /dev/null
+++ b/src/proguard/classfile/visitor/NamedMethodVisitor.java
@@ -0,0 +1,59 @@
+/* $Id: NamedMethodVisitor.java,v 1.11 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This class visits ProgramMemberInfo objects referring to methods, identified by
+ * a name and descriptor pair.
+ *
+ * @author Eric Lafortune
+ */
+public class NamedMethodVisitor implements ClassFileVisitor
+{
+ private String name;
+ private String descriptor;
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ public NamedMethodVisitor(String name,
+ String descriptor,
+ MemberInfoVisitor memberInfoVisitor)
+ {
+ this.name = name;
+ this.descriptor = descriptor;
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ programClassFile.methodAccept(name, descriptor, memberInfoVisitor);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ libraryClassFile.methodAccept(name, descriptor, memberInfoVisitor);
+ }
+}
diff --git a/src/proguard/classfile/visitor/ProgramClassFileFilter.java b/src/proguard/classfile/visitor/ProgramClassFileFilter.java
new file mode 100644
index 0000000..b825e97
--- /dev/null
+++ b/src/proguard/classfile/visitor/ProgramClassFileFilter.java
@@ -0,0 +1,60 @@
+/* $Id: ProgramClassFileFilter.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> delegates its visits to another given
+ * <code>ClassFileVisitor</code>, but only when visiting program class files.
+ *
+ * @author Eric Lafortune
+ */
+public class ProgramClassFileFilter implements ClassFileVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+
+
+ /**
+ * Creates a new ProgramClassFileFilter.
+ * @param classFileVisitor the <code>ClassFileVisitor</code> to which visits
+ * will be delegated.
+ */
+ public ProgramClassFileFilter(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ classFileVisitor.visitProgramClassFile(programClassFile);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ // Don't delegate visits to library class files.
+ }
+}
diff --git a/src/proguard/classfile/visitor/ProgramMemberInfoFilter.java b/src/proguard/classfile/visitor/ProgramMemberInfoFilter.java
new file mode 100644
index 0000000..82a9cb5
--- /dev/null
+++ b/src/proguard/classfile/visitor/ProgramMemberInfoFilter.java
@@ -0,0 +1,73 @@
+/* $Id: ProgramMemberInfoFilter.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This <code>MemberInfoVisitor</code> delegates its visits to another given
+ * <code>MemberInfoVisitor</code>, but only when visiting members of program
+ * class files.
+ *
+ * @author Eric Lafortune
+ */
+public class ProgramMemberInfoFilter implements MemberInfoVisitor
+{
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ /**
+ * Creates a new ProgramMemberInfoFilter.
+ * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which
+ * visits will be delegated.
+ */
+ public ProgramMemberInfoFilter(MemberInfoVisitor memberInfoVisitor)
+ {
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ memberInfoVisitor.visitProgramFieldInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ memberInfoVisitor.visitProgramMethodInfo(programClassFile, programMethodInfo);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ // Don't delegate visits to library members.
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ // Don't delegate visits to library members.
+ }
+}
diff --git a/src/proguard/classfile/visitor/ReferencedClassFileVisitor.java b/src/proguard/classfile/visitor/ReferencedClassFileVisitor.java
new file mode 100644
index 0000000..12a89e5
--- /dev/null
+++ b/src/proguard/classfile/visitor/ReferencedClassFileVisitor.java
@@ -0,0 +1,110 @@
+/* $Id: ReferencedClassFileVisitor.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This CpInfoVisitor lets a given ClassFileVisitor visit all the referenced
+ * class files of the constant pool entries that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class ReferencedClassFileVisitor
+ implements CpInfoVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+
+
+ public ReferencedClassFileVisitor(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ visitReferencedClassFile(stringCpInfo.referencedClassFile);
+ }
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ visitReferencedClassFile(fieldrefCpInfo.referencedClassFile);
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ visitReferencedClassFile(interfaceMethodrefCpInfo.referencedClassFile);
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ visitReferencedClassFile(methodrefCpInfo.referencedClassFile);
+ }
+
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ visitReferencedClassFile(classCpInfo.referencedClassFile);
+ }
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ visitReferencedClassFiles(nameAndTypeCpInfo.referencedClassFiles);
+ }
+
+
+ // Small utility methods.
+
+ private void visitReferencedClassFiles(ClassFile[] referencedClassFiles)
+ {
+ if (referencedClassFiles != null)
+ {
+ for (int index = 0; index < referencedClassFiles.length; index++)
+ {
+ visitReferencedClassFile(referencedClassFiles[index]);
+ }
+ }
+ }
+
+
+ private void visitReferencedClassFile(ClassFile referencedClassFile)
+ {
+ if (referencedClassFile != null)
+ {
+ referencedClassFile.accept(classFileVisitor);
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/SimpleClassFilePrinter.java b/src/proguard/classfile/visitor/SimpleClassFilePrinter.java
new file mode 100644
index 0000000..c09ac46
--- /dev/null
+++ b/src/proguard/classfile/visitor/SimpleClassFilePrinter.java
@@ -0,0 +1,169 @@
+/* $Id: SimpleClassFilePrinter.java,v 1.17 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.optimize.*;
+import proguard.optimize.SideEffectMethodMarker;
+
+import java.io.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> and <code>MemberInfoVisitor</code>
+ * prints out the class names of the class files it visits, and the full class
+ * member descriptions of the class members it visits. The names are printed
+ * in a readable, Java-like format. The access modifiers can be included or not.
+ *
+ * @author Eric Lafortune
+ */
+public class SimpleClassFilePrinter
+ implements ClassFileVisitor,
+ MemberInfoVisitor
+{
+ private boolean printAccessModifiers;
+ private PrintStream ps;
+
+
+ /**
+ * Creates a new SimpleClassFilePrinter that prints to
+ * <code>System.out</code>, including the access modifiers.
+ */
+ public SimpleClassFilePrinter()
+ {
+ this(true);
+ }
+
+ /**
+ * Creates a new SimpleClassFilePrinter that prints to
+ * <code>System.out</code>, with or without the access modifiers.
+ */
+ public SimpleClassFilePrinter(boolean printAccessModifiers)
+ {
+ this(printAccessModifiers, System.out);
+ }
+
+ /**
+ * Creates a new SimpleClassFilePrinter that prints to the given
+ * <code>PrintStream</code>, with or without the access modifiers.
+ */
+ public SimpleClassFilePrinter(boolean printAccessModifiers,
+ PrintStream printStream)
+ {
+ this.printAccessModifiers = printAccessModifiers;
+ this.ps = printStream;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ ps.println(ClassUtil.externalFullClassDescription(
+ printAccessModifiers ?
+ programClassFile.getAccessFlags() :
+ 0,
+ programClassFile.getName()));
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ ps.println(ClassUtil.externalFullClassDescription(
+ printAccessModifiers ?
+ libraryClassFile.getAccessFlags() :
+ 0,
+ libraryClassFile.getName()));
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ ps.println(ClassUtil.externalFullClassDescription(
+ printAccessModifiers ?
+ programClassFile.getAccessFlags() :
+ 0,
+ programClassFile.getName()) +
+ ": " +
+ ClassUtil.externalFullFieldDescription(
+ printAccessModifiers ?
+ programFieldInfo.getAccessFlags() :
+ 0,
+ programFieldInfo.getName(programClassFile),
+ programFieldInfo.getDescriptor(programClassFile)));
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ ps.println(ClassUtil.externalFullClassDescription(
+ printAccessModifiers ?
+ programClassFile.getAccessFlags() :
+ 0,
+ programClassFile.getName()) +
+ ": " +
+ ClassUtil.externalFullMethodDescription(
+ programClassFile.getName(),
+ printAccessModifiers ?
+ programMethodInfo.getAccessFlags() :
+ 0,
+ programMethodInfo.getName(programClassFile),
+ programMethodInfo.getDescriptor(programClassFile)));
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ ps.println(ClassUtil.externalFullClassDescription(
+ printAccessModifiers ?
+ libraryClassFile.getAccessFlags() :
+ 0,
+ libraryClassFile.getName()) +
+ ": " +
+ ClassUtil.externalFullFieldDescription(
+ printAccessModifiers ?
+ libraryFieldInfo.getAccessFlags() :
+ 0,
+ libraryFieldInfo.getName(libraryClassFile),
+ libraryFieldInfo.getDescriptor(libraryClassFile)));
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ ps.println(ClassUtil.externalFullClassDescription(
+ printAccessModifiers ?
+ libraryClassFile.getAccessFlags() :
+ 0,
+ libraryClassFile.getName()) +
+ ": " +
+ ClassUtil.externalFullMethodDescription(
+ libraryClassFile.getName(),
+ printAccessModifiers ?
+ libraryMethodInfo.getAccessFlags() :
+ 0,
+ libraryMethodInfo.getName(libraryClassFile),
+ libraryMethodInfo.getDescriptor(libraryClassFile)));
+ }
+}
diff --git a/src/proguard/classfile/visitor/VariableClassFileVisitor.java b/src/proguard/classfile/visitor/VariableClassFileVisitor.java
new file mode 100644
index 0000000..ab555a8
--- /dev/null
+++ b/src/proguard/classfile/visitor/VariableClassFileVisitor.java
@@ -0,0 +1,78 @@
+/* $Id: VariableClassFileVisitor.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This ClassFileVisitor delegates all method calls to a ClassFileVisitor
+ * that can be changed at any time.
+ *
+ * @author Eric Lafortune
+ */
+public class VariableClassFileVisitor implements ClassFileVisitor
+{
+ private ClassFileVisitor classFileVisitor;
+
+
+ public VariableClassFileVisitor()
+ {
+ this(null);
+ }
+
+
+ public VariableClassFileVisitor(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ public void setClassFileVisitor(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+ public ClassFileVisitor getClassFileVisitor()
+ {
+ return classFileVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ if (classFileVisitor != null)
+ {
+ classFileVisitor.visitProgramClassFile(programClassFile);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ if (classFileVisitor != null)
+ {
+ classFileVisitor.visitLibraryClassFile(libraryClassFile);
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/VariableMemberInfoVisitor.java b/src/proguard/classfile/visitor/VariableMemberInfoVisitor.java
new file mode 100644
index 0000000..2fdeef3
--- /dev/null
+++ b/src/proguard/classfile/visitor/VariableMemberInfoVisitor.java
@@ -0,0 +1,96 @@
+/* $Id: VariableMemberInfoVisitor.java,v 1.11 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.visitor;
+
+import proguard.classfile.*;
+
+
+/**
+ * This MemberInfoVisitor delegates all method calls to a MemberInfoVisitor
+ * that can be changed at any time.
+ *
+ * @author Eric Lafortune
+ */
+public class VariableMemberInfoVisitor implements MemberInfoVisitor
+{
+ private MemberInfoVisitor memberInfoVisitor;
+
+
+ public VariableMemberInfoVisitor()
+ {
+ this(null);
+ }
+
+
+ public VariableMemberInfoVisitor(MemberInfoVisitor memberInfoVisitor)
+ {
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+
+ public void setMemberInfoVisitor(MemberInfoVisitor memberInfoVisitor)
+ {
+ this.memberInfoVisitor = memberInfoVisitor;
+ }
+
+ public MemberInfoVisitor getMemberInfoVisitor()
+ {
+ return memberInfoVisitor;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ if (memberInfoVisitor != null)
+ {
+ memberInfoVisitor.visitProgramFieldInfo(programClassFile, programFieldInfo);
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ if (memberInfoVisitor != null)
+ {
+ memberInfoVisitor.visitProgramMethodInfo(programClassFile, programMethodInfo);
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ if (memberInfoVisitor != null)
+ {
+ memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, libraryFieldInfo);
+ }
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ if (memberInfoVisitor != null)
+ {
+ memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
+ }
+ }
+}
diff --git a/src/proguard/classfile/visitor/package.html b/src/proguard/classfile/visitor/package.html
new file mode 100644
index 0000000..d3be40c
--- /dev/null
+++ b/src/proguard/classfile/visitor/package.html
@@ -0,0 +1,40 @@
+<body>
+This package contains interfaces and classes for processing class files from
+the <code>{@link proguard.classfile proguard.classfile}</code> package using
+the <i>visitor pattern</i>. Cfr., for instance, "Design Patterns, Elements of
+Reusable OO Software", by Gamma, Helm, Johnson, and Vlissider.
+<p>
+Why the visitor pattern? Class files frequently contain lists of elements of
+various mixed types: class items, constant pool entries, attributes,...
+These lists and types are largely fixed; they won't change much in future
+releases of the Java class file specifications. On the other hand, the kinds
+of operations that we may wish to perform on the class files may change and
+expand. We want to separate the objects and the operations performed upon them.
+This is a good place to use the visitor pattern.
+<p>
+Visitor interfaces avoid having to do series of <code>instanceof</code> tests
+on the elements of a list, followed by type casts and the proper operations.
+Every list element is a visitor accepter. When its <code>accept</code> method
+is called by a visitor, it calls its corresponding <code>visitX</code> method
+in the visitor, passing itself as an argument. This technique is called
+double-dispatch.
+<p>
+As already mentioned, the main advantage is avoiding lots of
+<code>instanceof</code> tests and type casts. Also, implementing a visitor
+interface ensures you're handling all possible visitor accepter types. Each
+type has its own method, which you simply have to implement.
+<p>
+A disadvantage is that the visitor methods always get the same names, specified
+by the visitor interface. These names aren't descriptive at all, making code
+harder to read. It's the visitor classes that describe the operations now.
+<p>
+Also, the visitor methods always have the same parameters and return values, as
+specified by the visitor interfaces. Passing additional parameters is done by
+means of extra fields in the visitor, which is somewhat of a kludge.
+<p>
+Because objects (the visitor accepters) and the operations performed upon them
+(the visitors) are now separated, it becomes harder to associate some state
+with the objects. For convenience, we always provide an extra <i>visitor
+info</i> field in visitor accepters, in which visitors can put any temporary
+information they want.
+</body>
diff --git a/src/proguard/gui/ClassMemberSpecificationDialog.java b/src/proguard/gui/ClassMemberSpecificationDialog.java
new file mode 100644
index 0000000..6777bff
--- /dev/null
+++ b/src/proguard/gui/ClassMemberSpecificationDialog.java
@@ -0,0 +1,416 @@
+/* $Id: ClassMemberSpecificationDialog.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.border.Border;
+
+import proguard.*;
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.util.*;
+
+/**
+ * This <code>JDialog</code> allows the user to enter a String.
+ *
+ * @author Eric Lafortune
+ */
+class ClassMemberSpecificationDialog extends JDialog
+{
+ /**
+ * Return value if the dialog is canceled (with the Cancel button or by
+ * closing the dialog window).
+ */
+ public static final int CANCEL_OPTION = 1;
+
+ /**
+ * Return value if the dialog is approved (with the Ok button).
+ */
+ public static final int APPROVE_OPTION = 0;
+
+
+ private boolean isField;
+
+ private JRadioButton[] publicRadioButtons;
+ private JRadioButton[] privateRadioButtons;
+ private JRadioButton[] protectedRadioButtons;
+ private JRadioButton[] staticRadioButtons;
+ private JRadioButton[] finalRadioButtons;
+
+ private JRadioButton[] volatileRadioButtons;
+ private JRadioButton[] transientRadioButtons;
+
+ private JRadioButton[] synchronizedRadioButtons;
+ private JRadioButton[] nativeRadioButtons;
+ private JRadioButton[] abstractRadioButtons;
+ private JRadioButton[] strictRadioButtons;
+
+ private JTextField nameTextField = new JTextField(20);
+ private JTextField typeTextField = new JTextField(20);
+ private JTextField argumentsTextField = new JTextField(20);
+ private int returnValue;
+
+
+ public ClassMemberSpecificationDialog(JDialog owner, boolean isField)
+ {
+ super(owner, true);
+ setResizable(true);
+
+ // Create some constraints that can be reused.
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(1, 2, 1, 2);
+
+ GridBagConstraints constraintsStretch = new GridBagConstraints();
+ constraintsStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsStretch.weightx = 1.0;
+ constraintsStretch.anchor = GridBagConstraints.WEST;
+ constraintsStretch.insets = constraints.insets;
+
+ GridBagConstraints constraintsLast = new GridBagConstraints();
+ constraintsLast.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLast.anchor = GridBagConstraints.WEST;
+ constraintsLast.insets = constraints.insets;
+
+ GridBagConstraints constraintsLastStretch = new GridBagConstraints();
+ constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsLastStretch.weightx = 1.0;
+ constraintsLastStretch.anchor = GridBagConstraints.WEST;
+ constraintsLastStretch.insets = constraints.insets;
+
+ GridBagConstraints panelConstraints = new GridBagConstraints();
+ panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ panelConstraints.fill = GridBagConstraints.HORIZONTAL;
+ panelConstraints.weightx = 1.0;
+ panelConstraints.weighty = 0.0;
+ panelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ panelConstraints.insets = constraints.insets;
+
+ GridBagConstraints stretchPanelConstraints = new GridBagConstraints();
+ stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ stretchPanelConstraints.fill = GridBagConstraints.BOTH;
+ stretchPanelConstraints.weightx = 1.0;
+ stretchPanelConstraints.weighty = 1.0;
+ stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ stretchPanelConstraints.insets = constraints.insets;
+
+ GridBagConstraints labelConstraints = new GridBagConstraints();
+ labelConstraints.anchor = GridBagConstraints.CENTER;
+ labelConstraints.insets = new Insets(2, 10, 2, 10);
+
+ GridBagConstraints lastLabelConstraints = new GridBagConstraints();
+ lastLabelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ lastLabelConstraints.anchor = GridBagConstraints.CENTER;
+ lastLabelConstraints.insets = labelConstraints.insets;
+
+ GridBagConstraints okButtonConstraints = new GridBagConstraints();
+ okButtonConstraints.weightx = 1.0;
+ okButtonConstraints.weighty = 1.0;
+ okButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ okButtonConstraints.insets = new Insets(4, 4, 8, 4);
+
+ GridBagConstraints cancelButtonConstraints = new GridBagConstraints();
+ cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;;
+ cancelButtonConstraints.weighty = 1.0;
+ cancelButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ cancelButtonConstraints.insets = okButtonConstraints.insets;
+
+ GridBagLayout layout = new GridBagLayout();
+
+ Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
+
+ this.isField = isField;
+
+ // Create the access panel.
+ JPanel accessPanel = new JPanel(layout);
+ accessPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("access")));
+
+ accessPanel.add(Box.createGlue(), labelConstraints);
+ accessPanel.add(new JLabel(GUIResources.getMessage("required")), labelConstraints);
+ accessPanel.add(new JLabel(GUIResources.getMessage("not")), labelConstraints);
+ accessPanel.add(new JLabel(GUIResources.getMessage("dontCare")), labelConstraints);
+ accessPanel.add(Box.createGlue(), constraintsLastStretch);
+
+ publicRadioButtons = addRadioButtonTriplet("Public", accessPanel);
+ privateRadioButtons = addRadioButtonTriplet("Private", accessPanel);
+ protectedRadioButtons = addRadioButtonTriplet("Protected", accessPanel);
+ staticRadioButtons = addRadioButtonTriplet("Static", accessPanel);
+ finalRadioButtons = addRadioButtonTriplet("Final", accessPanel);
+
+ if (isField)
+ {
+ volatileRadioButtons = addRadioButtonTriplet("Volatile", accessPanel);
+ transientRadioButtons = addRadioButtonTriplet("Transient", accessPanel);
+ }
+ else
+ {
+ synchronizedRadioButtons = addRadioButtonTriplet("Synchronized", accessPanel);
+ nativeRadioButtons = addRadioButtonTriplet("Native", accessPanel);
+ abstractRadioButtons = addRadioButtonTriplet("Abstract", accessPanel);
+ strictRadioButtons = addRadioButtonTriplet("Strict", accessPanel);
+ }
+
+ // Create the type panel.
+ JPanel typePanel = new JPanel(layout);
+ typePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("returnType")));
+
+ typePanel.add(typeTextField, constraintsLastStretch);
+
+ // Create the name panel.
+ JPanel namePanel = new JPanel(layout);
+ namePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("name")));
+
+ namePanel.add(nameTextField, constraintsLastStretch);
+
+ // Create the arguments panel.
+ JPanel argumentsPanel = new JPanel(layout);
+ argumentsPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("arguments")));
+
+ argumentsPanel.add(argumentsTextField, constraintsLastStretch);
+
+ // Create the Ok button.
+ JButton okButton = new JButton(GUIResources.getMessage("ok"));
+ okButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ returnValue = APPROVE_OPTION;
+ hide();
+ }
+ });
+
+ // Create the Cancel button.
+ JButton cancelButton = new JButton(GUIResources.getMessage("cancel"));
+ cancelButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ hide();
+ }
+ });
+
+ // Add all panels to the main panel.
+ JPanel mainPanel = new JPanel(layout);
+ mainPanel.add(accessPanel, panelConstraints);
+ mainPanel.add(typePanel, panelConstraints);
+ mainPanel.add(namePanel, panelConstraints);
+
+ if (!isField)
+ {
+ mainPanel.add(argumentsPanel, panelConstraints);
+ }
+
+ mainPanel.add(okButton, okButtonConstraints);
+ mainPanel.add(cancelButton, cancelButtonConstraints);
+
+ getContentPane().add(mainPanel);
+ }
+
+
+ /**
+ * Adds a JLabel and three JRadioButton instances in a ButtonGroup to the
+ * given panel with a GridBagLayout, and returns the buttons in an array.
+ */
+ private JRadioButton[] addRadioButtonTriplet(String labelText,
+ JPanel panel)
+ {
+ GridBagConstraints labelConstraints = new GridBagConstraints();
+ labelConstraints.anchor = GridBagConstraints.WEST;
+ labelConstraints.insets = new Insets(2, 10, 2, 10);
+
+ GridBagConstraints buttonConstraints = new GridBagConstraints();
+ buttonConstraints.insets = labelConstraints.insets;
+
+ GridBagConstraints lastGlueConstraints = new GridBagConstraints();
+ lastGlueConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ lastGlueConstraints.weightx = 1.0;
+
+ // Create the radio buttons.
+ JRadioButton radioButton0 = new JRadioButton();
+ JRadioButton radioButton1 = new JRadioButton();
+ JRadioButton radioButton2 = new JRadioButton();
+
+ // Put them in a button group.
+ ButtonGroup buttonGroup = new ButtonGroup();
+ buttonGroup.add(radioButton0);
+ buttonGroup.add(radioButton1);
+ buttonGroup.add(radioButton2);
+
+ // Add the label and the buttons to the panel.
+ panel.add(new JLabel(labelText), labelConstraints);
+ panel.add(radioButton0, buttonConstraints);
+ panel.add(radioButton1, buttonConstraints);
+ panel.add(radioButton2, buttonConstraints);
+ panel.add(Box.createGlue(), lastGlueConstraints);
+
+ return new JRadioButton[]
+ {
+ radioButton0,
+ radioButton1,
+ radioButton2
+ };
+ }
+
+
+ /**
+ * Sets the ClassMemberSpecification to be represented in this dialog.
+ */
+ public void setClassMemberSpecification(ClassMemberSpecification classMemberSpecification)
+ {
+ String name = classMemberSpecification.name;
+ String descriptor = classMemberSpecification.descriptor;
+
+ // Set the access radio buttons.
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_PRIVATE, privateRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons);
+ setClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons);
+
+ // Set the class name text fields.
+ nameTextField.setText(name == null ? "" : name);
+
+ if (isField)
+ {
+ typeTextField .setText(descriptor == null ? "" : ClassUtil.externalType(descriptor));
+ }
+ else
+ {
+ typeTextField .setText(descriptor == null ? "" : ClassUtil.externalMethodReturnType(descriptor));
+ argumentsTextField.setText(descriptor == null ? "" : ClassUtil.externalMethodArguments(descriptor));
+ }
+ }
+
+
+ /**
+ * Returns the ClassMemberSpecification currently represented in this dialog.
+ */
+ public ClassMemberSpecification getClassMemberSpecification()
+ {
+ String name = nameTextField.getText();
+ String type = typeTextField.getText();
+ String arguments = argumentsTextField.getText();
+
+ boolean fullWildcard = name.equals("") ||
+ type.equals("");
+
+ ClassMemberSpecification classMemberSpecification = fullWildcard ?
+ new ClassMemberSpecification(0,
+ 0,
+ null,
+ null) :
+ new ClassMemberSpecification(0,
+ 0,
+ name,
+ isField ? ClassUtil.internalType(type) :
+ ClassUtil.internalMethodDescriptor(type, ListUtil.commaSeparatedList(arguments)));
+
+ // Also get the access radio button settings.
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_PRIVATE, privateRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons);
+ getClassMemberSpecificationRadioButtons(classMemberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons);
+
+ return classMemberSpecification;
+ }
+
+
+ /**
+ * Shows this dialog. This method only returns when the dialog is closed.
+ *
+ * @return <code>CANCEL_OPTION</code> or <code>APPROVE_OPTION</code>,
+ * depending on the choice of the user.
+ */
+ public int showDialog()
+ {
+ returnValue = CANCEL_OPTION;
+
+ // Open the dialog in the right place, then wait for it to be closed,
+ // one way or another.
+ pack();
+ setLocationRelativeTo(getOwner());
+ show();
+
+ return returnValue;
+ }
+
+
+ /**
+ * Sets the appropriate radio button of a given triplet, based on the access
+ * flags of the given keep option.
+ */
+ private void setClassMemberSpecificationRadioButtons(ClassMemberSpecification classMemberSpecification,
+ int flag,
+ JRadioButton[] radioButtons)
+ {
+ if (radioButtons != null)
+ {
+ int index = (classMemberSpecification.requiredSetAccessFlags & flag) != 0 ? 0 :
+ (classMemberSpecification.requiredUnsetAccessFlags & flag) != 0 ? 1 :
+ 2;
+ radioButtons[index].setSelected(true);
+ }
+ }
+
+
+ /**
+ * Updates the access flag of the given keep option, based on the given radio
+ * button triplet.
+ */
+ private void getClassMemberSpecificationRadioButtons(ClassMemberSpecification classMemberSpecification,
+ int flag,
+ JRadioButton[] radioButtons)
+ {
+ if (radioButtons != null)
+ {
+ if (radioButtons[0].isSelected())
+ {
+ classMemberSpecification.requiredSetAccessFlags |= flag;
+ }
+ else if (radioButtons[1].isSelected())
+ {
+ classMemberSpecification.requiredUnsetAccessFlags |= flag;
+ }
+ }
+ }
+}
diff --git a/src/proguard/gui/ClassMemberSpecificationsPanel.java b/src/proguard/gui/ClassMemberSpecificationsPanel.java
new file mode 100644
index 0000000..4d34fed
--- /dev/null
+++ b/src/proguard/gui/ClassMemberSpecificationsPanel.java
@@ -0,0 +1,268 @@
+/* $Id: ClassMemberSpecificationsPanel.java,v 1.5 2004/08/28 22:50:49 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import proguard.*;
+import proguard.classfile.util.ClassUtil;
+
+import java.awt.Component;
+import java.awt.event.*;
+import java.util.*;
+
+import javax.swing.*;
+
+
+/**
+ * This <code>ListPanel</code> allows the user to add, edit, move, and remove
+ * ClassMemberSpecification entries in a list.
+ *
+ * @author Eric Lafortune
+ */
+class ClassMemberSpecificationsPanel extends ListPanel
+{
+ private ClassMemberSpecificationDialog fieldSpecificationDialog;
+ private ClassMemberSpecificationDialog methodSpecificationDialog;
+
+
+ public ClassMemberSpecificationsPanel(JDialog owner, boolean fullKeepOptions)
+ {
+ super();
+
+ super.firstSelectionButton = fullKeepOptions ? 3 : 2;
+
+ list.setCellRenderer(new MyListCellRenderer());
+
+ fieldSpecificationDialog = new ClassMemberSpecificationDialog(owner, true);
+ methodSpecificationDialog = new ClassMemberSpecificationDialog(owner, false);
+
+ if (fullKeepOptions)
+ {
+ addAddFieldButton();
+ }
+ addAddMethodButton();
+ addEditButton();
+ addRemoveButton();
+ addUpButton();
+ addDownButton();
+
+ enableSelectionButtons();
+ }
+
+
+ protected void addAddFieldButton()
+ {
+ JButton addFieldButton = new JButton(GUIResources.getMessage("addField"));
+ addFieldButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ fieldSpecificationDialog.setClassMemberSpecification(new ClassMemberSpecification());
+ int returnValue = fieldSpecificationDialog.showDialog();
+ if (returnValue == ClassMemberSpecificationDialog.APPROVE_OPTION)
+ {
+ // Add the new element.
+ addElement(new MyClassMemberSpecificationWrapper(fieldSpecificationDialog.getClassMemberSpecification(),
+ true));
+ }
+ }
+ });
+
+ addButton(addFieldButton);
+ }
+
+
+ protected void addAddMethodButton()
+ {
+ JButton addMethodButton = new JButton(GUIResources.getMessage("addMethod"));
+ addMethodButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ methodSpecificationDialog.setClassMemberSpecification(new ClassMemberSpecification());
+ int returnValue = methodSpecificationDialog.showDialog();
+ if (returnValue == ClassMemberSpecificationDialog.APPROVE_OPTION)
+ {
+ // Add the new element.
+ addElement(new MyClassMemberSpecificationWrapper(methodSpecificationDialog.getClassMemberSpecification(),
+ false));
+ }
+ }
+ });
+
+ addButton(addMethodButton);
+ }
+
+
+ protected void addEditButton()
+ {
+ JButton editButton = new JButton(GUIResources.getMessage("edit"));
+ editButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ MyClassMemberSpecificationWrapper wrapper =
+ (MyClassMemberSpecificationWrapper)list.getSelectedValue();
+
+ ClassMemberSpecificationDialog classMemberSpecificationDialog =
+ wrapper.isField ?
+ fieldSpecificationDialog :
+ methodSpecificationDialog;
+
+ classMemberSpecificationDialog.setClassMemberSpecification(wrapper.classMemberSpecification);
+ int returnValue = classMemberSpecificationDialog.showDialog();
+ if (returnValue == ClassMemberSpecificationDialog.APPROVE_OPTION)
+ {
+ // Replace the old element.
+ wrapper.classMemberSpecification = classMemberSpecificationDialog.getClassMemberSpecification();
+ setElementAt(wrapper,
+ list.getSelectedIndex());
+ }
+ }
+ });
+
+ addButton(editButton);
+ }
+
+
+ /**
+ * Sets the ClassMemberSpecification instances to be represented in this panel.
+ */
+ public void setClassMemberSpecifications(List fieldSpecifications,
+ List methodSpecifications)
+ {
+ listModel.clear();
+
+ if (fieldSpecifications != null)
+ {
+ for (int index = 0; index < fieldSpecifications.size(); index++)
+ {
+ listModel.addElement(
+ new MyClassMemberSpecificationWrapper((ClassMemberSpecification)fieldSpecifications.get(index),
+ true));
+ }
+ }
+
+ if (methodSpecifications != null)
+ {
+ for (int index = 0; index < methodSpecifications.size(); index++)
+ {
+ listModel.addElement(
+ new MyClassMemberSpecificationWrapper((ClassMemberSpecification)methodSpecifications.get(index),
+ false));
+ }
+ }
+
+ // Make sure the selection buttons are properly enabled,
+ // since the clear method doesn't seem to notify the listener.
+ enableSelectionButtons();
+ }
+
+
+ /**
+ * Returns the ClassMemberSpecification instances currently represented in
+ * this panel, referring to fields or to methods.
+ *
+ * @param isField specifies whether specifications referring to fields or
+ * specifications referring to methods should be returned.
+ */
+ public List getClassMemberSpecifications(boolean isField)
+ {
+ int size = listModel.size();
+ if (size == 0)
+ {
+ return null;
+ }
+
+ List classMemberSpecifcations = new ArrayList(size);
+ for (int index = 0; index < size; index++)
+ {
+ MyClassMemberSpecificationWrapper wrapper =
+ (MyClassMemberSpecificationWrapper)listModel.get(index);
+
+ if (wrapper.isField == isField)
+ {
+ classMemberSpecifcations.add(wrapper.classMemberSpecification);
+ }
+ }
+
+ return classMemberSpecifcations;
+ }
+
+
+ /**
+ * This ListCellRenderer renders ClassMemberSpecification objects.
+ */
+ private static class MyListCellRenderer implements ListCellRenderer
+ {
+ JLabel label = new JLabel();
+
+
+ // Implementations for ListCellRenderer.
+
+ public Component getListCellRendererComponent(JList list,
+ Object value,
+ int index,
+ boolean isSelected,
+ boolean cellHasFocus)
+ {
+ MyClassMemberSpecificationWrapper wrapper = (MyClassMemberSpecificationWrapper)value;
+
+ ClassMemberSpecification option = wrapper.classMemberSpecification;
+ String name = option.name;
+ label.setText(wrapper.isField ?
+ (name == null ? "<fields>" : ClassUtil.externalFullFieldDescription(0, option.name, option.descriptor)) :
+ (name == null ? "<methods>" : ClassUtil.externalFullMethodDescription("<init>", 0, option.name, option.descriptor)));
+
+ if (isSelected)
+ {
+ label.setBackground(list.getSelectionBackground());
+ label.setForeground(list.getSelectionForeground());
+ }
+ else
+ {
+ label.setBackground(list.getBackground());
+ label.setForeground(list.getForeground());
+ }
+
+ label.setOpaque(true);
+
+ return label;
+ }
+ }
+
+
+ /**
+ * This class wraps a ClassMemberSpecification, additionally storing whether
+ * the option refers to a field or to a method.
+ */
+ private static class MyClassMemberSpecificationWrapper
+ {
+ public ClassMemberSpecification classMemberSpecification;
+ public boolean isField;
+
+ public MyClassMemberSpecificationWrapper(ClassMemberSpecification classMemberSpecification,
+ boolean isField)
+ {
+ this.classMemberSpecification = classMemberSpecification;
+ this.isField = isField;
+ }
+ }
+}
diff --git a/src/proguard/gui/ClassPathPanel.java b/src/proguard/gui/ClassPathPanel.java
new file mode 100644
index 0000000..a15d1f5
--- /dev/null
+++ b/src/proguard/gui/ClassPathPanel.java
@@ -0,0 +1,415 @@
+/* $Id: ClassPathPanel.java,v 1.14 2004/08/21 21:35:28 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+
+import javax.swing.*;
+
+import proguard.*;
+
+/**
+ * This <code>ListPanel</code> allows the user to add, edit, filter, move, and
+ * remove ClassPathEntry objects in a ClassPath object.
+ *
+ * @author Eric Lafortune
+ */
+class ClassPathPanel extends ListPanel
+{
+ private JFrame owner;
+ private boolean inputAndOutput;
+ private JFileChooser chooser;
+ private FilterDialog filterDialog;
+
+
+ public ClassPathPanel(JFrame owner, boolean inputAndOutput)
+ {
+ super();
+
+ super.firstSelectionButton = inputAndOutput ? 3 : 2;
+
+ this.owner = owner;
+ this.inputAndOutput = inputAndOutput;
+
+ list.setCellRenderer(new MyListCellRenderer());
+
+ chooser = new JFileChooser("");
+ chooser.setMultiSelectionEnabled(true);
+ chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+ chooser.addChoosableFileFilter(
+ new ExtensionFileFilter(GUIResources.getMessage("jarWarEarZipExtensions"),
+ new String[] { ".jar", ".war", ".ear", ".zip" }));
+ chooser.setApproveButtonText(GUIResources.getMessage("ok"));
+
+ filterDialog = new FilterDialog(owner, GUIResources.getMessage("enterFilter"));
+
+ addAddButton(inputAndOutput, false);
+ if (inputAndOutput)
+ {
+ addAddButton(inputAndOutput, true);
+ }
+ addEditButton();
+ addFilterButton();
+ addRemoveButton();
+ addUpButton();
+ addDownButton();
+
+ enableSelectionButtons();
+ }
+
+
+ protected void addAddButton(boolean inputAndOutput,
+ final boolean isOutput)
+ {
+ JButton addButton = new JButton(GUIResources.getMessage(inputAndOutput ?
+ isOutput ? "addOutput" :
+ "addInput" :
+ "add"));
+ addButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ chooser.setDialogTitle(GUIResources.getMessage("addJars"));
+ chooser.setSelectedFile(null);
+ chooser.setSelectedFiles(null);
+
+ int returnValue = chooser.showOpenDialog(owner);
+ if (returnValue == JFileChooser.APPROVE_OPTION)
+ {
+ File[] selectedFiles = chooser.getSelectedFiles();
+ ClassPathEntry[] entries = classPathEntries(selectedFiles, isOutput);
+
+ // Add the new elements.
+ addElements(entries);
+ }
+ }
+ });
+
+ addButton(addButton);
+ }
+
+
+ protected void addEditButton()
+ {
+ JButton editButton = new JButton(GUIResources.getMessage("edit"));
+ editButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ boolean isOutput = false;
+
+ int[] selectedIndices = list.getSelectedIndices();
+
+ // Copy the Object array into a File array.
+ File[] selectedFiles = new File[selectedIndices.length];
+ for (int index = 0; index < selectedFiles.length; index++)
+ {
+ ClassPathEntry entry =
+ (ClassPathEntry)listModel.getElementAt(selectedIndices[index]);
+
+ isOutput = entry.isOutput();
+
+ selectedFiles[index] = new File(entry.getName());
+ }
+
+ chooser.setDialogTitle(GUIResources.getMessage("chooseJars"));
+
+ // Up to JDK 1.3.1, setSelectedFiles doesn't show in the file
+ // chooser, so we just use setSelectedFile first. It also sets
+ // the current directory.
+ chooser.setSelectedFile(selectedFiles[0]);
+ chooser.setSelectedFiles(selectedFiles);
+
+ int returnValue = chooser.showOpenDialog(owner);
+ if (returnValue == JFileChooser.APPROVE_OPTION)
+ {
+ selectedFiles = chooser.getSelectedFiles();
+ ClassPathEntry[] entries = classPathEntries(selectedFiles, isOutput);
+
+ // If there are the same number of files selected now as
+ // there were before, we can just replace the old ones.
+ if (selectedIndices.length == selectedFiles.length)
+ {
+ // Replace the old elements.
+ setElementsAt(entries, selectedIndices);
+ }
+ else
+ {
+ // Remove the old elements.
+ removeElementsAt(selectedIndices);
+
+ // Add the new elements.
+ addElements(entries);
+ }
+ }
+ }
+ });
+
+ addButton(editButton);
+ }
+
+
+ protected void addFilterButton()
+ {
+ JButton filterButton = new JButton(GUIResources.getMessage("filter"));
+ filterButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (!list.isSelectionEmpty())
+ {
+ int[] selectedIndices = list.getSelectedIndices();
+
+ // Put the filters of the first selected entry in the dialog.
+ getFiltersFrom(selectedIndices[0]);
+
+ int returnValue = filterDialog.showDialog();
+ if (returnValue == FilterDialog.APPROVE_OPTION)
+ {
+ // Apply the entered filters to all selected entries.
+ setFiltersAt(selectedIndices);
+ }
+ }
+ }
+ });
+
+ addButton(filterButton);
+ }
+
+
+ /**
+ * Sets the ClassPath to be represented in this panel.
+ */
+ public void setClassPath(ClassPath classPath)
+ {
+ listModel.clear();
+
+ if (classPath != null)
+ {
+ for (int index = 0; index < classPath.size(); index++)
+ {
+ listModel.addElement(classPath.get(index));
+ }
+ }
+
+ // Make sure the selection buttons are properly enabled,
+ // since the clear method doesn't seem to notify the listener.
+ enableSelectionButtons();
+ }
+
+
+ /**
+ * Returns the ClassPath currently represented in this panel.
+ */
+ public ClassPath getClassPath()
+ {
+ int size = listModel.size();
+ if (size == 0)
+ {
+ return null;
+ }
+
+ ClassPath classPath = new ClassPath();
+ for (int index = 0; index < size; index++)
+ {
+ classPath.add((ClassPathEntry)listModel.get(index));
+ }
+
+ return classPath;
+ }
+
+
+ /**
+ * Converts the given array of File objects into a corresponding array of
+ * ClassPathEntry objects.
+ */
+ private ClassPathEntry[] classPathEntries(File[] files, boolean isOutput)
+ {
+ ClassPathEntry[] entries = new ClassPathEntry[files.length];
+ for (int index = 0; index < entries.length; index++)
+ {
+ entries[index] = new ClassPathEntry(files[index].toString(), isOutput);
+ }
+ return entries;
+ }
+
+
+ /**
+ * Sets up the filter dialog with the filters from the specified class path
+ * entry.
+ */
+ private void getFiltersFrom(int index)
+ {
+ ClassPathEntry firstEntry = (ClassPathEntry)listModel.get(index);
+
+ filterDialog.setFilter(firstEntry.getFilter());
+ filterDialog.setJarFilter(firstEntry.getJarFilter());
+ filterDialog.setWarFilter(firstEntry.getWarFilter());
+ filterDialog.setEarFilter(firstEntry.getEarFilter());
+ filterDialog.setZipFilter(firstEntry.getZipFilter());
+ }
+
+
+ /**
+ * Applies the entered filter to the specified class path entries.
+ * Any previously set filters are discarded.
+ */
+ private void setFiltersAt(int[] indices)
+ {
+ for (int index = indices.length - 1; index >= 0; index--)
+ {
+ ClassPathEntry entry = (ClassPathEntry)listModel.get(indices[index]);
+ entry.setFilter(filterDialog.getFilter());
+ entry.setJarFilter(filterDialog.getJarFilter());
+ entry.setWarFilter(filterDialog.getWarFilter());
+ entry.setEarFilter(filterDialog.getEarFilter());
+ entry.setZipFilter(filterDialog.getZipFilter());
+ }
+
+ // Make sure they are selected and thus repainted.
+ list.setSelectedIndices(indices);
+ }
+
+
+ /**
+ * This ListCellRenderer renders ClassPathEntry objects.
+ */
+ private class MyListCellRenderer implements ListCellRenderer
+ {
+ private static final String ARROW_IMAGE_FILE = "arrow.gif";
+
+ private JPanel cellPanel = new JPanel(new GridBagLayout());
+ private JLabel iconLabel = new JLabel("", JLabel.RIGHT);
+ private JLabel jarNameLabel = new JLabel("", JLabel.RIGHT);
+ private JLabel filterLabel = new JLabel("", JLabel.RIGHT);
+
+ private Icon arrowIcon;
+
+
+ public MyListCellRenderer()
+ {
+ GridBagConstraints jarNameLabelConstraints = new GridBagConstraints();
+ jarNameLabelConstraints.anchor = GridBagConstraints.WEST;
+ jarNameLabelConstraints.insets = new Insets(1, 2, 1, 2);
+
+ GridBagConstraints filterLabelConstraints = new GridBagConstraints();
+ filterLabelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ filterLabelConstraints.fill = GridBagConstraints.HORIZONTAL;
+ filterLabelConstraints.weightx = 1.0;
+ filterLabelConstraints.anchor = GridBagConstraints.EAST;
+ filterLabelConstraints.insets = jarNameLabelConstraints.insets;
+
+ arrowIcon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource(ARROW_IMAGE_FILE)));
+
+ cellPanel.add(iconLabel, jarNameLabelConstraints);
+ cellPanel.add(jarNameLabel, jarNameLabelConstraints);
+ cellPanel.add(filterLabel, filterLabelConstraints);
+ }
+
+
+ // Implementations for ListCellRenderer.
+
+ public Component getListCellRendererComponent(JList list,
+ Object value,
+ int index,
+ boolean isSelected,
+ boolean cellHasFocus)
+ {
+ ClassPathEntry entry = (ClassPathEntry)value;
+
+ // Prepend an arrow to the output entries.
+ if (inputAndOutput && entry.isOutput())
+ {
+ iconLabel.setIcon(arrowIcon);
+ }
+ else
+ {
+ iconLabel.setIcon(null);
+ }
+
+ // Set the entry name text.
+ jarNameLabel.setText(entry.getName());
+
+ // Set the filter text.
+ StringBuffer filter = null;
+ filter = appendFilter(filter, entry.getZipFilter());
+ filter = appendFilter(filter, entry.getEarFilter());
+ filter = appendFilter(filter, entry.getWarFilter());
+ filter = appendFilter(filter, entry.getJarFilter());
+ filter = appendFilter(filter, entry.getFilter());
+
+ if (filter != null)
+ {
+ filter.append(')');
+ }
+
+ filterLabel.setText(filter != null ? filter.toString() : "");
+
+ // Set the colors.
+ if (isSelected)
+ {
+ cellPanel.setBackground(list.getSelectionBackground());
+ jarNameLabel.setForeground(list.getSelectionForeground());
+ filterLabel.setForeground(list.getSelectionForeground());
+ }
+ else
+ {
+ cellPanel.setBackground(list.getBackground());
+ jarNameLabel.setForeground(list.getForeground());
+ filterLabel.setForeground(list.getForeground());
+ }
+
+ // Make the font color red if this is an input file that can't be read.
+ if (!(inputAndOutput && entry.isOutput()) &&
+ !new File(entry.getName()).canRead())
+ {
+ jarNameLabel.setForeground(Color.red);
+ }
+
+ cellPanel.setOpaque(true);
+
+ return cellPanel;
+ }
+
+
+ private StringBuffer appendFilter(StringBuffer filter, String additionalFilter)
+ {
+ if (filter != null)
+ {
+ filter.append(';');
+ }
+
+ if (additionalFilter != null)
+ {
+ if (filter == null)
+ {
+ filter = new StringBuffer().append('(');
+ }
+
+ filter.append(additionalFilter);
+ }
+
+ return filter;
+ }
+ }
+}
diff --git a/src/proguard/gui/ClassSpecificationDialog.java b/src/proguard/gui/ClassSpecificationDialog.java
new file mode 100644
index 0000000..d98efb8
--- /dev/null
+++ b/src/proguard/gui/ClassSpecificationDialog.java
@@ -0,0 +1,414 @@
+/* $Id: ClassSpecificationDialog.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.border.Border;
+
+import java.util.List;
+
+import proguard.ClassSpecification;
+import proguard.classfile.ClassConstants;
+import proguard.classfile.util.ClassUtil;
+
+/**
+ * This <code>JDialog</code> allows the user to enter a String.
+ *
+ * @author Eric Lafortune
+ */
+class ClassSpecificationDialog extends JDialog
+{
+ /**
+ * Return value if the dialog is canceled (with the Cancel button or by
+ * closing the dialog window).
+ */
+ public static final int CANCEL_OPTION = 1;
+
+ /**
+ * Return value if the dialog is approved (with the Ok button).
+ */
+ public static final int APPROVE_OPTION = 0;
+
+
+ private JTextArea commentsTextArea = new JTextArea(4, 20);
+
+ private JRadioButton keepClassesAndMembersRadioButton = new JRadioButton(GUIResources.getMessage("keep"));
+ private JRadioButton keepClassMembersRadioButton = new JRadioButton(GUIResources.getMessage("keepClassMembers"));
+ private JRadioButton keepClassesWithMembersRadioButton = new JRadioButton(GUIResources.getMessage("keepClassesWithMembers"));
+
+ private JRadioButton[] publicRadioButtons;
+ private JRadioButton[] finalRadioButtons;
+ private JRadioButton[] interfaceRadioButtons;
+ private JRadioButton[] abstractRadioButtons;
+
+ private JTextField classNameTextField = new JTextField(20);
+ private JTextField extendsClassNameTextField = new JTextField(20);
+
+ private ClassMemberSpecificationsPanel classMembersPanel;
+
+ private int returnValue;
+
+
+ public ClassSpecificationDialog(JFrame owner, boolean fullKeepOptions)
+ {
+ super(owner, true);
+ setResizable(true);
+
+ // Create some constraints that can be reused.
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(1, 2, 1, 2);
+
+ GridBagConstraints constraintsStretch = new GridBagConstraints();
+ constraintsStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsStretch.weightx = 1.0;
+ constraintsStretch.anchor = GridBagConstraints.WEST;
+ constraintsStretch.insets = constraints.insets;
+
+ GridBagConstraints constraintsLast = new GridBagConstraints();
+ constraintsLast.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLast.anchor = GridBagConstraints.WEST;
+ constraintsLast.insets = constraints.insets;
+
+ GridBagConstraints constraintsLastStretch = new GridBagConstraints();
+ constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsLastStretch.weightx = 1.0;
+ constraintsLastStretch.anchor = GridBagConstraints.WEST;
+ constraintsLastStretch.insets = constraints.insets;
+
+ GridBagConstraints panelConstraints = new GridBagConstraints();
+ panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ panelConstraints.fill = GridBagConstraints.HORIZONTAL;
+ panelConstraints.weightx = 1.0;
+ panelConstraints.weighty = 0.0;
+ panelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ panelConstraints.insets = constraints.insets;
+
+ GridBagConstraints stretchPanelConstraints = new GridBagConstraints();
+ stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ stretchPanelConstraints.fill = GridBagConstraints.BOTH;
+ stretchPanelConstraints.weightx = 1.0;
+ stretchPanelConstraints.weighty = 1.0;
+ stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ stretchPanelConstraints.insets = constraints.insets;
+
+ GridBagConstraints labelConstraints = new GridBagConstraints();
+ labelConstraints.anchor = GridBagConstraints.CENTER;
+ labelConstraints.insets = new Insets(2, 10, 2, 10);
+
+ GridBagConstraints lastLabelConstraints = new GridBagConstraints();
+ lastLabelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ lastLabelConstraints.anchor = GridBagConstraints.CENTER;
+ lastLabelConstraints.insets = labelConstraints.insets;
+
+ GridBagConstraints okButtonConstraints = new GridBagConstraints();
+ okButtonConstraints.weightx = 1.0;
+ okButtonConstraints.weighty = 1.0;
+ okButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ okButtonConstraints.insets = new Insets(4, 4, 8, 4);
+
+ GridBagConstraints cancelButtonConstraints = new GridBagConstraints();
+ cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;;
+ cancelButtonConstraints.weighty = 1.0;
+ cancelButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ cancelButtonConstraints.insets = okButtonConstraints.insets;
+
+ GridBagLayout layout = new GridBagLayout();
+
+ Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
+
+ // Create the comments panel.
+ JPanel commentsPanel = new JPanel(layout);
+ commentsPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("comments")));
+
+ JScrollPane commentsScrollPane = new JScrollPane(commentsTextArea);
+ commentsScrollPane.setBorder(classNameTextField.getBorder());
+
+ commentsPanel.add(commentsScrollPane, constraintsLastStretch);
+
+ // Create the keep option panel.
+ ButtonGroup keepButtonGroup = new ButtonGroup();
+ keepButtonGroup.add(keepClassesAndMembersRadioButton);
+ keepButtonGroup.add(keepClassMembersRadioButton);
+ keepButtonGroup.add(keepClassesWithMembersRadioButton);
+
+ JPanel keepOptionPanel = new JPanel(layout);
+ keepOptionPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("keepTitle")));
+
+ keepOptionPanel.add(keepClassesAndMembersRadioButton, constraintsLastStretch);
+ keepOptionPanel.add(keepClassMembersRadioButton, constraintsLastStretch);
+ keepOptionPanel.add(keepClassesWithMembersRadioButton, constraintsLastStretch);
+
+ // Create the access panel.
+ JPanel accessPanel = new JPanel(layout);
+ accessPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("access")));
+
+ accessPanel.add(Box.createGlue(), labelConstraints);
+ accessPanel.add(new JLabel(GUIResources.getMessage("required")), labelConstraints);
+ accessPanel.add(new JLabel(GUIResources.getMessage("not")), labelConstraints);
+ accessPanel.add(new JLabel(GUIResources.getMessage("dontCare")), labelConstraints);
+ accessPanel.add(Box.createGlue(), constraintsLastStretch);
+
+ publicRadioButtons = addRadioButtonTriplet("Public", accessPanel);
+ finalRadioButtons = addRadioButtonTriplet("Final", accessPanel);
+ interfaceRadioButtons = addRadioButtonTriplet("Interface", accessPanel);
+ abstractRadioButtons = addRadioButtonTriplet("Abstract", accessPanel);
+
+ // Create the class name panel.
+ JPanel classNamePanel = new JPanel(layout);
+ classNamePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("class")));
+
+ classNamePanel.add(classNameTextField, constraintsLastStretch);
+
+ // Create the extends class name panel.
+ JPanel extendsClassNamePanel = new JPanel(layout);
+ extendsClassNamePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("extendsImplementsClass")));
+
+ extendsClassNamePanel.add(extendsClassNameTextField, constraintsLastStretch);
+
+
+ // Create the class member list panel.
+ classMembersPanel = new ClassMemberSpecificationsPanel(this, fullKeepOptions);
+ classMembersPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("classMembers")));
+
+ // Create the Ok button.
+ JButton okButton = new JButton(GUIResources.getMessage("ok"));
+ okButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ returnValue = APPROVE_OPTION;
+ hide();
+ }
+ });
+
+ // Create the Cancel button.
+ JButton cancelButton = new JButton(GUIResources.getMessage("cancel"));
+ cancelButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ hide();
+ }
+ });
+
+ // Add all panels to the main panel.
+ JPanel mainPanel = new JPanel(layout);
+ mainPanel.add(commentsPanel, panelConstraints);
+ if (fullKeepOptions)
+ {
+ mainPanel.add(keepOptionPanel, panelConstraints);
+ }
+ mainPanel.add(accessPanel, panelConstraints);
+ mainPanel.add(classNamePanel, panelConstraints);
+ mainPanel.add(extendsClassNamePanel, panelConstraints);
+ mainPanel.add(classMembersPanel, stretchPanelConstraints);
+
+ mainPanel.add(okButton, okButtonConstraints);
+ mainPanel.add(cancelButton, cancelButtonConstraints);
+
+ getContentPane().add(mainPanel);
+ }
+
+
+ /**
+ * Adds a JLabel and three JRadioButton instances in a ButtonGroup to the
+ * given panel with a GridBagLayout, and returns the buttons in an array.
+ */
+ private JRadioButton[] addRadioButtonTriplet(String labelText,
+ JPanel panel)
+ {
+ GridBagConstraints labelConstraints = new GridBagConstraints();
+ labelConstraints.anchor = GridBagConstraints.WEST;
+ labelConstraints.insets = new Insets(2, 10, 2, 10);
+
+ GridBagConstraints buttonConstraints = new GridBagConstraints();
+ buttonConstraints.insets = labelConstraints.insets;
+
+ GridBagConstraints lastGlueConstraints = new GridBagConstraints();
+ lastGlueConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ lastGlueConstraints.weightx = 1.0;
+
+ // Create the radio buttons.
+ JRadioButton radioButton0 = new JRadioButton();
+ JRadioButton radioButton1 = new JRadioButton();
+ JRadioButton radioButton2 = new JRadioButton();
+
+ // Put them in a button group.
+ ButtonGroup buttonGroup = new ButtonGroup();
+ buttonGroup.add(radioButton0);
+ buttonGroup.add(radioButton1);
+ buttonGroup.add(radioButton2);
+
+ // Add the label and the buttons to the panel.
+ panel.add(new JLabel(labelText), labelConstraints);
+ panel.add(radioButton0, buttonConstraints);
+ panel.add(radioButton1, buttonConstraints);
+ panel.add(radioButton2, buttonConstraints);
+ panel.add(Box.createGlue(), lastGlueConstraints);
+
+ return new JRadioButton[]
+ {
+ radioButton0,
+ radioButton1,
+ radioButton2
+ };
+ }
+
+
+ /**
+ * Sets the ClassSpecification to be represented in this dialog.
+ */
+ public void setClassSpecification(ClassSpecification classSpecification)
+ {
+ String className = classSpecification.className;
+ String extendsClassName = classSpecification.extendsClassName;
+ boolean markClassFiles = classSpecification.markClassFiles;
+ boolean markConditionally = classSpecification.markConditionally;
+ String comments = classSpecification.comments;
+ List keepFieldOptions = classSpecification.fieldSpecifications;
+ List keepMethodOptions = classSpecification.methodSpecifications;
+
+ // Set the comments text area.
+ commentsTextArea.setText(comments == null ? "" : comments);
+
+ // Figure out the proper keep radio button and set it.
+ JRadioButton keepOptionRadioButton =
+ markConditionally ? keepClassesWithMembersRadioButton :
+ markClassFiles ? keepClassesAndMembersRadioButton :
+ keepClassMembersRadioButton;
+
+ keepOptionRadioButton.setSelected(true);
+
+ // Set the access radio buttons.
+ setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons);
+ setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons);
+ setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_INTERFACE, interfaceRadioButtons);
+ setClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons);
+
+ // Set the class name text fields.
+ classNameTextField .setText(className == null ? "*" : ClassUtil.externalClassName(className));
+ extendsClassNameTextField.setText(extendsClassName == null ? "" : ClassUtil.externalClassName(extendsClassName));
+
+ // Set the keep class member option list.
+ classMembersPanel.setClassMemberSpecifications(keepFieldOptions, keepMethodOptions);
+ }
+
+
+ /**
+ * Returns the ClassSpecification currently represented in this dialog.
+ */
+ public ClassSpecification getClassSpecification()
+ {
+ String comments = commentsTextArea.getText();
+ String className = classNameTextField.getText();
+ String extendsClassName = extendsClassNameTextField.getText();
+ boolean markClassFiles = !keepClassMembersRadioButton.isSelected();
+ boolean markConditionally = keepClassesWithMembersRadioButton.isSelected();
+
+ ClassSpecification classSpecification =
+ new ClassSpecification(0,
+ 0,
+ className.equals("") ||
+ className.equals("*") ? null : ClassUtil.internalClassName(className),
+ extendsClassName.equals("") ? null : ClassUtil.internalClassName(extendsClassName),
+ markClassFiles,
+ markConditionally,
+ comments.equals("") ? null : comments);
+
+ // Also get the access radio button settings.
+ getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons);
+ getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons);
+ getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_INTERFACE, interfaceRadioButtons);
+ getClassSpecificationRadioButtons(classSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons);
+
+ // Get the keep class member option lists.
+ classSpecification.fieldSpecifications = classMembersPanel.getClassMemberSpecifications(true);
+ classSpecification.methodSpecifications = classMembersPanel.getClassMemberSpecifications(false);
+
+ return classSpecification;
+ }
+
+
+ /**
+ * Shows this dialog. This method only returns when the dialog is closed.
+ *
+ * @return <code>CANCEL_OPTION</code> or <code>APPROVE_OPTION</code>,
+ * depending on the choice of the user.
+ */
+ public int showDialog()
+ {
+ returnValue = CANCEL_OPTION;
+
+ // Open the dialog in the right place, then wait for it to be closed,
+ // one way or another.
+ pack();
+ setLocationRelativeTo(getOwner());
+ show();
+
+ return returnValue;
+ }
+
+
+ /**
+ * Sets the appropriate radio button of a given triplet, based on the access
+ * flags of the given keep option.
+ */
+ private void setClassSpecificationRadioButtons(ClassSpecification classSpecification,
+ int flag,
+ JRadioButton[] radioButtons)
+ {
+ int index = (classSpecification.requiredSetAccessFlags & flag) != 0 ? 0 :
+ (classSpecification.requiredUnsetAccessFlags & flag) != 0 ? 1 :
+ 2;
+ radioButtons[index].setSelected(true);
+ }
+
+
+ /**
+ * Updates the access flag of the given keep option, based on the given radio
+ * button triplet.
+ */
+ private void getClassSpecificationRadioButtons(ClassSpecification classSpecification,
+ int flag,
+ JRadioButton[] radioButtons)
+ {
+ if (radioButtons[0].isSelected())
+ {
+ classSpecification.requiredSetAccessFlags |= flag;
+ }
+ else if (radioButtons[1].isSelected())
+ {
+ classSpecification.requiredUnsetAccessFlags |= flag;
+ }
+ }
+}
diff --git a/src/proguard/gui/ClassSpecificationsPanel.java b/src/proguard/gui/ClassSpecificationsPanel.java
new file mode 100644
index 0000000..0746ab1
--- /dev/null
+++ b/src/proguard/gui/ClassSpecificationsPanel.java
@@ -0,0 +1,191 @@
+/* $Id: ClassSpecificationsPanel.java,v 1.4 2004/08/28 22:50:49 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import proguard.*;
+import proguard.classfile.util.ClassUtil;
+
+import java.awt.Component;
+import java.awt.event.*;
+import java.util.*;
+
+import javax.swing.*;
+
+
+/**
+ * This <code>ListPanel</code> allows the user to add, edit, move, and remove
+ * ClassSpecification entries in a list.
+ *
+ * @author Eric Lafortune
+ */
+class ClassSpecificationsPanel extends ListPanel
+{
+ private ClassSpecificationDialog classSpecificationDialog;
+
+
+ public ClassSpecificationsPanel(JFrame owner, boolean fullKeepOptions)
+ {
+ super();
+
+ list.setCellRenderer(new MyListCellRenderer());
+
+ classSpecificationDialog = new ClassSpecificationDialog(owner, fullKeepOptions);
+
+ addAddButton();
+ addEditButton();
+ addRemoveButton();
+ addUpButton();
+ addDownButton();
+
+ enableSelectionButtons();
+ }
+
+
+ protected void addAddButton()
+ {
+ JButton addButton = new JButton(GUIResources.getMessage("add"));
+ addButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ classSpecificationDialog.setClassSpecification(new ClassSpecification());
+ int returnValue = classSpecificationDialog.showDialog();
+ if (returnValue == ClassSpecificationDialog.APPROVE_OPTION)
+ {
+ // Add the new element.
+ addElement(classSpecificationDialog.getClassSpecification());
+ }
+ }
+ });
+
+ addButton(addButton);
+ }
+
+
+ protected void addEditButton()
+ {
+ JButton editButton = new JButton(GUIResources.getMessage("edit"));
+ editButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ ClassSpecification selectedClassSpecification =
+ (ClassSpecification)list.getSelectedValue();
+
+ classSpecificationDialog.setClassSpecification(selectedClassSpecification);
+ int returnValue = classSpecificationDialog.showDialog();
+ if (returnValue == ClassSpecificationDialog.APPROVE_OPTION)
+ {
+ // Replace the old element.
+ setElementAt(classSpecificationDialog.getClassSpecification(),
+ list.getSelectedIndex());
+ }
+ }
+ });
+
+ addButton(editButton);
+ }
+
+
+ /**
+ * Sets the ClassSpecification objects to be represented in this panel.
+ */
+ public void setClassSpecifications(List classSpecifications)
+ {
+ listModel.clear();
+
+ if (classSpecifications != null)
+ {
+ for (int index = 0; index < classSpecifications.size(); index++)
+ {
+ listModel.addElement(classSpecifications.get(index));
+ }
+ }
+
+ // Make sure the selection buttons are properly enabled,
+ // since the clear method doesn't seem to notify the listener.
+ enableSelectionButtons();
+ }
+
+
+ /**
+ * Returns the ClassSpecification objects currently represented in this panel.
+ */
+ public List getClassSpecifications()
+ {
+ int size = listModel.size();
+ if (size == 0)
+ {
+ return null;
+ }
+
+ List classSpecifications = new ArrayList(size);
+ for (int index = 0; index < size; index++)
+ {
+ classSpecifications.add(listModel.get(index));
+ }
+
+ return classSpecifications;
+ }
+
+
+ /**
+ * This ListCellRenderer renders ClassSpecification objects.
+ */
+ private static class MyListCellRenderer implements ListCellRenderer
+ {
+ JLabel label = new JLabel();
+
+
+ // Implementations for ListCellRenderer.
+
+ public Component getListCellRendererComponent(JList list,
+ Object value,
+ int index,
+ boolean isSelected,
+ boolean cellHasFocus)
+ {
+ ClassSpecification option = (ClassSpecification)value;
+
+ String comments = option.comments;
+
+ label.setText(comments != null ? comments.trim() :
+ option.className != null ? (GUIResources.getMessage("class") + ' ' + ClassUtil.externalClassName(option.className)) :
+ option.extendsClassName != null ? (GUIResources.getMessage("extensionsOf") + ' ' + ClassUtil.externalClassName(option.extendsClassName)) :
+ (GUIResources.getMessage("specificationNumber") + index));
+
+ if (isSelected)
+ {
+ label.setBackground(list.getSelectionBackground());
+ label.setForeground(list.getSelectionForeground());
+ }
+ else
+ {
+ label.setBackground(list.getBackground());
+ label.setForeground(list.getForeground());
+ }
+
+ label.setOpaque(true);
+
+ return label;
+ }
+ }
+}
diff --git a/src/proguard/gui/ExtensionFileFilter.java b/src/proguard/gui/ExtensionFileFilter.java
new file mode 100644
index 0000000..9a69355
--- /dev/null
+++ b/src/proguard/gui/ExtensionFileFilter.java
@@ -0,0 +1,78 @@
+/* $Id: ExtensionFileFilter.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.io.File;
+import javax.swing.filechooser.FileFilter;
+
+
+/**
+ * This <code>FileFilter</code> accepts files that end in one of the given
+ * extensions.
+ *
+ * @author Eric Lafortune
+ */
+class ExtensionFileFilter extends FileFilter
+{
+ private String description;
+ private String[] extensions;
+
+
+ /**
+ * Creates a new ExtensionFileFilter.
+ * @param description a description of the filter.
+ * @param extensions an array of acceptable extensions.
+ */
+ public ExtensionFileFilter(String description, String[] extensions)
+ {
+ this.description = description;
+ this.extensions = extensions;
+ }
+
+
+ // Implemntations for FileFilter
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+
+ public boolean accept(File file)
+ {
+ if (file.isDirectory())
+ {
+ return true;
+ }
+
+ String fileName = file.getName().toLowerCase();
+
+ for (int index = 0; index < extensions.length; index++)
+ {
+ if (fileName.endsWith(extensions[index]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/proguard/gui/FilterDialog.java b/src/proguard/gui/FilterDialog.java
new file mode 100644
index 0000000..8d2d791
--- /dev/null
+++ b/src/proguard/gui/FilterDialog.java
@@ -0,0 +1,296 @@
+/* $Id: FilterDialog.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+
+/**
+ * This <code>JDialog</code> allows the user to enter a String.
+ *
+ * @author Eric Lafortune
+ */
+public class FilterDialog extends JDialog
+{
+ /**
+ * Return value if the dialog is canceled (with the Cancel button or by
+ * closing the dialog window).
+ */
+ public static final int CANCEL_OPTION = 1;
+
+ /**
+ * Return value if the dialog is approved (with the Ok button).
+ */
+ public static final int APPROVE_OPTION = 0;
+
+ private static final String DEFAULT_FILTER = "**";
+ private static final String DEFAULT_JAR_FILTER = "**.jar";
+ private static final String DEFAULT_WAR_FILTER = "**.war";
+ private static final String DEFAULT_EAR_FILTER = "**.ear";
+ private static final String DEFAULT_ZIP_FILTER = "**.zip";
+
+
+ private JTextField filterTextField = new JTextField(40);
+ private JTextField jarFilterTextField = new JTextField(40);
+ private JTextField warFilterTextField = new JTextField(40);
+ private JTextField earFilterTextField = new JTextField(40);
+ private JTextField zipFilterTextField = new JTextField(40);
+ private int returnValue;
+
+
+ public FilterDialog(JFrame owner,
+ String explanation)
+ {
+ super(owner, true);
+ setResizable(true);
+
+ // Create some constraints that can be reused.
+ GridBagConstraints textConstraints = new GridBagConstraints();
+ textConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ textConstraints.fill = GridBagConstraints.HORIZONTAL;
+ textConstraints.weightx = 1.0;
+ textConstraints.weighty = 1.0;
+ textConstraints.anchor = GridBagConstraints.NORTHWEST;
+ textConstraints.insets = new Insets(10, 10, 10, 10);
+
+ GridBagConstraints labelConstraints = new GridBagConstraints();
+ labelConstraints.anchor = GridBagConstraints.WEST;
+ labelConstraints.insets = new Insets(1, 2, 1, 2);
+
+ GridBagConstraints textFieldConstraints = new GridBagConstraints();
+ textFieldConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ textFieldConstraints.fill = GridBagConstraints.HORIZONTAL;
+ textFieldConstraints.weightx = 1.0;
+ textFieldConstraints.anchor = GridBagConstraints.WEST;
+ textFieldConstraints.insets = labelConstraints.insets;
+
+ GridBagConstraints panelConstraints = new GridBagConstraints();
+ panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ panelConstraints.fill = GridBagConstraints.HORIZONTAL;
+ panelConstraints.weightx = 1.0;
+ panelConstraints.weighty = 0.0;
+ panelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ panelConstraints.insets = labelConstraints.insets;
+
+ GridBagConstraints okButtonConstraints = new GridBagConstraints();
+ okButtonConstraints.weightx = 1.0;
+ okButtonConstraints.weighty = 1.0;
+ okButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ okButtonConstraints.insets = new Insets(4, 4, 8, 4);
+
+ GridBagConstraints cancelButtonConstraints = new GridBagConstraints();
+ cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;;
+ cancelButtonConstraints.weighty = 1.0;
+ cancelButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ cancelButtonConstraints.insets = okButtonConstraints.insets;
+
+ GridBagLayout layout = new GridBagLayout();
+
+ Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
+
+ // Create the panel with the explanation.
+ JTextArea explanationTextArea = new JTextArea(explanation, 3, 0);
+ explanationTextArea.setOpaque(false);
+ explanationTextArea.setEditable(false);
+ explanationTextArea.setLineWrap(true);
+ explanationTextArea.setWrapStyleWord(true);
+
+ // Create the filter labels.
+ JLabel filterLabel = new JLabel(GUIResources.getMessage("nameFilter"));
+ JLabel jarFilterLabel = new JLabel(GUIResources.getMessage("jarNameFilter"));
+ JLabel warFilterLabel = new JLabel(GUIResources.getMessage("warNameFilter"));
+ JLabel earFilterLabel = new JLabel(GUIResources.getMessage("earNameFilter"));
+ JLabel zipFilterLabel = new JLabel(GUIResources.getMessage("zipNameFilter"));
+
+ // Create the filter panel.
+ JPanel filterPanel = new JPanel(layout);
+ filterPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
+ GUIResources.getMessage("filters")));
+
+ filterPanel.add(explanationTextArea, textConstraints);
+
+ filterPanel.add(filterLabel, labelConstraints);
+ filterPanel.add(filterTextField, textFieldConstraints);
+
+ filterPanel.add(jarFilterLabel, labelConstraints);
+ filterPanel.add(jarFilterTextField, textFieldConstraints);
+
+ filterPanel.add(warFilterLabel, labelConstraints);
+ filterPanel.add(warFilterTextField, textFieldConstraints);
+
+ filterPanel.add(earFilterLabel, labelConstraints);
+ filterPanel.add(earFilterTextField, textFieldConstraints);
+
+ filterPanel.add(zipFilterLabel, labelConstraints);
+ filterPanel.add(zipFilterTextField, textFieldConstraints);
+
+
+ JButton okButton = new JButton(GUIResources.getMessage("ok"));
+ okButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ returnValue = APPROVE_OPTION;
+ hide();
+ }
+ });
+
+ JButton cancelButton = new JButton(GUIResources.getMessage("cancel"));
+ cancelButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ hide();
+ }
+ });
+
+ // Add all panels to the main panel.
+ JPanel mainPanel = new JPanel(layout);
+ mainPanel.add(filterPanel, panelConstraints);
+ mainPanel.add(okButton, okButtonConstraints);
+ mainPanel.add(cancelButton, cancelButtonConstraints);
+
+ getContentPane().add(mainPanel);
+ }
+
+
+ /**
+ * Sets the filter to be represented in this dialog.
+ */
+ public void setFilter(String filter)
+ {
+ filterTextField.setText(filter != null ? filter : DEFAULT_FILTER);
+ }
+
+
+ /**
+ * Returns the filter currently represented in this dialog.
+ */
+ public String getFilter()
+ {
+ String filter = filterTextField.getText();
+
+ return filter.equals(DEFAULT_FILTER) ? null : filter;
+ }
+
+
+ /**
+ * Sets the jar filter to be represented in this dialog.
+ */
+ public void setJarFilter(String filter)
+ {
+ jarFilterTextField.setText(filter != null ? filter : DEFAULT_JAR_FILTER);
+ }
+
+
+ /**
+ * Returns the jar filter currently represented in this dialog.
+ */
+ public String getJarFilter()
+ {
+ String filter = jarFilterTextField.getText();
+
+ return filter.equals(DEFAULT_JAR_FILTER) ? null : filter;
+ }
+
+
+ /**
+ * Sets the war filter to be represented in this dialog.
+ */
+ public void setWarFilter(String filter)
+ {
+ warFilterTextField.setText(filter != null ? filter : DEFAULT_WAR_FILTER);
+ }
+
+
+ /**
+ * Returns the war filter currently represented in this dialog.
+ */
+ public String getWarFilter()
+ {
+ String filter = warFilterTextField.getText();
+
+ return filter.equals(DEFAULT_WAR_FILTER) ? null : filter;
+ }
+
+
+ /**
+ * Sets the ear filter to be represented in this dialog.
+ */
+ public void setEarFilter(String filter)
+ {
+ earFilterTextField.setText(filter != null ? filter : DEFAULT_EAR_FILTER);
+ }
+
+
+ /**
+ * Returns the ear filter currently represented in this dialog.
+ */
+ public String getEarFilter()
+ {
+ String filter = earFilterTextField.getText();
+
+ return filter.equals(DEFAULT_EAR_FILTER) ? null : filter;
+ }
+
+
+ /**
+ * Sets the zip filter to be represented in this dialog.
+ */
+ public void setZipFilter(String filter)
+ {
+ zipFilterTextField.setText(filter != null ? filter : DEFAULT_ZIP_FILTER);
+ }
+
+
+ /**
+ * Returns the zip filter currently represented in this dialog.
+ */
+ public String getZipFilter()
+ {
+ String filter = zipFilterTextField.getText();
+
+ return filter.equals(DEFAULT_ZIP_FILTER) ? null : filter;
+ }
+
+
+ /**
+ * Shows this dialog. This method only returns when the dialog is closed.
+ *
+ * @return <code>CANCEL_OPTION</code> or <code>APPROVE_OPTION</code>,
+ * depending on the choice of the user.
+ */
+ public int showDialog()
+ {
+ returnValue = CANCEL_OPTION;
+
+ // Open the dialog in the right place, then wait for it to be closed,
+ // one way or another.
+ pack();
+ setLocationRelativeTo(getOwner());
+ show();
+
+ return returnValue;
+ }
+}
diff --git a/src/proguard/gui/GUIResources.java b/src/proguard/gui/GUIResources.java
new file mode 100644
index 0000000..fa126d5
--- /dev/null
+++ b/src/proguard/gui/GUIResources.java
@@ -0,0 +1,56 @@
+/* $Id: GUIResources.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.text.MessageFormat;
+import java.util.*;
+
+
+/**
+ * This class provides some utility methods for working with resource bundles.
+ *
+ * @author Eric Lafortune
+ */
+class GUIResources
+{
+ private static ResourceBundle messages = ResourceBundle.getBundle(new GUIResources().getClass().getName());
+ private static MessageFormat formatter = new MessageFormat("");
+
+
+ /**
+ * Returns an internationalized message, based on its key.
+ */
+ public static String getMessage(String messageKey)
+ {
+ return messages.getString(messageKey);
+ }
+
+
+ /**
+ * Returns an internationalized, formatted message, based on its key, with
+ * the given arguments.
+ */
+ public static String getMessage(String messageKey, Object[] messageArguments)
+ {
+ formatter.applyPattern(messages.getString(messageKey));
+ return formatter.format(messageArguments);
+ }
+}
diff --git a/src/proguard/gui/GUIResources.properties b/src/proguard/gui/GUIResources.properties
new file mode 100644
index 0000000..fe0ca28
--- /dev/null
+++ b/src/proguard/gui/GUIResources.properties
@@ -0,0 +1,255 @@
+# ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+# Copyright (c) 1999-2004 Eric Lafortune (eric at graphics.cornell.edu)
+
+#
+# Tab names.
+#
+proGuardTab = ProGuard
+inputOutputTab = Input/Output
+shrinkingTab = Shrinking
+obfuscationTab = Obfuscation
+optimizationTab = Optimization
+informationTab = Information
+processTab = Process
+reTraceTab = ReTrace
+
+#
+# Splash text.
+#
+developed = Developed by Eric Lafortune
+shrinking = Shrinking
+optimization = Optimization
+obfuscation = Obfuscation
+
+#
+# Panel titles.
+#
+welcome = Welcome to ProGuard, version 3.2
+options = Options
+keepAdditional = Keep additional classes and class members
+keepNamesAdditional = Keep additional class names and class member names
+assumeNoSideEffectsAdditional = Assume no side effects for additional methods
+consistencyAndCorrectness = Consistency and correctness
+processingConsole = Processing console
+reTraceSettings = ReTrace settings
+
+mappingFile = Mapping file
+obfuscatedStackTrace = Obfuscated stack trace
+deobfuscatedStackTrace = De-obfuscated stack trace
+
+#
+# Info texts.
+#
+proGuardInfo = \
+ ProGuard is a free class file shrinker, optimizer, and obfuscator.\
+ \n\n\
+ With this GUI, you can create, load, modify, and save ProGuard configurations. \
+ \n\
+ You can then process your code right away, or you can run ProGuard from the \
+ command line using your saved configuration. \
+ \n\n\
+ With the ReTrace part of this GUI you can de-obfuscate your stack traces.\
+ \n\n\
+ ProGuard and ReTrace are written and maintained by Eric Lafortune.\
+ \n\n\
+ Based on class file IO code by Mark Welsh.\
+ \n\n\
+ Distributed under the GNU General Public License.\
+ \n\
+ Copyright (c) 1999-2004.
+
+processingInfo = \
+ You can now start processing your code, \
+ or you can run ProGuard from the command line using your saved configuration.\
+ \n\n\
+ It's always a good idea to save your configuration first.
+
+reTraceInfo = \
+ If you had ProGuard write out a mapping file, \
+ you can de-obfuscate your obfuscated stack traces with ReTrace!\
+ \n\n\
+ You can load an obfuscated stack trace from a file, \
+ or you can paste it straight into the text area above.
+
+#
+# Titles and labels corresponding to common ProGuard options.
+#
+programJars = Program jars, wars, ears, zips, and directories
+libraryJars = Library jars, wars, ears, zips, and directories
+outputJars = Output jars, wars, ears, zips, and directories
+
+printSeeds = Print seeds
+shrink = Shrink
+printUsage = Print usage
+
+optimize = Optimize
+allowAccessModification = Allow access modification
+
+obfuscate = Obfuscate
+printMapping = Print mapping
+applyMapping = Apply mapping
+obfuscationDictionary = Obfuscation dictionary
+overloadAggressively = Overload aggressively
+defaultPackage = Default package
+useMixedCaseClassNames = Use mixed-case class names
+keepAttributes = Keep attributes
+renameSourceFileAttribute = Rename SourceFile attribute
+
+verbose = Verbose
+note = Note Class.forName invocations with variable arguments
+warn = Warn about missing libraries
+ignoreWarnings = Ignore warnings about missing libraries
+skipNonPublicLibraryClasses = Skip non-public library classes
+skipNonPublicLibraryClassMembers = Skip non-public library class members
+
+#
+# Panel titles and labels for boilerplate keep options.
+#
+boilerplate_keep = Keep
+boilerplate_applications = Applications
+boilerplate_applets = Applets
+boilerplate_servlets = Servlets
+boilerplate_midlets = Midlets
+boilerplate_library = Library
+
+boilerplate_also_keep = Also keep
+boilerplate_enumerations = Enumerations
+boilerplate_serialization_code = Serialization code
+boilerplate_beaninfo_classes = BeanInfo classes
+boilerplate_bean_classes = Bean classes
+boilerplate_rmi_interfaces = RMI interfaces
+boilerplate_rmi_implementations = RMI implementations
+
+#
+# Panel titles and labels for boilerplate keep names options.
+#
+boilerplate_keep_names = Keep names
+boilerplate_native_method_names = Native method names
+boilerplate__class_method_names = .class method names
+
+#
+# Labels for boilerplate "no side effect methods" options.
+#
+boilerplate_remove = Remove
+boilerplate_system_method_calls = System method calls without side effects
+boilerplate_math_method_calls = Math method calls without side effects
+boilerplate_string_method_calls = String method calls without side effects
+boilerplate_stringbuffer_method_calls = StringBuffer method calls without side effects
+boilerplate_stringbuilder_method_calls = StringBuilder method calls without side effects
+
+boilerplate_remove_debugging = Remove debugging
+boilerplate_throwable_printstacktrace_calls = Throwable.printStackTrace() calls
+boilerplate_thread_dumpstack_calls = Thread.dumpStack() calls
+boilerplate_all_logging_api_calls = All logging API calls
+boilerplate_all_log4j_api_calls = All Log4j API calls
+
+#
+# Titles and labels corresponding to ProGuard keep options.
+#
+keepTitle = Keep
+
+keep = Keep classes and class members
+keepClassMembers = Keep class members only
+keepClassesWithMembers = Keep classes and class members, if members are present
+
+#
+# Further keep titles and labels.
+#
+comments = Comments
+access = Access
+required = Required
+not = Not
+dontCare = Don't care
+class = Class
+extendsImplementsClass = Extends/implements class
+classMembers = Class members
+
+extensionsOf = Extensions of
+specificationNumber = Specification #
+
+returnType = Return type
+name = Name
+arguments = Arguments
+
+#
+# File selection titles.
+#
+selectConfigurationFile = Select a configuration file...
+saveConfigurationFile = Save configuration...
+selectSeedsFile = Select a seeds output file...
+selectUsageFile = Select a usage output file...
+selectPrintMappingFile = Select an output mapping file...
+selectApplyMappingFile = Select an input mapping file...
+selectObfuscationDictionaryFile = Select an obfuscation dictionary...
+selectStackTraceFile = Select a stack trace file...
+
+cantOpenConfigurationFile = Can''t open the configuration file [{0}]
+cantParseConfigurationFile = Can''t parse the configuration file [{0}]
+cantSaveConfigurationFile = Can''t save the configuration file [{0}]
+cantOpenStackTraceFile = Can''t open the stack trace file [{0}]
+
+jarWarEarZipExtensions = *.jar, *.war, *.ear, *.zip (archives and directories)
+proExtension = *.pro (ProGuard configurations)
+
+addJars = Add one or more jars or directories...
+chooseJars = Choose different jars or directories...
+enterFilter = \
+ You can enter optional filters for the file names contained in the selected entries. \
+ The filters are comma-separated lists of relative file names, supporting ?, * and ** wildcards, and ! negators. \
+
+filters = Filters
+nameFilter = File name filter
+jarNameFilter = Jar name filter
+warNameFilter = War name filter
+earNameFilter = Ear name filter
+zipNameFilter = Zip name filter
+
+#
+# Simple button texts.
+#
+previous = Previous
+next = Next
+browse = Browse...
+ok = Ok
+cancel = Cancel
+
+add = Add...
+addInput = Add input...
+addOutput = Add output...
+edit = Edit...
+filter = Filter...
+remove = Remove
+moveUp = Move up
+moveDown = Move down
+
+moveToLibraries = Move to libraries
+moveToProgram = Move to program
+
+addField = Add field...
+addMethod = Add method...
+
+loadConfiguration = Load configuration...
+viewConfiguration = View configuration
+saveConfiguration = Save configuration...
+loadStackTrace = Load stack trace...
+process = Process!
+reTrace = ReTrace!
+
+#
+# Progress messages and error messages.
+#
+warning = Warning
+outOfMemory = Out of memory
+outOfMemoryInfo = \n\
+ You should run the ProGuard GUI with a larger java heap size, \
+ with a command like\
+ \n\n\t\
+ java -Xms128m -Xmx192m -jar proguardgui.jar {0}\
+ \n\n\
+ or you can try running ProGuard from the command line. \
+ with a command like\
+ \n\n\t\
+ java -jar proguard.jar @{0}
+sampleConfigurationFileName = configuration.pro
+errorProcessing = Error during processing
+errorReTracing = Error during retracing
diff --git a/src/proguard/gui/ListPanel.java b/src/proguard/gui/ListPanel.java
new file mode 100644
index 0000000..8f2021f
--- /dev/null
+++ b/src/proguard/gui/ListPanel.java
@@ -0,0 +1,317 @@
+/* $Id: ListPanel.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.List;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+/**
+ * This <code>Jpanel</code> allows the user to move and remove entries in a
+ * list and between lists. Extensions of this class should add buttons to add
+ * and possibly edit entries, and to set and get the resulting list.
+ *
+ * @author Eric Lafortune
+ */
+abstract class ListPanel extends JPanel
+{
+ protected DefaultListModel listModel = new DefaultListModel();
+ protected JList list = new JList(listModel);
+
+ protected int firstSelectionButton = 2;
+
+
+ protected ListPanel()
+ {
+ GridBagLayout layout = new GridBagLayout();
+ setLayout(layout);
+
+ GridBagConstraints listConstraints = new GridBagConstraints();
+ listConstraints.gridheight = GridBagConstraints.REMAINDER;
+ listConstraints.fill = GridBagConstraints.BOTH;
+ listConstraints.weightx = 1.0;
+ listConstraints.weighty = 1.0;
+ listConstraints.anchor = GridBagConstraints.NORTHWEST;
+ listConstraints.insets = new Insets(0, 2, 0, 2);
+
+ // Make sure some buttons are disabled or enabled depending on whether
+ // the selection is empty or not.
+ list.addListSelectionListener(new ListSelectionListener()
+ {
+ public void valueChanged(ListSelectionEvent e)
+ {
+ enableSelectionButtons();
+ }
+ });
+
+ add(new JScrollPane(list), listConstraints);
+
+ // something like the following calls are up to the extending class:
+ //addAddButton();
+ //addEditButton();
+ //addRemoveButton();
+ //addUpButton();
+ //addDownButton();
+ //
+ //enableSelectionButtons();
+ }
+
+
+ protected void addRemoveButton()
+ {
+ JButton removeButton = new JButton(GUIResources.getMessage("remove"));
+ removeButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // Remove the selected elements.
+ removeElementsAt(list.getSelectedIndices());
+ }
+ });
+
+ addButton(removeButton);
+ }
+
+
+ protected void addUpButton()
+ {
+ JButton upButton = new JButton(GUIResources.getMessage("moveUp"));
+ upButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ int[] selectedIndices = list.getSelectedIndices();
+ if (selectedIndices.length > 0 &&
+ selectedIndices[0] > 0)
+ {
+ // Move the selected elements up.
+ moveElementsAt(selectedIndices, -1);
+ }
+ }
+ });
+
+ addButton(upButton);
+ }
+
+
+ protected void addDownButton()
+ {
+ JButton downButton = new JButton(GUIResources.getMessage("moveDown"));
+ downButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ int[] selectedIndices = list.getSelectedIndices();
+ if (selectedIndices.length > 0 &&
+ selectedIndices[selectedIndices.length-1] < listModel.getSize()-1)
+ {
+ // Move the selected elements down.
+ moveElementsAt(selectedIndices, 1);
+ }
+ }
+ });
+
+ addButton(downButton);
+ }
+
+
+ /**
+ * Adds a button that allows to copy or move entries to another ListPanel.
+ *
+ * @param buttonText the button text.
+ * @param panel the other ListPanel.
+ */
+ public void addCopyToPanelButton(String buttonText,
+ final ListPanel panel)
+ {
+ JButton moveButton = new JButton(buttonText);
+ moveButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ int[] selectedIndices = list.getSelectedIndices();
+ Object[] selectedElements = list.getSelectedValues();
+
+ // Remove the selected elements from this panel.
+ removeElementsAt(selectedIndices);
+
+ // Add the elements to the other panel.
+ panel.addElements(selectedElements);
+ }
+ });
+
+ addButton(moveButton);
+ }
+
+
+ protected void addButton(JButton button)
+ {
+ GridBagConstraints buttonConstraints = new GridBagConstraints();
+ buttonConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ buttonConstraints.fill = GridBagConstraints.HORIZONTAL;
+ buttonConstraints.anchor = GridBagConstraints.NORTHWEST;
+ buttonConstraints.insets = new Insets(0, 2, 0, 2);
+
+ add(button, buttonConstraints);
+ }
+
+
+ /**
+ * Returns a list of all right-hand side buttons.
+ */
+ public List getButtons()
+ {
+ List list = new ArrayList(getComponentCount()-1);
+
+ // Add all buttons.
+ for (int index = 1; index < getComponentCount(); index++)
+ {
+ list.add(getComponent(index));
+ }
+
+ return list;
+ }
+
+
+ protected void addElement(Object element)
+ {
+ listModel.addElement(element);
+
+ // Make sure it is selected.
+ list.setSelectedIndex(listModel.size() - 1);
+ }
+
+
+ protected void addElements(Object[] elements)
+ {
+ // Add the elements one by one.
+ for (int index = 0; index < elements.length; index++)
+ {
+ listModel.addElement(elements[index]);
+ }
+
+ // Make sure they are selected.
+ int[] selectedIndices = new int[elements.length];
+ for (int index = 0; index < selectedIndices.length; index++)
+ {
+ selectedIndices[index] =
+ listModel.size() - selectedIndices.length + index;
+ }
+ list.setSelectedIndices(selectedIndices);
+ }
+
+
+ protected void moveElementsAt(int[] indices, int offset)
+ {
+ // Remember the selected elements.
+ Object[] selectedElements = list.getSelectedValues();
+
+ // Remove the selected elements.
+ removeElementsAt(indices);
+
+ // Update the element indices.
+ for (int index = 0; index < indices.length; index++)
+ {
+ indices[index] += offset;
+ }
+
+ // Reinsert the selected elements.
+ insertElementsAt(selectedElements, indices);
+ }
+
+
+ protected void insertElementsAt(Object[] elements, int[] indices)
+ {
+ for (int index = 0; index < elements.length; index++)
+ {
+ listModel.insertElementAt(elements[index], indices[index]);
+ }
+
+ // Make sure they are selected.
+ list.setSelectedIndices(indices);
+ }
+
+
+ protected void setElementAt(Object element, int index)
+ {
+ listModel.setElementAt(element, index);
+
+ // Make sure it is selected.
+ list.setSelectedIndex(index);
+ }
+
+
+ protected void setElementsAt(Object[] elements, int[] indices)
+ {
+ for (int index = 0; index < elements.length; index++)
+ {
+ listModel.setElementAt(elements[index], indices[index]);
+ }
+
+ // Make sure they are selected.
+ list.setSelectedIndices(indices);
+ }
+
+
+ protected void removeElementsAt(int[] indices)
+ {
+ for (int index = indices.length - 1; index >= 0; index--)
+ {
+ listModel.removeElementAt(indices[index]);
+ }
+
+ // Make sure nothing is selected.
+ list.clearSelection();
+
+ // Make sure the selection buttons are properly enabled,
+ // since the above method doesn't seem to notify the listener.
+ enableSelectionButtons();
+ }
+
+
+ protected void removeAllElements()
+ {
+ listModel.removeAllElements();
+
+ // Make sure the selection buttons are properly enabled,
+ // since the above method doesn't seem to notify the listener.
+ enableSelectionButtons();
+ }
+
+
+ /**
+ * Enables or disables the buttons that depend on a selection.
+ */
+ protected void enableSelectionButtons()
+ {
+ boolean selected = !list.isSelectionEmpty();
+
+ // Loop over all components, except the list itself and the Add button.
+ for (int index = firstSelectionButton; index < getComponentCount(); index++)
+ {
+ getComponent(index).setEnabled(selected);
+ }
+ }
+}
diff --git a/src/proguard/gui/MessageDialogRunnable.java b/src/proguard/gui/MessageDialogRunnable.java
new file mode 100644
index 0000000..c3b6d1c
--- /dev/null
+++ b/src/proguard/gui/MessageDialogRunnable.java
@@ -0,0 +1,83 @@
+/* $Id: MessageDialogRunnable.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+
+/**
+ * This <code>Runnable</code> can show a message dialog.
+ *
+ * @author Eric Lafortune
+ */
+class MessageDialogRunnable implements Runnable
+{
+ private Component parentComponent;
+ private Object message;
+ private String title;
+ private int messageType;
+
+
+ /**
+ * Creates a new MessageDialogRunnable object.
+ * @see JOptionPane.showMessageDialog
+ */
+ public static void showMessageDialog(Component parentComponent,
+ Object message,
+ String title,
+ int messageType)
+ {
+ SwingUtil.invokeAndWait(new MessageDialogRunnable(parentComponent,
+ message,
+ title,
+ messageType));
+ }
+
+
+ /**
+ * Creates a new MessageDialogRunnable object.
+ * @see JOptionPane.showMessageDialog
+ */
+ public MessageDialogRunnable(Component parentComponent,
+ Object message,
+ String title,
+ int messageType)
+ {
+ this.parentComponent = parentComponent;
+ this.message = message;
+ this.title = title;
+ this.messageType = messageType;
+ }
+
+
+
+ // Implementation for Runnable.
+
+ public void run()
+ {
+ JOptionPane.showMessageDialog(parentComponent,
+ message,
+ title,
+ messageType);
+ }
+}
diff --git a/src/proguard/gui/ProGuardGUI.java b/src/proguard/gui/ProGuardGUI.java
new file mode 100644
index 0000000..d5d9512
--- /dev/null
+++ b/src/proguard/gui/ProGuardGUI.java
@@ -0,0 +1,1420 @@
+/* $Id: ProGuardGUI.java,v 1.27 2004/11/20 15:08:57 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import proguard.*;
+import proguard.optimize.NoSideEffectMethodMarker;
+import proguard.util.*;
+import proguard.classfile.util.*;
+import proguard.gui.splash.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import java.util.List;
+
+
+/**
+ * GUI for configuring and executing ProGuard and ReTrace.
+ *
+ * @author Eric Lafortune
+ */
+public class ProGuardGUI extends JFrame
+{
+ private static final String NO_SPLASH_OPTION = "-nosplash";
+
+ private static final String TITLE_IMAGE_FILE = "vtitle.gif";
+ private static final String BOILERPLATE_CONFIGURATION = "boilerplate.pro";
+ private static final String DEFAULT_CONFIGURATION = "default.pro";
+
+ private static final String KEEP_ATTRIBUTE_DEFAULT = "InnerClasses,SourceFile,LineNumberTable,Deprecated,Signature,*Annotation*,EnclosingMethod";
+ private static final String SOURCE_FILE_ATTRIBUTE_DEFAULT = "SourceFile";
+
+ private static final Border BORDER = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
+
+ static boolean systemOutRedirected;
+
+ private JFileChooser configurationChooser = new JFileChooser("");
+ private JFileChooser fileChooser = new JFileChooser("");
+
+ private SplashPanel splashPanel;
+
+ private ClassPathPanel programPanel = new ClassPathPanel(this, true);
+ private ClassPathPanel libraryPanel = new ClassPathPanel(this, false);
+
+ private ClassSpecification[] boilerplateKeep;
+ private JCheckBox[] boilerplateKeepCheckBoxes;
+ private JTextField[] boilerplateKeepTextFields;
+
+ private ClassSpecificationsPanel additionalKeepPanel = new ClassSpecificationsPanel(this, true);
+
+ private ClassSpecification[] boilerplateKeepNames;
+ private JCheckBox[] boilerplateKeepNamesCheckBoxes;
+ private JTextField[] boilerplateKeepNamesTextFields;
+
+ private ClassSpecificationsPanel additionalKeepNamesPanel = new ClassSpecificationsPanel(this, true);
+
+ private ClassSpecification[] boilerplateNoSideEffectMethods;
+ private JCheckBox[] boilerplateNoSideEffectMethodCheckBoxes;
+
+ private ClassSpecificationsPanel additionalNoSideEffectsPanel = new ClassSpecificationsPanel(this, false);
+
+ private JCheckBox shrinkCheckBox = new JCheckBox(msg("shrink"));
+ private JCheckBox printUsageCheckBox = new JCheckBox(msg("printUsage"));
+
+ private JCheckBox optimizeCheckBox = new JCheckBox(msg("optimize"));
+ private JCheckBox allowAccessModificationCheckBox = new JCheckBox(msg("allowAccessModification"));
+
+ private JCheckBox obfuscateCheckBox = new JCheckBox(msg("obfuscate"));
+ private JCheckBox printMappingCheckBox = new JCheckBox(msg("printMapping"));
+ private JCheckBox applyMappingCheckBox = new JCheckBox(msg("applyMapping"));
+ private JCheckBox obfuscationDictionaryCheckBox = new JCheckBox(msg("obfuscationDictionary"));
+ private JCheckBox overloadAggressivelyCheckBox = new JCheckBox(msg("overloadAggressively"));
+ private JCheckBox defaultPackageCheckBox = new JCheckBox(msg("defaultPackage"));
+ private JCheckBox useMixedCaseClassNamesCheckBox = new JCheckBox(msg("useMixedCaseClassNames"));
+ private JCheckBox keepAttributesCheckBox = new JCheckBox(msg("keepAttributes"));
+ private JCheckBox newSourceFileAttributeCheckBox = new JCheckBox(msg("renameSourceFileAttribute"));
+
+ private JCheckBox printSeedsCheckBox = new JCheckBox(msg("printSeeds"));
+ private JCheckBox verboseCheckBox = new JCheckBox(msg("verbose"));
+ private JCheckBox ignoreWarningsCheckBox = new JCheckBox(msg("ignoreWarnings"));
+ private JCheckBox warnCheckBox = new JCheckBox(msg("warn"));
+ private JCheckBox noteCheckBox = new JCheckBox(msg("note"));
+ private JCheckBox skipNonPublicLibraryClassesCheckBox = new JCheckBox(msg("skipNonPublicLibraryClasses"));
+ private JCheckBox skipNonPublicLibraryClassMembersCheckBox = new JCheckBox(msg("skipNonPublicLibraryClassMembers"));
+
+ private JTextField printUsageTextField = new JTextField(40);
+ private JTextField printMappingTextField = new JTextField(40);
+ private JTextField applyMappingTextField = new JTextField(40);
+ private JTextField obfuscationDictionaryTextField = new JTextField(40);
+ private JTextField defaultPackageTextField = new JTextField(40);
+ private JTextField keepAttributesTextField = new JTextField(40);
+ private JTextField newSourceFileAttributeTextField = new JTextField(40);
+ private JTextField printSeedsTextField = new JTextField(40);
+
+ private JTextArea consoleTextArea = new JTextArea(msg("processingInfo"), 3, 40);
+
+ private JTextField reTraceMappingTextField = new JTextField(40);
+ private JCheckBox reTraceVerboseCheckBox = new JCheckBox(msg("verbose"));
+ private JTextArea stackTraceTextArea = new JTextArea(3, 40);
+ private JTextArea reTraceTextArea = new JTextArea(msg("reTraceInfo"), 3, 40);
+
+
+ /**
+ * Creates a new ProGuardGUI.
+ */
+ public ProGuardGUI()
+ {
+ setTitle("ProGuard");
+ setDefaultCloseOperation(EXIT_ON_CLOSE);
+
+ // Create some constraints that can be reused.
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 4, 0, 4);
+
+ GridBagConstraints constraintsStretch = new GridBagConstraints();
+ constraintsStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsStretch.weightx = 1.0;
+ constraintsStretch.anchor = GridBagConstraints.WEST;
+ constraintsStretch.insets = constraints.insets;
+
+ GridBagConstraints constraintsLast = new GridBagConstraints();
+ constraintsLast.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLast.anchor = GridBagConstraints.WEST;
+ constraintsLast.insets = constraints.insets;
+
+ GridBagConstraints constraintsLastStretch = new GridBagConstraints();
+ constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsLastStretch.weightx = 1.0;
+ constraintsLastStretch.anchor = GridBagConstraints.WEST;
+ constraintsLastStretch.insets = constraints.insets;
+
+ GridBagConstraints splashPanelConstraints = new GridBagConstraints();
+ splashPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ splashPanelConstraints.fill = GridBagConstraints.BOTH;
+ splashPanelConstraints.weightx = 1.0;
+ splashPanelConstraints.weighty = 0.02;
+ splashPanelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ //splashPanelConstraints.insets = constraints.insets;
+
+ GridBagConstraints welcomeTextAreaConstraints = new GridBagConstraints();
+ welcomeTextAreaConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ welcomeTextAreaConstraints.fill = GridBagConstraints.NONE;
+ welcomeTextAreaConstraints.weightx = 1.0;
+ welcomeTextAreaConstraints.weighty = 0.01;
+ welcomeTextAreaConstraints.anchor = GridBagConstraints.CENTER;//NORTHWEST;
+ welcomeTextAreaConstraints.insets = new Insets(20, 40, 20, 40);
+
+ GridBagConstraints panelConstraints = new GridBagConstraints();
+ panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ panelConstraints.fill = GridBagConstraints.HORIZONTAL;
+ panelConstraints.weightx = 1.0;
+ panelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ panelConstraints.insets = constraints.insets;
+
+ GridBagConstraints stretchPanelConstraints = new GridBagConstraints();
+ stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ stretchPanelConstraints.fill = GridBagConstraints.BOTH;
+ stretchPanelConstraints.weightx = 1.0;
+ stretchPanelConstraints.weighty = 1.0;
+ stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ stretchPanelConstraints.insets = constraints.insets;
+
+ GridBagConstraints glueConstraints = new GridBagConstraints();
+ glueConstraints.fill = GridBagConstraints.BOTH;
+ glueConstraints.weightx = 0.01;
+ glueConstraints.weighty = 0.01;
+ glueConstraints.anchor = GridBagConstraints.NORTHWEST;
+ glueConstraints.insets = constraints.insets;
+
+ GridBagConstraints bottomButtonConstraints = new GridBagConstraints();
+ bottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ bottomButtonConstraints.insets = new Insets(2, 2, 4, 6);
+ bottomButtonConstraints.ipadx = 10;
+ bottomButtonConstraints.ipady = 2;
+
+ GridBagConstraints lastBottomButtonConstraints = new GridBagConstraints();
+ lastBottomButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ lastBottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ lastBottomButtonConstraints.insets = bottomButtonConstraints.insets;
+ lastBottomButtonConstraints.ipadx = bottomButtonConstraints.ipadx;
+ lastBottomButtonConstraints.ipady = bottomButtonConstraints.ipady;
+
+ GridBagLayout layout = new GridBagLayout();
+
+ configurationChooser.addChoosableFileFilter(
+ new ExtensionFileFilter(msg("proExtension"), new String[] { ".pro" }));
+
+ // Create the opening panel.
+ //JLabel titleLabel = new JLabel("ProGuard", JLabel.CENTER);
+ //titleLabel.setFont(new Font("serif", Font.BOLD, 40));
+ //titleLabel.setForeground(Color.gray);
+
+ Font font = new Font("sansserif", Font.BOLD, 50);
+ Color fontColor = Color.white;
+
+ Sprite splash =
+ new CompositeSprite(new Sprite[]
+ {
+ new TextSprite(new ConstantString("ProGuard"),
+ new ConstantFont(new Font("sansserif", Font.BOLD, 90)),
+ new ConstantColor(Color.gray),
+ new ConstantInt(160),
+ new LinearInt(-10, 120, new SmoothTiming(500, 1000))),
+
+ new ShadowedSprite(new ConstantInt(3),
+ new ConstantInt(3),
+ new ConstantDouble(0.4),
+ new ConstantInt(2),
+ new CompositeSprite(new Sprite[]
+ {
+ new TextSprite(new ConstantString(msg("shrinking")),
+ new ConstantFont(font),
+ new ConstantColor(fontColor),
+ new LinearInt(1000, 60, new SmoothTiming(1000, 2000)),
+ new ConstantInt(70)),
+ new TextSprite(new ConstantString(msg("optimization")),
+ new ConstantFont(font),
+ new ConstantColor(fontColor),
+ new LinearInt(1000, 400, new SmoothTiming(1500, 2500)),
+ new ConstantInt(60)),
+ new TextSprite(new ConstantString(msg("obfuscation")),
+ new ConstantFont(font),
+ new ConstantColor(fontColor),
+ new LinearInt(1000, 350, new SmoothTiming(2000, 3000)),
+ new ConstantInt(140)),
+ new TextSprite(new TypeWriterString(msg("developed"), new LinearTiming(3000, 5000)),
+ new ConstantFont(new Font("monospaced", Font.BOLD, 20)),
+ new ConstantColor(fontColor),
+ new ConstantInt(250),
+ new ConstantInt(170)),
+ })),
+ });
+ splashPanel = new SplashPanel(splash, 0.5, 5000L);
+ splashPanel.setPreferredSize(new Dimension(0, 200));
+
+ JTextArea welcomeTextArea = new JTextArea(msg("proGuardInfo"), 18, 50);
+ welcomeTextArea.setOpaque(false);
+ welcomeTextArea.setEditable(false);
+ welcomeTextArea.setLineWrap(true);
+ welcomeTextArea.setWrapStyleWord(true);
+ welcomeTextArea.setPreferredSize(new Dimension(0, 0));
+ welcomeTextArea.setBorder(new EmptyBorder(20, 20, 20, 20));
+ addBorder(welcomeTextArea, "welcome");
+
+ JPanel proGuardPanel = new JPanel(layout);
+ proGuardPanel.add(splashPanel, splashPanelConstraints);
+ proGuardPanel.add(welcomeTextArea, welcomeTextAreaConstraints);
+
+ // Create the input panel.
+ // TODO: properly clone the ClassPath objects.
+ // This is awkward to implement in the generic ListPanel.addElements(...)
+ // method, since the Object.clone() method is not public.
+ programPanel.addCopyToPanelButton(msg("moveToLibraries"), libraryPanel);
+ libraryPanel.addCopyToPanelButton(msg("moveToProgram"), programPanel);
+
+ // Collect all buttons of these panels and make sure they are equally
+ // sized.
+ List panelButtons = new ArrayList();
+ panelButtons.addAll(programPanel.getButtons());
+ panelButtons.addAll(libraryPanel.getButtons());
+ setCommonPreferredSize(panelButtons);
+ panelButtons = null;
+
+ addBorder(programPanel, "programJars" );
+ addBorder(libraryPanel, "libraryJars" );
+
+ JPanel inputOutputPanel = new JPanel(layout);
+ inputOutputPanel.add(programPanel, stretchPanelConstraints);
+ inputOutputPanel.add(libraryPanel, stretchPanelConstraints);
+
+ // Load the boiler plate options.
+ loadBoilerplateConfiguration();
+
+ // Create the boiler plate keep panels.
+ boilerplateKeepCheckBoxes = new JCheckBox[boilerplateKeep.length];
+ boilerplateKeepTextFields = new JTextField[boilerplateKeep.length];
+
+ JButton printUsageBrowseButton = createBrowseButton(printUsageTextField,
+ msg("selectUsageFile"));
+
+ JPanel shrinkingOptionsPanel = new JPanel(layout);
+ addBorder(shrinkingOptionsPanel, "options");
+
+ shrinkingOptionsPanel.add(shrinkCheckBox, constraintsLastStretch);
+ shrinkingOptionsPanel.add(printUsageCheckBox, constraints);
+ shrinkingOptionsPanel.add(printUsageTextField, constraintsStretch);
+ shrinkingOptionsPanel.add(printUsageBrowseButton, constraintsLast);
+
+ JPanel shrinkingPanel = new JPanel(layout);
+
+ shrinkingPanel.add(shrinkingOptionsPanel, panelConstraints);
+ addClassSpecifications(boilerplateKeep,
+ shrinkingPanel,
+ boilerplateKeepCheckBoxes,
+ boilerplateKeepTextFields);
+
+ addBorder(additionalKeepPanel, "keepAdditional");
+ shrinkingPanel.add(additionalKeepPanel, stretchPanelConstraints);
+
+ // Create the boiler plate keep names panels.
+ boilerplateKeepNamesCheckBoxes = new JCheckBox[boilerplateKeepNames.length];
+ boilerplateKeepNamesTextFields = new JTextField[boilerplateKeepNames.length];
+
+ JButton printMappingBrowseButton = createBrowseButton(printMappingTextField,
+ msg("selectPrintMappingFile"));
+ JButton applyMappingBrowseButton = createBrowseButton(applyMappingTextField,
+ msg("selectApplyMappingFile"));
+ JButton obfucationDictionaryBrowseButton = createBrowseButton(obfuscationDictionaryTextField,
+ msg("selectObfuscationDictionaryFile"));
+
+ JPanel obfuscationOptionsPanel = new JPanel(layout);
+ addBorder(obfuscationOptionsPanel, "options");
+
+ obfuscationOptionsPanel.add(obfuscateCheckBox, constraintsLastStretch);
+ obfuscationOptionsPanel.add(printMappingCheckBox, constraints);
+ obfuscationOptionsPanel.add(printMappingTextField, constraintsStretch);
+ obfuscationOptionsPanel.add(printMappingBrowseButton, constraintsLast);
+ obfuscationOptionsPanel.add(applyMappingCheckBox, constraints);
+ obfuscationOptionsPanel.add(applyMappingTextField, constraintsStretch);
+ obfuscationOptionsPanel.add(applyMappingBrowseButton, constraintsLast);
+ obfuscationOptionsPanel.add(obfuscationDictionaryCheckBox, constraints);
+ obfuscationOptionsPanel.add(obfuscationDictionaryTextField, constraintsStretch);
+ obfuscationOptionsPanel.add(obfucationDictionaryBrowseButton, constraintsLast);
+ obfuscationOptionsPanel.add(overloadAggressivelyCheckBox, constraintsLastStretch);
+ obfuscationOptionsPanel.add(defaultPackageCheckBox, constraints);
+ obfuscationOptionsPanel.add(defaultPackageTextField, constraintsLastStretch);
+ obfuscationOptionsPanel.add(useMixedCaseClassNamesCheckBox, constraintsLastStretch);
+ obfuscationOptionsPanel.add(keepAttributesCheckBox, constraints);
+ obfuscationOptionsPanel.add(keepAttributesTextField, constraintsLastStretch);
+ obfuscationOptionsPanel.add(newSourceFileAttributeCheckBox, constraints);
+ obfuscationOptionsPanel.add(newSourceFileAttributeTextField, constraintsLastStretch);
+
+ JPanel obfuscationPanel = new JPanel(layout);
+
+ obfuscationPanel.add(obfuscationOptionsPanel, panelConstraints);
+ addClassSpecifications(boilerplateKeepNames,
+ obfuscationPanel,
+ boilerplateKeepNamesCheckBoxes,
+ boilerplateKeepNamesTextFields);
+
+ addBorder(additionalKeepNamesPanel, "keepNamesAdditional");
+ obfuscationPanel.add(additionalKeepNamesPanel, stretchPanelConstraints);
+
+ // Create the boiler plate "no side effect methods" panels.
+ boilerplateNoSideEffectMethodCheckBoxes = new JCheckBox[boilerplateNoSideEffectMethods.length];
+
+ JPanel optimizationOptionsPanel = new JPanel(layout);
+ addBorder(optimizationOptionsPanel, "options");
+
+ optimizationOptionsPanel.add(optimizeCheckBox, constraintsLastStretch);
+ optimizationOptionsPanel.add(allowAccessModificationCheckBox, constraintsLastStretch);
+
+ JPanel optimizationPanel = new JPanel(layout);
+
+ optimizationPanel.add(optimizationOptionsPanel, panelConstraints);
+ addClassSpecifications(boilerplateNoSideEffectMethods,
+ optimizationPanel,
+ boilerplateNoSideEffectMethodCheckBoxes,
+ null);
+
+ addBorder(additionalNoSideEffectsPanel, "assumeNoSideEffectsAdditional");
+ optimizationPanel.add(additionalNoSideEffectsPanel, stretchPanelConstraints);
+
+ // Create the options panel.
+ JButton printSeedsBrowseButton = createBrowseButton(printSeedsTextField,
+ msg("selectSeedsFile"));
+
+ JPanel consistencyPanel = new JPanel(layout);
+ addBorder(consistencyPanel, "consistencyAndCorrectness");
+
+ consistencyPanel.add(printSeedsCheckBox, constraints);
+ consistencyPanel.add(printSeedsTextField, constraintsStretch);
+ consistencyPanel.add(printSeedsBrowseButton, constraintsLast);
+ consistencyPanel.add(verboseCheckBox, constraintsLastStretch);
+ consistencyPanel.add(noteCheckBox, constraintsLastStretch);
+ consistencyPanel.add(warnCheckBox, constraintsLastStretch);
+ consistencyPanel.add(ignoreWarningsCheckBox, constraintsLastStretch);
+ consistencyPanel.add(skipNonPublicLibraryClassesCheckBox, constraintsLastStretch);
+ consistencyPanel.add(skipNonPublicLibraryClassMembersCheckBox, constraintsLastStretch);
+
+ // Collect all components that are followed by text fields and make
+ // sure they are equally sized. That way the text fields start at the
+ // same horizontal position.
+ setCommonPreferredSize(Arrays.asList(new JComponent[] {
+ printMappingCheckBox,
+ applyMappingCheckBox,
+ defaultPackageCheckBox,
+ newSourceFileAttributeCheckBox,
+ }));
+
+ JPanel optionsPanel = new JPanel(layout);
+
+ optionsPanel.add(consistencyPanel, panelConstraints);
+
+ // Create the process panel.
+ consoleTextArea.setOpaque(false);
+ consoleTextArea.setEditable(false);
+ consoleTextArea.setLineWrap(false);
+ consoleTextArea.setWrapStyleWord(false);
+ JScrollPane consoleScrollPane = new JScrollPane(consoleTextArea);
+ consoleScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1));
+ addBorder(consoleScrollPane, "processingConsole");
+
+ JPanel processPanel = new JPanel(layout);
+ processPanel.add(consoleScrollPane, stretchPanelConstraints);
+
+ // Create the load, save, and process buttons.
+ JButton loadButton = new JButton(msg("loadConfiguration"));
+ loadButton.addActionListener(new MyLoadConfigurationActionListener());
+
+ JButton viewButton = new JButton(msg("viewConfiguration"));
+ viewButton.addActionListener(new MyViewConfigurationActionListener());
+
+ JButton saveButton = new JButton(msg("saveConfiguration"));
+ saveButton.addActionListener(new MySaveConfigurationActionListener());
+
+ JButton processButton = new JButton(msg("process"));
+ processButton.addActionListener(new MyProcessActionListener());
+
+ // Create the ReTrace panel.
+ JPanel reTraceSettingsPanel = new JPanel(layout);
+ addBorder(reTraceSettingsPanel, "reTraceSettings");
+
+ JButton reTraceMappingBrowseButton = createBrowseButton(reTraceMappingTextField,
+ msg("selectApplyMappingFile"));
+
+ JLabel reTraceMappingLabel = new JLabel(msg("mappingFile"));
+ reTraceMappingLabel.setForeground(reTraceVerboseCheckBox.getForeground());
+
+ reTraceSettingsPanel.add(reTraceMappingLabel, constraints);
+ reTraceSettingsPanel.add(reTraceMappingTextField, constraintsStretch);
+ reTraceSettingsPanel.add(reTraceMappingBrowseButton, constraintsLast);
+ reTraceSettingsPanel.add(reTraceVerboseCheckBox, constraintsLastStretch);
+
+ stackTraceTextArea.setOpaque(true);
+ stackTraceTextArea.setEditable(true);
+ stackTraceTextArea.setLineWrap(false);
+ stackTraceTextArea.setWrapStyleWord(true);
+ JScrollPane stackTraceScrollPane = new JScrollPane(stackTraceTextArea);
+ addBorder(stackTraceScrollPane, "obfuscatedStackTrace");
+
+ reTraceTextArea.setOpaque(false);
+ reTraceTextArea.setEditable(false);
+ reTraceTextArea.setLineWrap(true);
+ reTraceTextArea.setWrapStyleWord(true);
+ JScrollPane reTraceScrollPane = new JScrollPane(reTraceTextArea);
+ reTraceScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1));
+ addBorder(reTraceScrollPane, "deobfuscatedStackTrace");
+
+ JPanel reTracePanel = new JPanel(layout);
+ reTracePanel.add(reTraceSettingsPanel, panelConstraints);
+ reTracePanel.add(stackTraceScrollPane, panelConstraints);
+ reTracePanel.add(reTraceScrollPane, stretchPanelConstraints);
+
+ // Create the load button.
+ JButton loadStackTraceButton = new JButton(msg("loadStackTrace"));
+ loadStackTraceButton.addActionListener(new MyLoadStackTraceActionListener());
+
+ JButton reTraceButton = new JButton(msg("reTrace"));
+ reTraceButton.addActionListener(new MyReTraceActionListener());
+
+ // Create the main tabbed pane.
+ TabbedPane tabs = new TabbedPane();
+ tabs.add(msg("proGuardTab"), proGuardPanel);
+ tabs.add(msg("inputOutputTab"), inputOutputPanel);
+ tabs.add(msg("shrinkingTab"), shrinkingPanel);
+ tabs.add(msg("obfuscationTab"), obfuscationPanel);
+ tabs.add(msg("optimizationTab"), optimizationPanel);
+ tabs.add(msg("informationTab"), optionsPanel);
+ tabs.add(msg("processTab"), processPanel);
+ tabs.add(msg("reTraceTab"), reTracePanel);
+ tabs.addImage(Toolkit.getDefaultToolkit().getImage(
+ this.getClass().getResource(TITLE_IMAGE_FILE)));
+
+ // Add the bottom buttons to each panel.
+ proGuardPanel .add(Box.createGlue(), glueConstraints);
+ proGuardPanel .add(loadButton, bottomButtonConstraints);
+ proGuardPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ inputOutputPanel .add(Box.createGlue(), glueConstraints);
+ inputOutputPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ inputOutputPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ shrinkingPanel .add(Box.createGlue(), glueConstraints);
+ shrinkingPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ shrinkingPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ obfuscationPanel .add(Box.createGlue(), glueConstraints);
+ obfuscationPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ obfuscationPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ optimizationPanel .add(Box.createGlue(), glueConstraints);
+ optimizationPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ optimizationPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ optionsPanel .add(Box.createGlue(), glueConstraints);
+ optionsPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ optionsPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ processPanel .add(Box.createGlue(), glueConstraints);
+ processPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ processPanel .add(viewButton, bottomButtonConstraints);
+ processPanel .add(saveButton, bottomButtonConstraints);
+ processPanel .add(processButton, lastBottomButtonConstraints);
+
+ reTracePanel .add(Box.createGlue(), glueConstraints);
+ reTracePanel .add(loadStackTraceButton, bottomButtonConstraints);
+ reTracePanel .add(reTraceButton, lastBottomButtonConstraints);
+
+ // Initialize the GUI settings to reasonable defaults.
+ loadConfiguration(this.getClass().getResource(DEFAULT_CONFIGURATION));
+
+ // Add the main tabs to the frame and pack it.
+ getContentPane().add(tabs);
+ }
+
+
+ public void startSplash()
+ {
+ splashPanel.start();
+ }
+
+
+ public void skipSplash()
+ {
+ splashPanel.stop();
+ }
+
+
+ /**
+ * Loads the boilerplate keep class file options from the boilerplate file
+ * into the boilerplate array.
+ */
+ private void loadBoilerplateConfiguration()
+ {
+ try
+ {
+ // Parse the boilerplate configuration file.
+ ConfigurationParser parser = new ConfigurationParser(
+ this.getClass().getResource(BOILERPLATE_CONFIGURATION));
+ Configuration configuration = new Configuration();
+ parser.parse(configuration);
+
+ // We're interested in the keep options.
+ boilerplateKeep = new ClassSpecification[configuration.keep.size()];
+ configuration.keep.toArray(boilerplateKeep);
+
+ // We're interested in the keep names options.
+ boilerplateKeepNames = new ClassSpecification[configuration.keepNames.size()];
+ configuration.keepNames.toArray(boilerplateKeepNames);
+
+ // We're interested in the side effects options.
+ boilerplateNoSideEffectMethods = new ClassSpecification[configuration.assumeNoSideEffects.size()];
+ configuration.assumeNoSideEffects.toArray(boilerplateNoSideEffectMethods);
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Creates a panel with the given boiler plate class specifications.
+ */
+ private void addClassSpecifications(ClassSpecification[] boilerplateClassSpecifications,
+ JPanel classSpecificationsPanel,
+ JCheckBox[] boilerplateCheckBoxes,
+ JTextField[] boilerplateTextFields)
+ {
+ // Create some constraints that can be reused.
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 4, 0, 4);
+
+ GridBagConstraints constraintsLastStretch = new GridBagConstraints();
+ constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsLastStretch.weightx = 1.0;
+ constraintsLastStretch.anchor = GridBagConstraints.WEST;
+ constraintsLastStretch.insets = constraints.insets;
+
+ GridBagConstraints panelConstraints = new GridBagConstraints();
+ panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ panelConstraints.fill = GridBagConstraints.HORIZONTAL;
+ panelConstraints.weightx = 1.0;
+ panelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ panelConstraints.insets = constraints.insets;
+
+ GridBagLayout layout = new GridBagLayout();
+
+ String lastPanelName = null;
+ JPanel keepSubpanel = null;
+ for (int index = 0; index < boilerplateClassSpecifications.length; index++)
+ {
+ ClassSpecification classSpecification =
+ boilerplateClassSpecifications[index];
+
+ // The panel structure is derived from the comments.
+ String comments = classSpecification.comments;
+ int dashIndex = comments.indexOf('-');
+ int periodIndex = comments.indexOf('.', dashIndex);
+ String panelName = comments.substring(0, dashIndex).trim();
+ String optionName = comments.substring(dashIndex + 1, periodIndex).trim();
+ if (!panelName.equals(lastPanelName))
+ {
+ // Create a new keep subpanel and add it.
+ keepSubpanel = new JPanel(layout);
+ String titleKey = "boilerplate_" + panelName.toLowerCase().replace(' ', '_');
+ addBorder(keepSubpanel, titleKey);
+ classSpecificationsPanel.add(keepSubpanel, panelConstraints);
+
+ lastPanelName = panelName;
+ }
+
+ // Add the check box to the subpanel.
+ String messageKey = "boilerplate_" + optionName.toLowerCase().replace(' ', '_');
+ boilerplateCheckBoxes[index] = new JCheckBox(msg(messageKey));
+ keepSubpanel.add(boilerplateCheckBoxes[index],
+ boilerplateTextFields != null ?
+ constraints :
+ constraintsLastStretch);
+
+ if (boilerplateTextFields != null)
+ {
+ // Add the text field to the subpanel.
+ boilerplateTextFields[index] = new JTextField(40);
+ keepSubpanel.add(boilerplateTextFields[index], constraintsLastStretch);
+ }
+ }
+ }
+
+
+ /**
+ * Adds a standard border with the title that corresponds to the given key
+ * in the GUI resources.
+ */
+ private void addBorder(JComponent component, String titleKey)
+ {
+ Border oldBorder = component.getBorder();
+ Border newBorder = BorderFactory.createTitledBorder(BORDER, msg(titleKey));
+
+ component.setBorder(oldBorder == null ?
+ newBorder :
+ new CompoundBorder(newBorder, oldBorder));
+ }
+
+
+ /**
+ * Creates a Previous button for the given tabbed pane.
+ */
+ private JButton createPreviousButton(final TabbedPane tabbedPane)
+ {
+ JButton browseButton = new JButton(msg("previous"));
+ browseButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ tabbedPane.previous();
+ }
+ });
+
+ return browseButton;
+ }
+
+
+ /**
+ * Creates a Next button for the given tabbed pane.
+ */
+ private JButton createNextButton(final TabbedPane tabbedPane)
+ {
+ JButton browseButton = new JButton(msg("next"));
+ browseButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ tabbedPane.next();
+ }
+ });
+
+ return browseButton;
+ }
+
+
+ /**
+ * Creates a browse button that opens a file browser for the given text field.
+ */
+ private JButton createBrowseButton(final JTextField textField,
+ final String title)
+ {
+ JButton browseButton = new JButton(msg("browse"));
+ browseButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ fileChooser.setDialogTitle(title);
+ fileChooser.setSelectedFile(new File(textField.getText()));
+
+ int returnVal = fileChooser.showDialog(ProGuardGUI.this, msg("ok"));
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
+ textField.setText(fileChooser.getSelectedFile().getPath());
+ }
+ }
+ });
+
+ return browseButton;
+ }
+
+
+ /**
+ * Sets the preferred sizes of the given components to the maximum of their
+ * current preferred sizes.
+ */
+ private void setCommonPreferredSize(List components)
+ {
+ // Find the maximum preferred size.
+ Dimension maximumSize = null;
+ for (int index = 0; index < components.size(); index++)
+ {
+ JComponent component = (JComponent)components.get(index);
+ Dimension size = component.getPreferredSize();
+ if (maximumSize == null ||
+ size.getWidth() > maximumSize.getWidth())
+ {
+ maximumSize = size;
+ }
+ }
+
+ // Set the size that we found as the preferred size for all components.
+ for (int index = 0; index < components.size(); index++)
+ {
+ JComponent component = (JComponent)components.get(index);
+ component.setPreferredSize(maximumSize);
+ }
+ }
+
+
+ /**
+ * Updates to GUI settings to reflect the given ProGuard configuration.
+ */
+ private void setProGuardConfiguration(Configuration configuration)
+ {
+ // Set up the input and output jars and directories.
+ programPanel.setClassPath(configuration.programJars);
+ libraryPanel.setClassPath(configuration.libraryJars);
+
+ // Set up the boilerplate keep options.
+ for (int index = 0; index < boilerplateKeep.length; index++)
+ {
+ String classNames =
+ findMatchingClassSpecifications(boilerplateKeep[index],
+ configuration.keep);
+
+ boilerplateKeepCheckBoxes[index].setSelected(classNames != null);
+ boilerplateKeepTextFields[index].setText(classNames == null ? "*" : classNames);
+ }
+
+ // Set up the additional keep options. Note that the matched boilerplate
+ // options have been removed from the list.
+ additionalKeepPanel.setClassSpecifications(configuration.keep);
+
+
+ // Set up the boilerplate keep names options.
+ for (int index = 0; index < boilerplateKeepNames.length; index++)
+ {
+ String classNames =
+ findMatchingClassSpecifications(boilerplateKeepNames[index],
+ configuration.keepNames);
+
+ boilerplateKeepNamesCheckBoxes[index].setSelected(classNames != null);
+ boilerplateKeepNamesTextFields[index].setText(classNames == null ? "*" : classNames);
+ }
+
+ // Set up the additional keep options. Note that the matched boilerplate
+ // options have been removed from the list.
+ additionalKeepNamesPanel.setClassSpecifications(configuration.keepNames);
+
+
+ // Set up the boilerplate "no side effect methods" options.
+ for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++)
+ {
+ boolean found =
+ findClassSpecification(boilerplateNoSideEffectMethods[index],
+ configuration.assumeNoSideEffects);
+
+ boilerplateNoSideEffectMethodCheckBoxes[index].setSelected(found);
+ }
+
+ // Set up the additional keep options. Note that the matched boilerplate
+ // options have been removed from the list.
+ additionalNoSideEffectsPanel.setClassSpecifications(configuration.assumeNoSideEffects);
+
+ // Set up the other options.
+ shrinkCheckBox .setSelected(configuration.shrink);
+ printUsageCheckBox .setSelected(configuration.printUsage != null);
+
+ optimizeCheckBox .setSelected(configuration.optimize);
+ allowAccessModificationCheckBox .setSelected(configuration.allowAccessModification);
+
+ obfuscateCheckBox .setSelected(configuration.obfuscate);
+ printMappingCheckBox .setSelected(configuration.printMapping != null);
+ applyMappingCheckBox .setSelected(configuration.applyMapping != null);
+ obfuscationDictionaryCheckBox .setSelected(configuration.defaultPackage != null);
+ overloadAggressivelyCheckBox .setSelected(configuration.overloadAggressively);
+ defaultPackageCheckBox .setSelected(configuration.obfuscationDictionary != null);
+ useMixedCaseClassNamesCheckBox .setSelected(configuration.useMixedCaseClassNames);
+ keepAttributesCheckBox .setSelected(configuration.keepAttributes != null);
+ newSourceFileAttributeCheckBox .setSelected(configuration.newSourceFileAttribute != null);
+
+ printSeedsCheckBox .setSelected(configuration.printSeeds != null);
+ verboseCheckBox .setSelected(configuration.verbose);
+ noteCheckBox .setSelected(configuration.note);
+ warnCheckBox .setSelected(configuration.warn);
+ ignoreWarningsCheckBox .setSelected(configuration.ignoreWarnings);
+ skipNonPublicLibraryClassesCheckBox .setSelected(configuration.skipNonPublicLibraryClasses);
+ skipNonPublicLibraryClassMembersCheckBox.setSelected(configuration.skipNonPublicLibraryClassMembers);
+
+ printUsageTextField .setText(configuration.printUsage);
+ printMappingTextField .setText(configuration.printMapping);
+ applyMappingTextField .setText(configuration.applyMapping);
+ obfuscationDictionaryTextField .setText(configuration.obfuscationDictionary);
+ defaultPackageTextField .setText(configuration.defaultPackage);
+ keepAttributesTextField .setText(configuration.keepAttributes == null ? KEEP_ATTRIBUTE_DEFAULT : ListUtil.commaSeparatedString(configuration.keepAttributes));
+ newSourceFileAttributeTextField .setText(configuration.newSourceFileAttribute == null ? SOURCE_FILE_ATTRIBUTE_DEFAULT : configuration.newSourceFileAttribute);
+ printSeedsTextField .setText(configuration.printSeeds);
+
+ if (configuration.printMapping != null)
+ {
+ reTraceMappingTextField.setText(configuration.printMapping);
+ }
+ }
+
+
+ /**
+ * Returns the ProGuard configuration that reflects the current GUI settings.
+ */
+ private Configuration getProGuardConfiguration()
+ {
+ Configuration configuration = new Configuration();
+
+ // Get the input and output jars and directories.
+ configuration.programJars = programPanel.getClassPath();
+ configuration.libraryJars = libraryPanel.getClassPath();
+
+ // Collect the boilerplate keep options.
+ List keep = new ArrayList();
+
+ for (int index = 0; index < boilerplateKeep.length; index++)
+ {
+ if (boilerplateKeepCheckBoxes[index].isSelected())
+ {
+ addClassSpecifications(keep,
+ boilerplateKeep[index],
+ boilerplateKeepTextFields[index].getText());
+ }
+ }
+
+ // Collect the additional keep options.
+ List additionalKeep = additionalKeepPanel.getClassSpecifications();
+ if (additionalKeep != null)
+ {
+ keep.addAll(additionalKeep);
+ }
+
+ // Put the list of keep options in the configuration.
+ if (keep.size() > 0)
+ {
+ configuration.keep = keep;
+ }
+
+
+ // Collect the boilerplate keep names options.
+ List keepNames = new ArrayList();
+
+ for (int index = 0; index < boilerplateKeepNames.length; index++)
+ {
+ if (boilerplateKeepNamesCheckBoxes[index].isSelected())
+ {
+ addClassSpecifications(keepNames,
+ boilerplateKeepNames[index],
+ boilerplateKeepNamesTextFields[index].getText());
+ }
+ }
+
+ // Collect the additional keep names options.
+ List additionalKeepNames = additionalKeepNamesPanel.getClassSpecifications();
+ if (additionalKeepNames != null)
+ {
+ keepNames.addAll(additionalKeepNames);
+ }
+
+ // Put the list of keep names options in the configuration.
+ if (keepNames.size() > 0)
+ {
+ configuration.keepNames = keepNames;
+ }
+
+
+ // Collect the boilerplate "no side effect methods" options.
+ List noSideEffectMethods = new ArrayList();
+
+ for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++)
+ {
+ if (boilerplateNoSideEffectMethodCheckBoxes[index].isSelected())
+ {
+ noSideEffectMethods.add(boilerplateNoSideEffectMethods[index]);
+ }
+ }
+
+ // Collect the additional "no side effect methods" options.
+ List additionalNoSideEffectOptions = additionalNoSideEffectsPanel.getClassSpecifications();
+ if (additionalNoSideEffectOptions != null)
+ {
+ noSideEffectMethods.addAll(additionalNoSideEffectOptions);
+ }
+
+ // Put the list of "no side effect methods" options in the configuration.
+ if (noSideEffectMethods.size() > 0)
+ {
+ configuration.assumeNoSideEffects = noSideEffectMethods;
+ }
+
+
+ // Get the other options.
+ configuration.shrink = shrinkCheckBox .isSelected();
+ configuration.printUsage = printUsageCheckBox .isSelected() ? printUsageTextField .getText() : null;
+
+ configuration.optimize = optimizeCheckBox .isSelected();
+ configuration.allowAccessModification = allowAccessModificationCheckBox .isSelected();
+
+ configuration.obfuscate = obfuscateCheckBox .isSelected();
+ configuration.printMapping = printMappingCheckBox .isSelected() ? printMappingTextField .getText() : null;
+ configuration.applyMapping = applyMappingCheckBox .isSelected() ? applyMappingTextField .getText() : null;
+ configuration.obfuscationDictionary = obfuscationDictionaryCheckBox .isSelected() ? obfuscationDictionaryTextField .getText() : null;
+ configuration.overloadAggressively = overloadAggressivelyCheckBox .isSelected();
+ configuration.defaultPackage = defaultPackageCheckBox .isSelected() ? defaultPackageTextField .getText() : null;
+ configuration.useMixedCaseClassNames = useMixedCaseClassNamesCheckBox .isSelected();
+ configuration.keepAttributes = keepAttributesCheckBox .isSelected() ? ListUtil.commaSeparatedList(keepAttributesTextField.getText()) : null;
+ configuration.newSourceFileAttribute = newSourceFileAttributeCheckBox .isSelected() ? newSourceFileAttributeTextField .getText() : null;
+
+ configuration.printSeeds = printSeedsCheckBox .isSelected() ? printSeedsTextField .getText() : null;
+ configuration.verbose = verboseCheckBox .isSelected();
+ configuration.note = noteCheckBox .isSelected();
+ configuration.warn = warnCheckBox .isSelected();
+ configuration.ignoreWarnings = ignoreWarningsCheckBox .isSelected();
+ configuration.skipNonPublicLibraryClasses = skipNonPublicLibraryClassesCheckBox .isSelected();
+ configuration.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembersCheckBox.isSelected();
+
+ return configuration;
+ }
+
+
+ /**
+ * Looks in the given list for a ProGuard option that is identical to the
+ * given template. Returns true if it found, and removes the matching option
+ * as a side effect.
+ */
+ private boolean findClassSpecification(ClassSpecification classSpecificationTemplate,
+ List classSpecifications)
+ {
+ if (classSpecifications == null)
+ {
+ return false;
+ }
+
+ for (int index = 0; index < classSpecifications.size(); index++)
+ {
+ if (classSpecificationTemplate.equals(classSpecifications.get(index)))
+ {
+ // Remove the matching option as a side effect.
+ classSpecifications.remove(index);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Looks in the given list for ProGuard options that match the given template.
+ * Returns a comma-separated string of class file names from matching options,
+ * and removes the matching options as a side effect.
+ */
+ private String findMatchingClassSpecifications(ClassSpecification classSpecificationTemplate,
+ List classSpecifications)
+ {
+ if (classSpecifications == null)
+ {
+ return null;
+ }
+
+ StringBuffer buffer = null;
+
+ for (int index = 0; index < classSpecifications.size(); index++)
+ {
+ ClassSpecification listedClassSpecification =
+ (ClassSpecification)classSpecifications.get(index);
+ String className = listedClassSpecification.className;
+ classSpecificationTemplate.className = className;
+ if (classSpecificationTemplate.equals(listedClassSpecification))
+ {
+ if (buffer == null)
+ {
+ buffer = new StringBuffer();
+ }
+ else
+ {
+ buffer.append(',');
+ }
+ buffer.append(className == null ? "*" : ClassUtil.externalClassName(className));
+
+ // Remove the matching option as a side effect.
+ classSpecifications.remove(index--);
+ }
+ }
+
+ return buffer == null ? null : buffer.toString();
+ }
+
+
+ /**
+ * Adds ProGuard options to the given list, based on the given option
+ * template and the comma-separated list of class names to be filled in.
+ */
+ private void addClassSpecifications(List classSpecifications,
+ ClassSpecification classSpecificationTemplate,
+ String classNamesString)
+ {
+ List classNames = ListUtil.commaSeparatedList(classNamesString);
+
+ for (int index = 0; index < classNames.size(); index++)
+ {
+ String className = (String)classNames.get(index);
+
+ // Create a copy of the template.
+ ClassSpecification classSpecification =
+ (ClassSpecification)classSpecificationTemplate.clone();
+
+ // Set the class name in the copy.
+ classSpecification.className =
+ className.equals("") ||
+ className.equals("*") ?
+ null :
+ ClassUtil.internalClassName(className);
+
+ // Add the copy to the list.
+ classSpecifications.add(classSpecification);
+ }
+ }
+
+
+ // Methods and internal classes related to actions.
+
+ /**
+ * Loads the given ProGuard configuration into the GUI.
+ */
+ private void loadConfiguration(String fileName)
+ {
+ try
+ {
+ // Parse the configuration file.
+ ConfigurationParser parser = new ConfigurationParser(fileName);
+ Configuration configuration = new Configuration();
+ parser.parse(configuration);
+
+ // Let the GUI reflect the configuration.
+ setProGuardConfiguration(configuration);
+ }
+ catch (IOException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantOpenConfigurationFile", fileName),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ catch (ParseException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantParseConfigurationFile", fileName),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+
+ /**
+ * Loads the given ProGuard configuration into the GUI.
+ */
+ private void loadConfiguration(URL url)
+ {
+ try
+ {
+ // Parse the configuration file.
+ ConfigurationParser parser = new ConfigurationParser(url);
+ Configuration configuration = new Configuration();
+ parser.parse(configuration);
+
+ // Let the GUI reflect the configuration.
+ setProGuardConfiguration(configuration);
+ }
+ catch (IOException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantOpenConfigurationFile", url),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ catch (ParseException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantParseConfigurationFile", url),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+
+ /**
+ * Saves the current ProGuard configuration to the given file.
+ */
+ private void saveConfiguration(String fileName)
+ {
+ try
+ {
+ // Save the configuration file.
+ ConfigurationWriter writer = new ConfigurationWriter(fileName);
+ writer.write(getProGuardConfiguration());
+ writer.close();
+ }
+ catch (Exception ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantSaveConfigurationFile", fileName),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+
+ /**
+ * Loads the given stack trace into the GUI.
+ */
+ private void loadStackTrace(String fileName)
+ {
+ try
+ {
+ // Read the entire stack trace file into a buffer.
+ File file = new File(fileName);
+ byte[] buffer = new byte[(int)file.length()];
+ InputStream inputStream = new FileInputStream(file);
+ inputStream.read(buffer);
+ inputStream.close();
+
+ // Put the stack trace in the text area.
+ stackTraceTextArea.setText(new String(buffer));
+ }
+ catch (IOException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantOpenStackTraceFile", fileName),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+
+ /**
+ * This ActionListener loads a ProGuard configuration file and initializes
+ * the GUI accordingly.
+ */
+ private class MyLoadConfigurationActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ configurationChooser.setDialogTitle(msg("selectConfigurationFile"));
+
+ int returnValue = configurationChooser.showOpenDialog(ProGuardGUI.this);
+ if (returnValue == JFileChooser.APPROVE_OPTION)
+ {
+ File selectedFile = configurationChooser.getSelectedFile();
+ String fileName = selectedFile.getPath();
+
+ loadConfiguration(fileName);
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener saves a ProGuard configuration file based on the
+ * current GUI settings.
+ */
+ private class MySaveConfigurationActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ configurationChooser.setDialogTitle(msg("saveConfigurationFile"));
+
+ int returnVal = configurationChooser.showSaveDialog(ProGuardGUI.this);
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
+ File selectedFile = configurationChooser.getSelectedFile();
+ String fileName = selectedFile.getPath();
+
+ saveConfiguration(fileName);
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener displays the ProGuard configuration specified by the
+ * current GUI settings.
+ */
+ private class MyViewConfigurationActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // Make sure System.out has not been redirected yet.
+ if (!systemOutRedirected)
+ {
+ consoleTextArea.setText("");
+
+ TextAreaOutputStream outputStream =
+ new TextAreaOutputStream(consoleTextArea);
+
+ try
+ {
+ // TODO: write out relative path names and path names with system
+ // properties.
+
+ // Write the configuration.
+ ConfigurationWriter writer = new ConfigurationWriter(outputStream);
+ writer.write(getProGuardConfiguration());
+ writer.close();
+ }
+ catch (IOException ex)
+ {
+ }
+
+ // Scroll to the top of the configuration.
+ consoleTextArea.setCaretPosition(0);
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener executes ProGuard based on the current GUI settings.
+ */
+ private class MyProcessActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // Make sure System.out has not been redirected yet.
+ if (!systemOutRedirected)
+ {
+ systemOutRedirected = true;
+
+ // Get the informational configuration file name.
+ File configurationFile = configurationChooser.getSelectedFile();
+ String configurationFileName = configurationFile != null ?
+ configurationFile.getName() :
+ msg("sampleConfigurationFileName");
+
+ // Create the ProGuard thread.
+ Thread proGuardThread =
+ new Thread(new ProGuardRunnable(consoleTextArea,
+ getProGuardConfiguration(),
+ configurationFileName));
+
+ // Run it.
+ proGuardThread.start();
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener loads an obfuscated stack trace from a file and puts
+ * it in the proper text area.
+ */
+ private class MyLoadStackTraceActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ fileChooser.setDialogTitle(msg("selectStackTraceFile"));
+ fileChooser.setSelectedFile(null);
+
+ int returnValue = fileChooser.showOpenDialog(ProGuardGUI.this);
+ if (returnValue == JFileChooser.APPROVE_OPTION)
+ {
+ File selectedFile = fileChooser.getSelectedFile();
+ String fileName = selectedFile.getPath();
+
+ loadStackTrace(fileName);
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener executes ReTrace based on the current GUI settings.
+ */
+ private class MyReTraceActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // Make sure System.out has not been redirected yet.
+ if (!systemOutRedirected)
+ {
+ systemOutRedirected = true;
+
+ boolean verbose = reTraceVerboseCheckBox.isSelected();
+ String retraceMappingFile = reTraceMappingTextField.getText();
+ String stackTrace = stackTraceTextArea.getText();
+
+ // Create the ReTrace runnable.
+ Runnable reTraceRunnable = new ReTraceRunnable(reTraceTextArea,
+ verbose,
+ retraceMappingFile,
+ stackTrace);
+
+ // Run it in this thread, because it won't take long anyway.
+ reTraceRunnable.run();
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the message from the GUI resources that corresponds to the given
+ * key.
+ */
+ private String msg(String messageKey)
+ {
+ return GUIResources.getMessage(messageKey);
+ }
+
+
+ /**
+ * Returns the message from the GUI resources that corresponds to the given
+ * key and argument.
+ */
+ private String msg(String messageKey,
+ Object messageArgument)
+ {
+ return GUIResources.getMessage(messageKey, new Object[] {messageArgument});
+ }
+
+
+ /**
+ * The main method for the ProGuard GUI.
+ */
+ public static void main(String[] args)
+ {
+ ProGuardGUI gui = new ProGuardGUI();
+ gui.pack();
+
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension guiSize = gui.getSize();
+ gui.setLocation((screenSize.width - guiSize.width) / 2,
+ (screenSize.height - guiSize.height) / 2);
+ gui.show();
+
+ // Start the splash animation, unless specified otherwise.
+ int argIndex = 0;
+ if (argIndex < args.length &&
+ NO_SPLASH_OPTION.startsWith(args[argIndex]))
+ {
+ gui.skipSplash();
+ argIndex++;
+ }
+ else
+ {
+ gui.startSplash();
+ }
+
+ // Load an initial configuration, if specified.
+ if (argIndex < args.length)
+ {
+ gui.loadConfiguration(args[argIndex]);
+ argIndex++;
+ }
+
+ if (argIndex < args.length)
+ {
+ System.out.println(gui.getClass().getName() + ": ignoring extra arguments [" + args[argIndex] + "...]");
+ }
+ }
+}
diff --git a/src/proguard/gui/ProGuardRunnable.java b/src/proguard/gui/ProGuardRunnable.java
new file mode 100644
index 0000000..ad5f31b
--- /dev/null
+++ b/src/proguard/gui/ProGuardRunnable.java
@@ -0,0 +1,148 @@
+/* $Id: ProGuardRunnable.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.awt.*;
+import java.io.*;
+
+import javax.swing.*;
+
+import proguard.*;
+
+
+/**
+ * This <code>Runnable</code> runs ProGuard, sending console output to a text
+ * area and any exceptions to message dialogs.
+ *
+ * @see ProGuard
+ * @author Eric Lafortune
+ */
+class ProGuardRunnable implements Runnable
+{
+ private JTextArea consoleTextArea;
+ private Configuration configuration;
+ private String configurationFileName;
+
+
+ /**
+ * Creates a new ProGuardRunnable object.
+ * @param consoleTextArea the text area to send the console output to.
+ * @param configuration the ProGuard configuration.
+ * @param configurationFileName the optional file name of the configuration,
+ * for informational purposes.
+ */
+ public ProGuardRunnable(JTextArea consoleTextArea,
+ Configuration configuration,
+ String configurationFileName)
+ {
+ this.consoleTextArea = consoleTextArea;
+ this.configuration = configuration;
+ this.configurationFileName = configurationFileName;
+ }
+
+
+ // Implementation for Runnable.
+
+ public void run()
+ {
+ consoleTextArea.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ consoleTextArea.setText("");
+
+ // Redirect the System's out and err streams to the console text area.
+ PrintStream oldOut = System.out;
+ PrintStream oldErr = System.err;
+
+ PrintStream printStream =
+ new PrintStream(new TextAreaOutputStream(consoleTextArea), true);
+
+ System.setOut(printStream);
+ System.setErr(printStream);
+
+ try
+ {
+ // Create a new ProGuard object with the GUI's configuration.
+ ProGuard proGuard = new ProGuard(configuration);
+
+ // Run it.
+ proGuard.execute();
+ }
+ catch (Exception ex)
+ {
+ // Print out the exception message.
+ System.out.println(ex.getMessage());
+
+ // Show a dialog as well.
+ MessageDialogRunnable.showMessageDialog(consoleTextArea,
+ ex.getMessage(),
+ msg("errorProcessing"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ catch (OutOfMemoryError er)
+ {
+ // Forget about the ProGuard object as quickly as possible.
+ System.gc();
+
+ // Print out a message suggesting what to do next.
+ System.out.println(msg("outOfMemoryInfo", configurationFileName));
+
+ // Show a dialog as well.
+ MessageDialogRunnable.showMessageDialog(consoleTextArea,
+ msg("outOfMemory"),
+ msg("errorProcessing"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+
+ // Make sure all output has been sent to the console text area.
+ printStream.flush();
+
+ // Restore the old System's out and err streams.
+ System.setOut(oldOut);
+ System.setErr(oldErr);
+
+ consoleTextArea.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+
+ // Reset the global static redirection lock.
+ ProGuardGUI.systemOutRedirected = false;
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the message from the GUI resources that corresponds to the given
+ * key.
+ */
+ private String msg(String messageKey)
+ {
+ return GUIResources.getMessage(messageKey);
+ }
+
+
+ /**
+ * Returns the message from the GUI resources that corresponds to the given
+ * key and argument.
+ */
+ private String msg(String messageKey,
+ Object messageArgument)
+ {
+ return GUIResources.getMessage(messageKey, new Object[] {messageArgument});
+ }
+}
diff --git a/src/proguard/gui/ReTraceRunnable.java b/src/proguard/gui/ReTraceRunnable.java
new file mode 100644
index 0000000..29cca05
--- /dev/null
+++ b/src/proguard/gui/ReTraceRunnable.java
@@ -0,0 +1,149 @@
+/* $Id: ReTraceRunnable.java,v 1.6 2004/08/21 21:36:03 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.awt.Cursor;
+import java.io.*;
+
+import javax.swing.*;
+
+import proguard.retrace.ReTrace;
+
+
+/**
+ * This <code>Runnable</code> runs ReTrace, sending console output to a text
+ * area and any exceptions to message dialogs.
+ *
+ * @see ReTrace
+ * @author Eric Lafortune
+ */
+class ReTraceRunnable implements Runnable
+{
+ private JTextArea consoleTextArea;
+ private boolean verbose;
+ private String retraceMappingFile;
+ private String stackTrace;
+
+
+ /**
+ * Creates a new ProGuardRunnable object.
+ * @param consoleTextArea the text area to send the console output to.
+ * @param verbose specifies whether the de-obfuscated stack trace
+ * should be verbose.
+ * @param mappingFileName the mapping file that was written out by ProGuard.
+ */
+ public ReTraceRunnable(JTextArea consoleTextArea,
+ boolean verbose,
+ String retraceMappingFile,
+ String stackTrace)
+ {
+ this.consoleTextArea = consoleTextArea;
+ this.verbose = verbose;
+ this.retraceMappingFile = retraceMappingFile;
+ this.stackTrace = stackTrace;
+ }
+
+
+ // Implementation for Runnable.
+
+ public void run()
+ {
+ consoleTextArea.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ consoleTextArea.setText("");
+
+ // Redirect the stack trace string to the System's in stream, and the
+ // out and err streams to the console text area.
+ InputStream oldIn = System.in;
+ PrintStream oldOut = System.out;
+ PrintStream oldErr = System.err;
+
+ ByteArrayInputStream inputStream =
+ new ByteArrayInputStream(stackTrace.getBytes());
+
+ PrintStream printStream =
+ new PrintStream(new TextAreaOutputStream(consoleTextArea), true);
+
+ System.setIn(inputStream);
+ System.setOut(printStream);
+ System.setErr(printStream);
+
+ try
+ {
+ // Create a new ProGuard object with the GUI's configuration.
+ ReTrace reTrace = new ReTrace(verbose,
+ retraceMappingFile);
+
+ // Run it.
+ reTrace.execute();
+ }
+ catch (Exception ex)
+ {
+ // Print out the exception message.
+ System.out.println(ex.getMessage());
+
+ // Show a dialog as well.
+ MessageDialogRunnable.showMessageDialog(consoleTextArea,
+ ex.getMessage(),
+ msg("errorReTracing"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ catch (OutOfMemoryError er)
+ {
+ // Forget about the ProGuard object as quickly as possible.
+ System.gc();
+
+ // Print out a message suggesting what to do next.
+ System.out.println(msg("outOfMemory"));
+
+ // Show a dialog as well.
+ MessageDialogRunnable.showMessageDialog(consoleTextArea,
+ msg("outOfMemory"),
+ msg("errorReTracing"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+
+ // Make sure all output has been sent to the console text area.
+ printStream.flush();
+
+ // Restore the old System's in, out, and err streams.
+ System.setIn(oldIn);
+ System.setOut(oldOut);
+ System.setErr(oldErr);
+
+ consoleTextArea.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ consoleTextArea.setCaretPosition(0);
+
+ // Reset the global static redirection lock.
+ ProGuardGUI.systemOutRedirected = false;
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the message from the GUI resources that corresponds to the given
+ * key.
+ */
+ private String msg(String messageKey)
+ {
+ return GUIResources.getMessage(messageKey);
+ }
+}
diff --git a/src/proguard/gui/SwingUtil.java b/src/proguard/gui/SwingUtil.java
new file mode 100644
index 0000000..22f3da4
--- /dev/null
+++ b/src/proguard/gui/SwingUtil.java
@@ -0,0 +1,80 @@
+/* $Id: SwingUtil.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import javax.swing.*;
+
+
+/**
+ * This utility class provides variants of the invocation method from the
+ * <code>SwingUtilities</code> class.
+ *
+ * @see SwingUtilities
+ * @author Eric Lafortune
+ */
+class SwingUtil
+{
+ /**
+ * Invokes the given Runnable in the AWT event dispatching thread,
+ * and waits for it to finish. This method may be called from any thread,
+ * including the event dispatching thread itself.
+ * @see SwingUtilities#invokeAndWait(java.lang.Runnable)
+ * @param runnable the Runnable to be executed.
+ */
+ public static void invokeAndWait(Runnable runnable)
+ {
+ try
+ {
+ if (SwingUtilities.isEventDispatchThread())
+ {
+ runnable.run();
+ }
+ else
+ {
+ SwingUtilities.invokeAndWait(runnable);
+ }
+ }
+ catch (Exception ex)
+ {
+ // Ignore any exceptions.
+ }
+ }
+
+
+ /**
+ * Invokes the given Runnable in the AWT event dispatching thread, not
+ * necessarily right away. This method may be called from any thread,
+ * including the event dispatching thread itself.
+ * @see SwingUtilities#invokeLater(java.lang.Runnable)
+ * @param runnable the Runnable to be executed.
+ */
+ public static void invokeLater(Runnable runnable)
+ {
+ if (SwingUtilities.isEventDispatchThread())
+ {
+ runnable.run();
+ }
+ else
+ {
+ SwingUtilities.invokeLater(runnable);
+ }
+ }
+}
diff --git a/src/proguard/gui/TabbedPane.java b/src/proguard/gui/TabbedPane.java
new file mode 100644
index 0000000..e61c8ba
--- /dev/null
+++ b/src/proguard/gui/TabbedPane.java
@@ -0,0 +1,229 @@
+/* $Id: TabbedPane.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+
+/**
+ * This <code>Jpanel</code> is similar to a <code>JTabbedPane</code>.
+ * It uses buttons on the left-hand side to switch between panels.
+ * An image can be added below these buttons.
+ * Some methods are provided to switch between tabs.
+ *
+ * @author Eric Lafortune
+ */
+public class TabbedPane
+ extends JPanel
+{
+ private CardLayout cardLayout = new CardLayout();
+ private JPanel cardPanel = new JPanel(cardLayout);
+ private ButtonGroup buttonGroup = new ButtonGroup();
+
+
+ /**
+ * Creates a new TabbedPane.
+ */
+ public TabbedPane()
+ {
+ GridBagLayout layout = new GridBagLayout();
+ setLayout(layout);
+
+ GridBagConstraints cardConstraints = new GridBagConstraints();
+ cardConstraints.gridx = 1;
+ cardConstraints.gridy = 0;
+ cardConstraints.gridheight = GridBagConstraints.REMAINDER;
+ cardConstraints.fill = GridBagConstraints.BOTH;
+ cardConstraints.weightx = 1.0;
+ cardConstraints.weighty = 1.0;
+ cardConstraints.anchor = GridBagConstraints.NORTHWEST;
+
+ add(cardPanel, cardConstraints);
+ }
+
+
+ /**
+ * Adds a component with a given title to the tabbed pane.
+ *
+ * @param title the title that will be used in the tab button.
+ * @param component the component that will be added as a tab.
+ */
+ public Component add(final String title, Component component)
+ {
+ GridBagConstraints buttonConstraints = new GridBagConstraints();
+ buttonConstraints.gridx = 0;
+ buttonConstraints.fill = GridBagConstraints.HORIZONTAL;
+ buttonConstraints.anchor = GridBagConstraints.NORTHWEST;
+ buttonConstraints.ipadx = 10;
+ buttonConstraints.ipady = 4;
+
+ JToggleButton button = new JToggleButton(title);
+
+ // Let the button react on the mouse press, instead of waiting for the
+ // mouse release.
+ button.setModel(new JToggleButton.ToggleButtonModel()
+ {
+ public void setPressed(boolean b)
+ {
+ if ((isPressed() == b) || !isEnabled())
+ {
+ return;
+ }
+
+ if (b == false && isArmed())
+ {
+ setSelected(!this.isSelected());
+ }
+
+ if (b)
+ {
+ stateMask |= PRESSED;
+ }
+ else
+ {
+ stateMask &= ~PRESSED;
+ }
+
+ fireStateChanged();
+
+ if (isPressed())
+ {
+ fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand()));
+ }
+ }
+
+ });
+
+ // Switch to the tab on a button press.
+ button.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ cardLayout.show(cardPanel, title);
+ }
+ });
+
+ // Only one button can be selected at the same time.
+ buttonGroup.add(button);
+
+ // If this is the first tab, make sure its button is selected.
+ if (cardPanel.getComponentCount() == 0)
+ {
+ button.setSelected(true);
+ }
+
+ // Add the button and its panel.
+ add(button, buttonConstraints);
+ cardPanel.add(title, component);
+
+ return component;
+ }
+
+
+ /**
+ * Adds an image below the tab buttons, after all tabs have been added.
+ * The image will only be as visible as permitted by the available space.
+ *
+ * @param image the image.
+ * @return the component containing the image.
+ */
+ public Component addImage(final Image image)
+ {
+ GridBagConstraints imageConstraints = new GridBagConstraints();
+ imageConstraints.gridx = 0;
+ imageConstraints.weighty = 1.0;
+ imageConstraints.fill = GridBagConstraints.BOTH;
+ imageConstraints.anchor = GridBagConstraints.SOUTHWEST;
+
+ JPanel component = new JPanel()
+ {
+ public void paintComponent(Graphics graphics)
+ {
+ graphics.drawImage(image, 0, getHeight() - image.getHeight(null), this);
+ }
+ };
+ component.setBorder(BorderFactory.createEtchedBorder());
+
+ add(component, imageConstraints);
+
+ return component;
+ }
+
+
+ /**
+ * Selects the first tab.
+ */
+ public void first()
+ {
+ cardLayout.first(cardPanel);
+ updateButtonSelection();
+ }
+
+
+ /**
+ * Selects the last tab.
+ */
+ public void last()
+ {
+ cardLayout.last(cardPanel);
+ updateButtonSelection();
+ }
+
+
+ /**
+ * Selects the previous tab.
+ */
+ public void previous()
+ {
+ cardLayout.previous(cardPanel);
+ updateButtonSelection();
+ }
+
+
+ /**
+ * Selects the next tab.
+ */
+ public void next()
+ {
+ cardLayout.next(cardPanel);
+ updateButtonSelection();
+ }
+
+
+ /**
+ * Lets the button selection reflect the currently visible panel.
+ */
+ private void updateButtonSelection()
+ {
+ int count = cardPanel.getComponentCount();
+ for (int index = 0 ; index < count ; index++) {
+ Component card = cardPanel.getComponent(index);
+ if (card.isShowing())
+ {
+ JToggleButton button = (JToggleButton)getComponent(index+1);
+ button.setSelected(true);
+ }
+ }
+ }
+}
diff --git a/src/proguard/gui/TextAreaOutputStream.java b/src/proguard/gui/TextAreaOutputStream.java
new file mode 100644
index 0000000..e06df07
--- /dev/null
+++ b/src/proguard/gui/TextAreaOutputStream.java
@@ -0,0 +1,74 @@
+/* $Id: TextAreaOutputStream.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import java.io.*;
+
+import javax.swing.*;
+
+
+/**
+ * This <code>PrintStream</code> appends its output to a given text area.
+ *
+ * @author Eric Lafortune
+ */
+class TextAreaOutputStream extends FilterOutputStream implements Runnable
+{
+ private JTextArea textArea;
+
+
+ public TextAreaOutputStream(JTextArea textArea)
+ {
+ super(new ByteArrayOutputStream());
+
+ this.textArea = textArea;
+ }
+
+
+ // Implementation for FilterOutputStream.
+
+ public void flush() throws IOException
+ {
+ super.flush();
+
+ // Append the accumulated buffer contents to the text area.
+ SwingUtil.invokeAndWait(this);
+ }
+
+
+ // Implementation for Runnable.
+
+ public synchronized void run()
+ {
+ ByteArrayOutputStream out = (ByteArrayOutputStream)super.out;
+
+ // Has any new text been written?
+ String text = out.toString();
+ if (text.length() > 0)
+ {
+ // Append the accumulated text to the text area.
+ textArea.append(text);
+
+ // Clear the buffer.
+ out.reset();
+ }
+ }
+}
diff --git a/src/proguard/gui/arrow.gif b/src/proguard/gui/arrow.gif
new file mode 100644
index 0000000..c58e34e
Binary files /dev/null and b/src/proguard/gui/arrow.gif differ
diff --git a/src/proguard/gui/boilerplate.pro b/src/proguard/gui/boilerplate.pro
new file mode 100644
index 0000000..c905e24
--- /dev/null
+++ b/src/proguard/gui/boilerplate.pro
@@ -0,0 +1,277 @@
+# Keep - Applications. Keep all application classes that have a main method.
+-keepclasseswithmembers public class * {
+ public static void main(java.lang.String[]);
+}
+
+# Keep - Applets. Keep all extensions of java.applet.Applet.
+-keep public class * extends java.applet.Applet
+
+# Keep - Servlets. Keep all extensions of javax.servlet.Servlet.
+-keep public class * extends javax.servlet.Servlet
+
+# Keep - Midlets. Keep all extensions of javax.microedition.midlet.MIDlet.
+-keep public class * extends javax.microedition.midlet.MIDlet
+
+# Keep - Library. Keep all externally accessible classes, fields, and methods.
+-keep public class * {
+ public protected <fields>;
+ public protected <methods>;
+}
+
+# Also keep - Enumerations. Keep a method that is required in enumeration
+# classes.
+-keepclassmembers class * extends java.lang.Enum {
+ public **[] values();
+}
+
+# Also keep - Serialization code. Keep all fields and methods that are
+# used for serialization.
+-keepclassmembers class * extends java.io.Serializable {
+ static final long serialVersionUID;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+
+# Also keep - BeanInfo classes. Keep all classes that implement the
+# BeanInfo interface.
+-keep class * implements java.beans.BeanInfo
+
+# Also keep - Bean classes. Keep all bean classes along with their getters
+# and setters.
+-keep class * {
+ void set*(%);
+ void set*(**);
+ void set*(%[]);
+ void set*(**[]);
+ void set*(int, %);
+ void set*(int, **);
+
+ % get*();
+ ** get*();
+ %[] get*();
+ **[] get*();
+ % get*(int);
+ ** get*(int);
+}
+
+# Also keep - RMI interfaces. Keep all Remote interfaces and their methods.
+-keep interface * extends java.rmi.Remote {
+ <methods>;
+}
+
+# Also keep - RMI implementations. Keep all Remote implementations. This
+# includes any explicit or implicit Activatable implementations with their
+# two-argument constructors.
+-keep class * implements java.rmi.Remote {
+ <init>(java.rmi.activation.ActivationID, java.rmi.MarshalledObject);
+}
+
+# Keep names - Native method names. Keep all native class/method names.
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# Keep names - _class method names. Keep all .class method names. Useful for
+# libraries that will be obfuscated again.
+-keepclassmembernames class * {
+ java.lang.Class class$(java.lang.String);
+ java.lang.Class class$(java.lang.String, boolean);
+}
+
+# Remove - System method calls. Remove all invocations of System
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.System {
+ public static native long currentTimeMillis();
+ static java.lang.Class getCallerClass();
+ public static native int identityHashCode(java.lang.Object);
+ public static java.lang.SecurityManager getSecurityManager();
+ public static java.util.Properties getProperties();
+ public static java.lang.String getProperty(java.lang.String);
+ public static java.lang.String getenv(java.lang.String);
+ public static native java.lang.String mapLibraryName(java.lang.String);
+ public static java.lang.String getProperty(java.lang.String,java.lang.String);
+}
+
+# Remove - Math method calls. Remove all invocations of Math
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.Math {
+ public static double sin(double);
+ public static double cos(double);
+ public static double tan(double);
+ public static double asin(double);
+ public static double acos(double);
+ public static double atan(double);
+ public static double toRadians(double);
+ public static double toDegrees(double);
+ public static double exp(double);
+ public static double log(double);
+ public static double log10(double);
+ public static double sqrt(double);
+ public static double cbrt(double);
+ public static double IEEEremainder(double, double);
+ public static double ceil(double);
+ public static double floor(double);
+ public static double rint(double);
+ public static double atan2(double, double);
+ public static double pow(double, double);
+ public static int round(float);
+ public static long round(double);
+ public static double random();
+ public static int abs(int);
+ public static long abs(long);
+ public static float abs(float);
+ public static double abs(double);
+ public static int max(int, int);
+ public static long max(long, long);
+ public static float max(float, float);
+ public static double max(double, double);
+ public static int min(int, int);
+ public static long min(long, long);
+ public static float min(float, float);
+ public static double min(double, double);
+ public static double ulp(double);
+ public static float ulp(float);
+ public static double signum(double);
+ public static float signum(float);
+ public static double sinh(double);
+ public static double cosh(double);
+ public static double tanh(double);
+ public static double hypot(double, double);
+ public static double expm1(double);
+ public static double log1p(double);
+}
+
+# Remove - String method calls. Remove all invocations of String
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.String {
+ public java.lang.String();
+ public java.lang.String(byte[]);
+ public java.lang.String(byte[],int);
+ public java.lang.String(byte[],int,int);
+ public java.lang.String(byte[],int,int,int);
+ public java.lang.String(byte[],int,int,java.lang.String);
+ public java.lang.String(byte[],java.lang.String);
+ public java.lang.String(char[]);
+ public java.lang.String(char[],int,int);
+ public java.lang.String(java.lang.String);
+ public java.lang.String(java.lang.StringBuffer);
+ public static java.lang.String copyValueOf(char[]);
+ public static java.lang.String copyValueOf(char[],int,int);
+ public static java.lang.String valueOf(boolean);
+ public static java.lang.String valueOf(char);
+ public static java.lang.String valueOf(char[]);
+ public static java.lang.String valueOf(char[],int,int);
+ public static java.lang.String valueOf(double);
+ public static java.lang.String valueOf(float);
+ public static java.lang.String valueOf(int);
+ public static java.lang.String valueOf(java.lang.Object);
+ public static java.lang.String valueOf(long);
+ public boolean contentEquals(java.lang.StringBuffer);
+ public boolean endsWith(java.lang.String);
+ public boolean equalsIgnoreCase(java.lang.String);
+ public boolean equals(java.lang.Object);
+ public boolean matches(java.lang.String);
+ public boolean regionMatches(boolean,int,java.lang.String,int,int);
+ public boolean regionMatches(int,java.lang.String,int,int);
+ public boolean startsWith(java.lang.String);
+ public boolean startsWith(java.lang.String,int);
+ public byte[] getBytes();
+ public byte[] getBytes(java.lang.String);
+ public char charAt(int);
+ public char[] toCharArray();
+ public int compareToIgnoreCase(java.lang.String);
+ public int compareTo(java.lang.Object);
+ public int compareTo(java.lang.String);
+ public int hashCode();
+ public int indexOf(int);
+ public int indexOf(int,int);
+ public int indexOf(java.lang.String);
+ public int indexOf(java.lang.String,int);
+ public int lastIndexOf(int);
+ public int lastIndexOf(int,int);
+ public int lastIndexOf(java.lang.String);
+ public int lastIndexOf(java.lang.String,int);
+ public int length();
+ public java.lang.CharSequence subSequence(int,int);
+ public java.lang.String concat(java.lang.String);
+ public java.lang.String replaceAll(java.lang.String,java.lang.String);
+ public java.lang.String replace(char,char);
+ public java.lang.String replaceFirst(java.lang.String,java.lang.String);
+ public java.lang.String[] split(java.lang.String);
+ public java.lang.String[] split(java.lang.String,int);
+ public java.lang.String substring(int);
+ public java.lang.String substring(int,int);
+ public java.lang.String toLowerCase();
+ public java.lang.String toLowerCase(java.util.Locale);
+ public java.lang.String toString();
+ public java.lang.String toUpperCase();
+ public java.lang.String toUpperCase(java.util.Locale);
+ public java.lang.String trim();
+}
+
+
+# Remove - StringBuffer method calls. Remove all invocations of
+# StringBuffer methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.StringBuffer {
+ public java.lang.StringBuffer();
+ public java.lang.StringBuffer(int);
+ public java.lang.StringBuffer(java.lang.String);
+ public java.lang.StringBuffer(java.lang.CharSequence);
+ public java.lang.String toString();
+ public char charAt(int);
+ public int capacity();
+ public int codePointAt(int);
+ public int codePointBefore(int);
+ public int indexOf(java.lang.String,int);
+ public int lastIndexOf(java.lang.String);
+ public int lastIndexOf(java.lang.String,int);
+ public int length();
+ public java.lang.String substring(int);
+ public java.lang.String substring(int,int);
+}
+
+# Remove - StringBuilder method calls. Remove all invocations of
+# StringBuilder methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.StringBuilder {
+ public java.lang.StringBuilder();
+ public java.lang.StringBuilder(int);
+ public java.lang.StringBuilder(java.lang.String);
+ public java.lang.StringBuilder(java.lang.CharSequence);
+ public java.lang.String toString();
+ public char charAt(int);
+ public int capacity();
+ public int codePointAt(int);
+ public int codePointBefore(int);
+ public int indexOf(java.lang.String,int);
+ public int lastIndexOf(java.lang.String);
+ public int lastIndexOf(java.lang.String,int);
+ public int length();
+ public java.lang.String substring(int);
+ public java.lang.String substring(int,int);
+}
+
+# Remove debugging - Throwable_printStackTrace calls. Remove all invocations of
+# Throwable.printStackTrace().
+-assumenosideeffects public class java.lang.Throwable {
+ public void printStackTrace();
+}
+
+# Remove debugging - Thread_dumpStack calls. Remove all invocations of
+# Thread.dumpStack().
+-assumenosideeffects public class java.lang.Thread {
+ public static void dumpStack();
+}
+
+# Remove debugging - All logging API calls. Remove all invocations of the
+# logging API whose return values are not used.
+-assumenosideeffects public class java.util.logging.* {
+ <methods>;
+}
+
+# Remove debugging - All Log4j API calls. Remove all invocations of the
+# Log4j API whose return values are not used.
+-assumenosideeffects public class org.apache.log4j.** {
+ <methods>;
+}
diff --git a/src/proguard/gui/default.pro b/src/proguard/gui/default.pro
new file mode 100644
index 0000000..a8cf902
--- /dev/null
+++ b/src/proguard/gui/default.pro
@@ -0,0 +1,193 @@
+# The default configuration when starting up the GUI.
+
+-libraryjars <java.home>/lib/rt.jar
+
+-verbose
+
+# Keep - Applications. Keep all application classes that have a main method.
+-keepclasseswithmembers public class * {
+ public static void main(java.lang.String[]);
+}
+
+# Keep names - Native method names. Keep all native class/method names.
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# Also keep - Enumerations. Keep a method that is required in enumeration
+# classes.
+-keepclassmembers class * extends java.lang.Enum {
+ public **[] values();
+}
+
+# Remove - System method calls. Remove all invocations of System
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.System {
+ public static native long currentTimeMillis();
+ static java.lang.Class getCallerClass();
+ public static native int identityHashCode(java.lang.Object);
+ public static java.lang.SecurityManager getSecurityManager();
+ public static java.util.Properties getProperties();
+ public static java.lang.String getProperty(java.lang.String);
+ public static java.lang.String getenv(java.lang.String);
+ public static native java.lang.String mapLibraryName(java.lang.String);
+ public static java.lang.String getProperty(java.lang.String,java.lang.String);
+}
+
+# Remove - Math method calls. Remove all invocations of Math
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.Math {
+ public static double sin(double);
+ public static double cos(double);
+ public static double tan(double);
+ public static double asin(double);
+ public static double acos(double);
+ public static double atan(double);
+ public static double toRadians(double);
+ public static double toDegrees(double);
+ public static double exp(double);
+ public static double log(double);
+ public static double log10(double);
+ public static double sqrt(double);
+ public static double cbrt(double);
+ public static double IEEEremainder(double, double);
+ public static double ceil(double);
+ public static double floor(double);
+ public static double rint(double);
+ public static double atan2(double, double);
+ public static double pow(double, double);
+ public static int round(float);
+ public static long round(double);
+ public static double random();
+ public static int abs(int);
+ public static long abs(long);
+ public static float abs(float);
+ public static double abs(double);
+ public static int max(int, int);
+ public static long max(long, long);
+ public static float max(float, float);
+ public static double max(double, double);
+ public static int min(int, int);
+ public static long min(long, long);
+ public static float min(float, float);
+ public static double min(double, double);
+ public static double ulp(double);
+ public static float ulp(float);
+ public static double signum(double);
+ public static float signum(float);
+ public static double sinh(double);
+ public static double cosh(double);
+ public static double tanh(double);
+ public static double hypot(double, double);
+ public static double expm1(double);
+ public static double log1p(double);
+}
+
+# Remove - String method calls. Remove all invocations of String
+# methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.String {
+ public java.lang.String();
+ public java.lang.String(byte[]);
+ public java.lang.String(byte[],int);
+ public java.lang.String(byte[],int,int);
+ public java.lang.String(byte[],int,int,int);
+ public java.lang.String(byte[],int,int,java.lang.String);
+ public java.lang.String(byte[],java.lang.String);
+ public java.lang.String(char[]);
+ public java.lang.String(char[],int,int);
+ public java.lang.String(java.lang.String);
+ public java.lang.String(java.lang.StringBuffer);
+ public static java.lang.String copyValueOf(char[]);
+ public static java.lang.String copyValueOf(char[],int,int);
+ public static java.lang.String valueOf(boolean);
+ public static java.lang.String valueOf(char);
+ public static java.lang.String valueOf(char[]);
+ public static java.lang.String valueOf(char[],int,int);
+ public static java.lang.String valueOf(double);
+ public static java.lang.String valueOf(float);
+ public static java.lang.String valueOf(int);
+ public static java.lang.String valueOf(java.lang.Object);
+ public static java.lang.String valueOf(long);
+ public boolean contentEquals(java.lang.StringBuffer);
+ public boolean endsWith(java.lang.String);
+ public boolean equalsIgnoreCase(java.lang.String);
+ public boolean equals(java.lang.Object);
+ public boolean matches(java.lang.String);
+ public boolean regionMatches(boolean,int,java.lang.String,int,int);
+ public boolean regionMatches(int,java.lang.String,int,int);
+ public boolean startsWith(java.lang.String);
+ public boolean startsWith(java.lang.String,int);
+ public byte[] getBytes();
+ public byte[] getBytes(java.lang.String);
+ public char charAt(int);
+ public char[] toCharArray();
+ public int compareToIgnoreCase(java.lang.String);
+ public int compareTo(java.lang.Object);
+ public int compareTo(java.lang.String);
+ public int hashCode();
+ public int indexOf(int);
+ public int indexOf(int,int);
+ public int indexOf(java.lang.String);
+ public int indexOf(java.lang.String,int);
+ public int lastIndexOf(int);
+ public int lastIndexOf(int,int);
+ public int lastIndexOf(java.lang.String);
+ public int lastIndexOf(java.lang.String,int);
+ public int length();
+ public java.lang.CharSequence subSequence(int,int);
+ public java.lang.String concat(java.lang.String);
+ public java.lang.String replaceAll(java.lang.String,java.lang.String);
+ public java.lang.String replace(char,char);
+ public java.lang.String replaceFirst(java.lang.String,java.lang.String);
+ public java.lang.String[] split(java.lang.String);
+ public java.lang.String[] split(java.lang.String,int);
+ public java.lang.String substring(int);
+ public java.lang.String substring(int,int);
+ public java.lang.String toLowerCase();
+ public java.lang.String toLowerCase(java.util.Locale);
+ public java.lang.String toString();
+ public java.lang.String toUpperCase();
+ public java.lang.String toUpperCase(java.util.Locale);
+ public java.lang.String trim();
+}
+
+
+# Remove - StringBuffer method calls. Remove all invocations of
+# StringBuffer methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.StringBuffer {
+ public java.lang.StringBuffer();
+ public java.lang.StringBuffer(int);
+ public java.lang.StringBuffer(java.lang.String);
+ public java.lang.StringBuffer(java.lang.CharSequence);
+ public java.lang.String toString();
+ public char charAt(int);
+ public int capacity();
+ public int codePointAt(int);
+ public int codePointBefore(int);
+ public int indexOf(java.lang.String,int);
+ public int lastIndexOf(java.lang.String);
+ public int lastIndexOf(java.lang.String,int);
+ public int length();
+ public java.lang.String substring(int);
+ public java.lang.String substring(int,int);
+}
+
+# Remove - StringBuilder method calls. Remove all invocations of
+# StringBuilder methods without side effects whose return values are not used.
+-assumenosideeffects public class java.lang.StringBuilder {
+ public java.lang.StringBuilder();
+ public java.lang.StringBuilder(int);
+ public java.lang.StringBuilder(java.lang.String);
+ public java.lang.StringBuilder(java.lang.CharSequence);
+ public java.lang.String toString();
+ public char charAt(int);
+ public int capacity();
+ public int codePointAt(int);
+ public int codePointBefore(int);
+ public int indexOf(java.lang.String,int);
+ public int lastIndexOf(java.lang.String);
+ public int lastIndexOf(java.lang.String,int);
+ public int length();
+ public java.lang.String substring(int);
+ public java.lang.String substring(int,int);
+}
diff --git a/src/proguard/gui/package.html b/src/proguard/gui/package.html
new file mode 100644
index 0000000..4eedcc2
--- /dev/null
+++ b/src/proguard/gui/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains a GUI for ProGuard and ReTrace.
+</body>
diff --git a/src/proguard/gui/splash/BufferedSprite.java b/src/proguard/gui/splash/BufferedSprite.java
new file mode 100644
index 0000000..684f977
--- /dev/null
+++ b/src/proguard/gui/splash/BufferedSprite.java
@@ -0,0 +1,85 @@
+/* $Id: BufferedSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.*;
+
+/**
+ * This Sprite encapsulates another Sprite, which is buffered on an Image.
+ *
+ * @author Eric Lafortune
+ */
+public class BufferedSprite implements Sprite
+{
+ private Image bufferImage;
+ private Graphics bufferGraphics;
+ private Color backgroundColor;
+ private Sprite sprite;
+
+ private long cachedTime = -1;
+
+
+ /**
+ * Creates a new BufferedSprite.
+ * @param bufferImage the Image that is used for the buffering.
+ * @param bufferGraphics the Graphics of the Image.
+ * @param backgroundColor the background color that is used for the buffer.
+ * @param sprite the Sprite that is painted in the buffer.
+ */
+ public BufferedSprite(Image bufferImage,
+ Graphics bufferGraphics,
+ Color backgroundColor,
+ Sprite sprite)
+ {
+
+ this.bufferImage = bufferImage;
+ this.bufferGraphics = bufferGraphics;
+ this.backgroundColor = backgroundColor;
+ this.sprite = sprite;
+ }
+
+
+ // Implementation for Sprite.
+
+ public void paint(Graphics graphics, long time)
+ {
+ Rectangle clip = bufferGraphics.getClipBounds();
+
+ // Do we need to repaint the sprites in the buffer image?
+ if (time != cachedTime)
+ {
+ // Clear the background.
+ if (backgroundColor != null)
+ {
+ bufferGraphics.setColor(backgroundColor);
+ bufferGraphics.fillRect(0, 0, clip.width, clip.height);
+ }
+
+ // Draw the sprite.
+ sprite.paint(bufferGraphics, time);
+
+ cachedTime = time;
+ }
+
+ // Draw the buffer image.
+ graphics.drawImage(bufferImage, 0, 0, clip.width, clip.height, null);
+ }
+}
diff --git a/src/proguard/gui/splash/CircleSprite.java b/src/proguard/gui/splash/CircleSprite.java
new file mode 100644
index 0000000..21484df
--- /dev/null
+++ b/src/proguard/gui/splash/CircleSprite.java
@@ -0,0 +1,80 @@
+/* $Id: CircleSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Graphics;
+
+/**
+ * This Sprite represents an animated circle. It can optionally be filled.
+ *
+ * @author Eric Lafortune
+ */
+public class CircleSprite implements Sprite
+{
+ private boolean filled;
+ private VariableColor color;
+ private VariableInt x;
+ private VariableInt y;
+ private VariableInt radius;
+
+
+ /**
+ * Creates a new CircleSprite.
+ * @param filled specifies whether the rectangle should be filled.
+ * @param color the variable color of the circle.
+ * @param x the variable x-coordinate of the center of the circle.
+ * @param y the variable y-coordinate of the center of the circle.
+ * @param radius the variable radius of the circle.
+ */
+ public CircleSprite(boolean filled,
+ VariableColor color,
+ VariableInt x,
+ VariableInt y,
+ VariableInt radius)
+ {
+ this.filled = filled;
+ this.color = color;
+ this.x = x;
+ this.y = y;
+ this.radius = radius;
+ }
+
+
+ // Implementation for Sprite.
+
+ public void paint(Graphics graphics, long time)
+ {
+ graphics.setColor(color.getColor(time));
+
+ int xt = x.getInt(time);
+ int yt = y.getInt(time);
+ int r = radius.getInt(time);
+
+ if (filled)
+ {
+ graphics.fillOval(xt - r, yt - r, 2 * r, 2 * r);
+ }
+ else
+ {
+ graphics.drawOval(xt - r, yt - r, 2 * r, 2 * r);
+ }
+ }
+}
diff --git a/src/proguard/gui/splash/ClipSprite.java b/src/proguard/gui/splash/ClipSprite.java
new file mode 100644
index 0000000..0cad063
--- /dev/null
+++ b/src/proguard/gui/splash/ClipSprite.java
@@ -0,0 +1,85 @@
+/* $Id: ClipSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.*;
+
+/**
+ * This Sprite encapsulates another Sprite, which is clipped by a clip Sprite.
+ *
+ * @author Eric Lafortune
+ */
+public class ClipSprite implements Sprite
+{
+ private VariableColor insideClipColor;
+ private VariableColor outsideClipColor;
+ private Sprite clipSprite;
+ private Sprite sprite;
+
+
+ /**
+ * Creates a new ClipSprite.
+ * @param insideClipColor the background color inside the clip sprite.
+ * @param outsideClipColor the background color outside the clip sprite.
+ * @param clipSprite the clip Sprite.
+ * @param sprite the clipped Sprite.
+ */
+ public ClipSprite(VariableColor insideClipColor,
+ VariableColor outsideClipColor,
+ Sprite clipSprite,
+ Sprite sprite)
+ {
+ this.insideClipColor = insideClipColor;
+ this.outsideClipColor = outsideClipColor;
+ this.clipSprite = clipSprite;
+ this.sprite = sprite;
+ }
+
+
+ // Implementation for Sprite.
+
+ public void paint(Graphics graphics, long time)
+ {
+ // Clear the background.
+ Color outsideColor = outsideClipColor.getColor(time);
+ Rectangle clip = graphics.getClipBounds();
+ graphics.setPaintMode();
+ graphics.setColor(outsideColor);
+ graphics.fillRect(0, 0, clip.width, clip.height);
+
+ // Draw the sprite in XOR mode.
+ OverrideGraphics2D g = new OverrideGraphics2D((Graphics2D)graphics);
+ Color insideColor = insideClipColor.getColor(time);
+ g.setOverrideXORMode(insideColor);
+ sprite.paint(g, time);
+ g.setOverrideXORMode(null);
+
+ // Clear the clip area.
+ g.setOverrideColor(insideColor);
+ clipSprite.paint(g, time);
+ g.setOverrideColor(null);
+
+ // Draw the sprite in XOR mode.
+ g.setOverrideXORMode(insideColor);
+ sprite.paint(g, time);
+ g.setOverrideXORMode(null);
+ }
+}
diff --git a/src/proguard/gui/splash/CompositeSprite.java b/src/proguard/gui/splash/CompositeSprite.java
new file mode 100644
index 0000000..8a27b35
--- /dev/null
+++ b/src/proguard/gui/splash/CompositeSprite.java
@@ -0,0 +1,56 @@
+/* $Id: CompositeSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Graphics;
+
+/**
+ * This Sprite is the composition of a list of Sprite objects.
+ *
+ * @author Eric Lafortune
+ */
+public class CompositeSprite implements Sprite
+{
+ private Sprite[] sprites;
+
+
+ /**
+ * Creates a new CompositeSprite.
+ * @param sprites the array of Sprite objects to which the painting will
+ * be delegated, starting with the first element.
+ */
+ public CompositeSprite(Sprite[] sprites)
+ {
+ this.sprites = sprites;
+ }
+
+
+ // Implementation for Sprite.
+
+ public void paint(Graphics graphics, long time)
+ {
+ // Draw the sprites.
+ for (int index = 0; index < sprites.length; index++)
+ {
+ sprites[index].paint(graphics, time);
+ }
+ }
+}
diff --git a/src/proguard/gui/splash/ConstantColor.java b/src/proguard/gui/splash/ConstantColor.java
new file mode 100644
index 0000000..9391ff2
--- /dev/null
+++ b/src/proguard/gui/splash/ConstantColor.java
@@ -0,0 +1,51 @@
+/* $Id: ConstantColor.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Color;
+
+/**
+ * This VariableColor is constant over time.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantColor implements VariableColor
+{
+ private Color value;
+
+
+ /**
+ * Creates a new ConstantColor.
+ * @param value the constant value.
+ */
+ public ConstantColor(Color value)
+ {
+ this.value = value;
+ }
+
+
+ // Implementation for VariableColor.
+
+ public Color getColor(long time)
+ {
+ return value;
+ }
+}
diff --git a/src/proguard/gui/splash/ConstantDouble.java b/src/proguard/gui/splash/ConstantDouble.java
new file mode 100644
index 0000000..da0e8fd
--- /dev/null
+++ b/src/proguard/gui/splash/ConstantDouble.java
@@ -0,0 +1,49 @@
+/* $Id: ConstantDouble.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This VariableDouble is constant over time.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantDouble implements VariableDouble
+{
+ private double value;
+
+
+ /**
+ * Creates a new ConstantDouble.
+ * @param value the constant value.
+ */
+ public ConstantDouble(double value)
+ {
+ this.value = value;
+ }
+
+
+ // Implementation for VariableDouble.
+
+ public double getDouble(long time)
+ {
+ return value;
+ }
+}
diff --git a/src/proguard/gui/splash/ConstantFont.java b/src/proguard/gui/splash/ConstantFont.java
new file mode 100644
index 0000000..f69f2ad
--- /dev/null
+++ b/src/proguard/gui/splash/ConstantFont.java
@@ -0,0 +1,46 @@
+/* $Id: ConstantFont.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Font;
+
+/**
+ * This VariableFont is constant over time.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantFont implements VariableFont
+{
+ private Font value;
+
+ public ConstantFont(Font value)
+ {
+ this.value = value;
+ }
+
+
+ // Implementation for VariableFont.
+
+ public Font getFont(long time)
+ {
+ return value;
+ }
+}
diff --git a/src/proguard/gui/splash/ConstantInt.java b/src/proguard/gui/splash/ConstantInt.java
new file mode 100644
index 0000000..c007256
--- /dev/null
+++ b/src/proguard/gui/splash/ConstantInt.java
@@ -0,0 +1,49 @@
+/* $Id: ConstantInt.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This VariableInt is constant over time.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantInt implements VariableInt
+{
+ private int value;
+
+
+ /**
+ * Creates a new ConstantInt.
+ * @param value the constant value.
+ */
+ public ConstantInt(int value)
+ {
+ this.value = value;
+ }
+
+
+ // Implementation for VariableInt.
+
+ public int getInt(long time)
+ {
+ return value;
+ }
+}
diff --git a/src/proguard/gui/splash/ConstantString.java b/src/proguard/gui/splash/ConstantString.java
new file mode 100644
index 0000000..3983dcf
--- /dev/null
+++ b/src/proguard/gui/splash/ConstantString.java
@@ -0,0 +1,49 @@
+/* $Id: ConstantString.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This VariableString is constant over time.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantString implements VariableString
+{
+ private String value;
+
+
+ /**
+ * Creates a new ConstantString.
+ * @param value the constant value.
+ */
+ public ConstantString(String value)
+ {
+ this.value = value;
+ }
+
+
+ // Implementation for VariableString.
+
+ public String getString(long time)
+ {
+ return value;
+ }
+}
diff --git a/src/proguard/gui/splash/ConstantTiming.java b/src/proguard/gui/splash/ConstantTiming.java
new file mode 100644
index 0000000..2c98fe4
--- /dev/null
+++ b/src/proguard/gui/splash/ConstantTiming.java
@@ -0,0 +1,58 @@
+/* $Id: ConstantTiming.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This Timing is constant over time.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantTiming implements Timing
+{
+ private double timing;
+
+
+ /**
+ * Creates a new ConstantTiming with a value of 0.
+ * @param timing the constant value of the timing.
+ */
+ public ConstantTiming()
+ {
+ this(0.0);
+ }
+
+ /**
+ * Creates a new ConstantTiming with a given value.
+ * @param timing the constant value of the timing.
+ */
+ public ConstantTiming(double timing)
+ {
+ this.timing = timing;
+ }
+
+
+ // Implementation for Timing.
+
+ public double getTiming(long time)
+ {
+ return timing;
+ }
+}
diff --git a/src/proguard/gui/splash/ImageSprite.java b/src/proguard/gui/splash/ImageSprite.java
new file mode 100644
index 0000000..cf62703
--- /dev/null
+++ b/src/proguard/gui/splash/ImageSprite.java
@@ -0,0 +1,76 @@
+/* $Id: ImageSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.*;
+
+/**
+ * This Sprite represents an animated image.
+ *
+ * @author Eric Lafortune
+ */
+public class ImageSprite implements Sprite
+{
+ private Image image;
+ private VariableInt x;
+ private VariableInt y;
+ private VariableDouble scaleX;
+ private VariableDouble scaleY;
+
+
+ /**
+ * Creates a new ImageSprite.
+ * @param image the Image to be painted.
+ * @param x the variable x-coordinate of the upper-left corner of the image.
+ * @param y the variable y-coordinate of the upper-left corner of the image.
+ * @param scaleX the variable x-scale of the image.
+ * @param scaleY the variable y-scale of the image.
+ */
+ public ImageSprite(Image image,
+ VariableInt x,
+ VariableInt y,
+ VariableDouble scaleX,
+ VariableDouble scaleY)
+ {
+ this.image = image;
+ this.x = x;
+ this.y = y;
+ this.scaleX = scaleX;
+ this.scaleY = scaleY;
+ }
+
+
+ // Implementation for Sprite.
+
+ public void paint(Graphics graphics, long time)
+ {
+ int xt = x.getInt(time);
+ int yt = y.getInt(time);
+
+ double scale_x = scaleX.getDouble(time);
+ double scale_y = scaleY.getDouble(time);
+
+ int width = (int)(image.getWidth(null) * scale_x);
+ int height = (int)(image.getHeight(null) * scale_y);
+
+ graphics.drawImage(image, xt, yt, width, height, null);
+ }
+}
diff --git a/src/proguard/gui/splash/LinearColor.java b/src/proguard/gui/splash/LinearColor.java
new file mode 100644
index 0000000..60c3666
--- /dev/null
+++ b/src/proguard/gui/splash/LinearColor.java
@@ -0,0 +1,72 @@
+/* $Id: LinearColor.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Color;
+
+/**
+ * This VariableColor varies linearly with respect to its Timing.
+ *
+ * @author Eric Lafortune
+ */
+public class LinearColor implements VariableColor
+{
+ private Color fromValue;
+ private Color toValue;
+ private Timing timing;
+
+ private double cachedTiming = -1.0;
+ private Color cachedColor;
+
+
+ /**
+ * Creates a new LinearColor.
+ * @param fromValue the value that corresponds to a timing of 0.
+ * @param toValue the value that corresponds to a timing of 1.
+ * @param timing the applied timing.
+ */
+ public LinearColor(Color fromValue, Color toValue, Timing timing)
+ {
+ this.fromValue = fromValue;
+ this.toValue = toValue;
+ this.timing = timing;
+ }
+
+
+ // Implementation for VariableColor.
+
+ public Color getColor(long time)
+ {
+ double t = timing.getTiming(time);
+ if (t != cachedTiming)
+ {
+ cachedTiming = t;
+ cachedColor =
+ t == 0.0 ? fromValue :
+ t == 1.0 ? toValue :
+ new Color((int)(fromValue.getRed() + t * (toValue.getRed() - fromValue.getRed())),
+ (int)(fromValue.getGreen() + t * (toValue.getGreen() - fromValue.getGreen())),
+ (int)(fromValue.getBlue() + t * (toValue.getBlue() - fromValue.getBlue())));
+ }
+
+ return cachedColor;
+ }
+}
diff --git a/src/proguard/gui/splash/LinearDouble.java b/src/proguard/gui/splash/LinearDouble.java
new file mode 100644
index 0000000..113a759
--- /dev/null
+++ b/src/proguard/gui/splash/LinearDouble.java
@@ -0,0 +1,55 @@
+/* $Id: LinearDouble.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This VariableDouble varies linearly with respect to its Timing.
+ *
+ * @author Eric Lafortune
+ */
+public class LinearDouble implements VariableDouble
+{
+ private double fromValue;
+ private double toValue;
+ private Timing timing;
+
+
+ /**
+ * Creates a new LinearDouble.
+ * @param fromValue the value that corresponds to a timing of 0.
+ * @param toValue the value that corresponds to a timing of 1.
+ * @param timing the applied timing.
+ */
+ public LinearDouble(double fromValue, double toValue, Timing timing)
+ {
+ this.fromValue = fromValue;
+ this.toValue = toValue;
+ this.timing = timing;
+ }
+
+
+ // Implementation for VariableDouble.
+
+ public double getDouble(long time)
+ {
+ return fromValue + timing.getTiming(time) * (toValue - fromValue);
+ }
+}
diff --git a/src/proguard/gui/splash/LinearInt.java b/src/proguard/gui/splash/LinearInt.java
new file mode 100644
index 0000000..909fc90
--- /dev/null
+++ b/src/proguard/gui/splash/LinearInt.java
@@ -0,0 +1,55 @@
+/* $Id: LinearInt.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This VariableColor varies linearly with respect to its Timing.
+ *
+ * @author Eric Lafortune
+ */
+public class LinearInt implements VariableInt
+{
+ private int fromValue;
+ private int toValue;
+ private Timing timing;
+
+
+ /**
+ * Creates a new LinearInt.
+ * @param fromValue the value that corresponds to a timing of 0.
+ * @param toValue the value that corresponds to a timing of 1.
+ * @param timing the applied timing.
+ */
+ public LinearInt(int fromValue, int toValue, Timing timing)
+ {
+ this.fromValue = fromValue;
+ this.toValue = toValue;
+ this.timing = timing;
+ }
+
+
+ // Implementation for VariableInt.
+
+ public int getInt(long time)
+ {
+ return (int) (fromValue + timing.getTiming(time) * (toValue - fromValue));
+ }
+}
diff --git a/src/proguard/gui/splash/LinearTiming.java b/src/proguard/gui/splash/LinearTiming.java
new file mode 100644
index 0000000..1dc3810
--- /dev/null
+++ b/src/proguard/gui/splash/LinearTiming.java
@@ -0,0 +1,55 @@
+/* $Id: LinearTiming.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This Timing ramps up linearly from 0 to 1 in a given time interval.
+ *
+ * @author Eric Lafortune
+ */
+public class LinearTiming implements Timing
+{
+ private long fromTime;
+ private long toTime;
+
+
+ /**
+ * Creates a new LinearTiming.
+ * @param fromTime the time at which the timing starts ramping up from 0.
+ * @param toTime the time at which the timing stops ramping up at 1.
+ */
+ public LinearTiming(long fromTime, long toTime)
+ {
+ this.fromTime = fromTime;
+ this.toTime = toTime;
+ }
+
+
+ // Implementation for Timing.
+
+ public double getTiming(long time)
+ {
+ // Compute the clamped linear interpolation.
+ return time <= fromTime ? 0.0 :
+ time >= toTime ? 1.0 :
+ (double)(time - fromTime) / (double)(toTime - fromTime);
+ }
+}
diff --git a/src/proguard/gui/splash/OverrideGraphics2D.java b/src/proguard/gui/splash/OverrideGraphics2D.java
new file mode 100644
index 0000000..4947bcd
--- /dev/null
+++ b/src/proguard/gui/splash/OverrideGraphics2D.java
@@ -0,0 +1,597 @@
+/* $Id: OverrideGraphics2D.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.*;
+import java.awt.RenderingHints.Key;
+import java.awt.font.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.*;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+/**
+ * This Graphics2D allows to fix some basic settings (Color, Font, Paint, Stroke,
+ * XORMode) of a delegate Graphics2D, overriding any subsequent attempts to
+ * change those settings.
+ *
+ * @author Eric Lafortune
+ */
+class OverrideGraphics2D extends Graphics2D
+{
+ private Graphics2D graphics;
+
+ private Color overrideColor;
+ private Font overrideFont;
+ private Paint overridePaint;
+ private Stroke overrideStroke;
+ private Color overrideXORMode;
+
+ private Color color;
+ private Font font;
+ private Paint paint;
+ private Stroke stroke;
+
+
+ /**
+ * Creates a new OverrideGraphics2D.
+ * @param graphics the delegate Graphics2D.
+ */
+ public OverrideGraphics2D(Graphics2D graphics)
+ {
+ this.graphics = graphics;
+ this.color = graphics.getColor();
+ this.font = graphics.getFont();
+ this.paint = graphics.getPaint();
+ this.stroke = graphics.getStroke();
+ }
+
+
+ /**
+ * Fixes the Color of the Graphics2D.
+ *
+ * @param color the fixed Color, or <code>null</code> to undo the fixing.
+ */
+ public void setOverrideColor(Color color)
+ {
+ this.overrideColor = color;
+ graphics.setColor(color != null ? color : this.color);
+ }
+
+ /**
+ * Fixes the Font of the Graphics2D.
+ *
+ * @param font the fixed Font, or <code>null</code> to undo the fixing.
+ */
+ public void setOverrideFont(Font font)
+ {
+ this.overrideFont = font;
+ graphics.setFont(font != null ? font : this.font);
+ }
+
+ /**
+ * Fixes the Paint of the Graphics2D.
+ *
+ * @param paint the fixed Paint, or <code>null</code> to undo the fixing.
+ */
+ public void setOverridePaint(Paint paint)
+ {
+ this.overridePaint = paint;
+ graphics.setPaint(paint != null ? paint : this.paint);
+ }
+
+ /**
+ * Fixes the Stroke of the Graphics2D.
+ *
+ * @param stroke the fixed Stroke, or <code>null</code> to undo the fixing.
+ */
+ public void setOverrideStroke(Stroke stroke)
+ {
+ this.overrideStroke = stroke;
+ graphics.setStroke(stroke != null ? stroke : this.stroke);
+ }
+
+ /**
+ * Fixes the XORMode of the Graphics2D.
+ *
+ * @param color the fixed XORMode Color, or <code>null</code> to undo the fixing.
+ */
+ public void setOverrideXORMode(Color color)
+ {
+ this.overrideXORMode = color;
+ if (color != null)
+ {
+ graphics.setXORMode(color);
+ }
+ else
+ {
+ graphics.setPaintMode();
+ }
+ }
+
+
+ // Implementations for Graphics2D.
+
+ public void setColor(Color color)
+ {
+ this.color = color;
+ if (overrideColor == null)
+ {
+ graphics.setColor(color);
+ }
+ }
+
+ public void setFont(Font font)
+ {
+ this.font = font;
+ if (overrideFont == null)
+ {
+ graphics.setFont(font);
+ }
+ }
+
+ public void setPaint(Paint paint)
+ {
+ this.paint = paint;
+ if (overridePaint == null)
+ {
+ graphics.setPaint(paint);
+ }
+ }
+
+ public void setStroke(Stroke stroke)
+ {
+ this.stroke = stroke;
+ if (overrideStroke == null)
+ {
+ graphics.setStroke(stroke);
+ }
+ }
+
+ public void setXORMode(Color color)
+ {
+ if (overrideXORMode == null)
+ {
+ graphics.setXORMode(color);
+ }
+ }
+
+ public void setPaintMode()
+ {
+ if (overrideXORMode == null)
+ {
+ graphics.setPaintMode();
+ }
+ }
+
+
+ public Color getColor()
+ {
+ return overrideColor != null ? color : graphics.getColor();
+ }
+
+ public Font getFont()
+ {
+ return overrideFont != null ? font : graphics.getFont();
+ }
+
+ public Paint getPaint()
+ {
+ return overridePaint != null ? paint : graphics.getPaint();
+ }
+
+ public Stroke getStroke()
+ {
+ return overrideStroke != null ? stroke : graphics.getStroke();
+ }
+
+
+ public Graphics create()
+ {
+ OverrideGraphics2D g = new OverrideGraphics2D((Graphics2D)graphics.create());
+ g.setOverrideColor(overrideColor);
+ g.setOverrideFont(overrideFont);
+ g.setOverridePaint(overridePaint);
+ g.setOverrideStroke(overrideStroke);
+
+ return g;
+ }
+
+ public Graphics create(int x, int y, int width, int height)
+ {
+ OverrideGraphics2D g = new OverrideGraphics2D((Graphics2D)graphics.create(x, y, width, height));
+ g.setOverrideColor(overrideColor);
+ g.setOverrideFont(overrideFont);
+ g.setOverridePaint(overridePaint);
+ g.setOverrideStroke(overrideStroke);
+
+ return g;
+ }
+
+
+ // Delegation for Graphics2D
+
+ public void addRenderingHints(Map hints)
+ {
+ graphics.addRenderingHints(hints);
+ }
+
+ public void clearRect(int x, int y, int width, int height)
+ {
+ graphics.clearRect(x, y, width, height);
+ }
+
+ public void clip(Shape s)
+ {
+ graphics.clip(s);
+ }
+
+ public void clipRect(int x, int y, int width, int height)
+ {
+ graphics.clipRect(x, y, width, height);
+ }
+
+ public void copyArea(int x, int y, int width, int height, int dx, int dy)
+ {
+ graphics.copyArea(x, y, width, height, dx, dy);
+ }
+
+ public void dispose()
+ {
+ graphics.dispose();
+ }
+
+ public void draw(Shape s)
+ {
+ graphics.draw(s);
+ }
+
+ public void draw3DRect(int x, int y, int width, int height, boolean raised)
+ {
+ graphics.draw3DRect(x, y, width, height, raised);
+ }
+
+ public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
+ {
+ graphics.drawArc(x, y, width, height, startAngle, arcAngle);
+ }
+
+ public void drawBytes(byte[] data, int offset, int length, int x, int y)
+ {
+ graphics.drawBytes(data, offset, length, x, y);
+ }
+
+ public void drawChars(char[] data, int offset, int length, int x, int y)
+ {
+ graphics.drawChars(data, offset, length, x, y);
+ }
+
+ public void drawGlyphVector(GlyphVector g, float x, float y)
+ {
+ graphics.drawGlyphVector(g, x, y);
+ }
+
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer)
+ {
+ return graphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
+ }
+
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
+ {
+ return graphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
+ }
+
+ public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer)
+ {
+ return graphics.drawImage(img, x, y, width, height, bgcolor, observer);
+ }
+
+ public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)
+ {
+ return graphics.drawImage(img, x, y, width, height, observer);
+ }
+
+ public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer)
+ {
+ return graphics.drawImage(img, x, y, bgcolor, observer);
+ }
+
+ public boolean drawImage(Image img, int x, int y, ImageObserver observer)
+ {
+ return graphics.drawImage(img, x, y, observer);
+ }
+
+ public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs)
+ {
+ return graphics.drawImage(img, xform, obs);
+ }
+
+ public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)
+ {
+ graphics.drawImage(img, op, x, y);
+ }
+
+ public void drawLine(int x1, int y1, int x2, int y2)
+ {
+ graphics.drawLine(x1, y1, x2, y2);
+ }
+
+ public void drawOval(int x, int y, int width, int height)
+ {
+ graphics.drawOval(x, y, width, height);
+ }
+
+ public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
+ {
+ graphics.drawPolygon(xPoints, yPoints, nPoints);
+ }
+
+ public void drawPolygon(Polygon p)
+ {
+ graphics.drawPolygon(p);
+ }
+
+ public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
+ {
+ graphics.drawPolyline(xPoints, yPoints, nPoints);
+ }
+
+ public void drawRect(int x, int y, int width, int height)
+ {
+ graphics.drawRect(x, y, width, height);
+ }
+
+ public void drawRenderableImage(RenderableImage img, AffineTransform xform)
+ {
+ graphics.drawRenderableImage(img, xform);
+ }
+
+ public void drawRenderedImage(RenderedImage img, AffineTransform xform)
+ {
+ graphics.drawRenderedImage(img, xform);
+ }
+
+ public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
+ {
+ graphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
+ }
+
+ public void drawString(String s, float x, float y)
+ {
+ graphics.drawString(s, x, y);
+ }
+
+ public void drawString(String str, int x, int y)
+ {
+ graphics.drawString(str, x, y);
+ }
+
+ public void drawString(AttributedCharacterIterator iterator, float x, float y)
+ {
+ graphics.drawString(iterator, x, y);
+ }
+
+ public void drawString(AttributedCharacterIterator iterator, int x, int y)
+ {
+ graphics.drawString(iterator, x, y);
+ }
+
+ public boolean equals(Object obj)
+ {
+ return graphics.equals(obj);
+ }
+
+ public void fill(Shape s)
+ {
+ graphics.fill(s);
+ }
+
+ public void fill3DRect(int x, int y, int width, int height, boolean raised)
+ {
+ graphics.fill3DRect(x, y, width, height, raised);
+ }
+
+ public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
+ {
+ graphics.fillArc(x, y, width, height, startAngle, arcAngle);
+ }
+
+ public void fillOval(int x, int y, int width, int height)
+ {
+ graphics.fillOval(x, y, width, height);
+ }
+
+ public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
+ {
+ graphics.fillPolygon(xPoints, yPoints, nPoints);
+ }
+
+ public void fillPolygon(Polygon p)
+ {
+ graphics.fillPolygon(p);
+ }
+
+ public void fillRect(int x, int y, int width, int height)
+ {
+ graphics.fillRect(x, y, width, height);
+ }
+
+ public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
+ {
+ graphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
+ }
+
+ public Color getBackground()
+ {
+ return graphics.getBackground();
+ }
+
+ public Shape getClip()
+ {
+ return graphics.getClip();
+ }
+
+ public Rectangle getClipBounds()
+ {
+ return graphics.getClipBounds();
+ }
+
+ public Rectangle getClipBounds(Rectangle r)
+ {
+ return graphics.getClipBounds(r);
+ }
+
+ public Rectangle getClipRect()
+ {
+ return graphics.getClipRect();
+ }
+
+ public Composite getComposite()
+ {
+ return graphics.getComposite();
+ }
+
+ public GraphicsConfiguration getDeviceConfiguration()
+ {
+ return graphics.getDeviceConfiguration();
+ }
+
+ public FontMetrics getFontMetrics()
+ {
+ return graphics.getFontMetrics();
+ }
+
+ public FontMetrics getFontMetrics(Font f)
+ {
+ return graphics.getFontMetrics(f);
+ }
+
+ public FontRenderContext getFontRenderContext()
+ {
+ return graphics.getFontRenderContext();
+ }
+
+ public Object getRenderingHint(Key hintKey)
+ {
+ return graphics.getRenderingHint(hintKey);
+ }
+
+ public RenderingHints getRenderingHints()
+ {
+ return graphics.getRenderingHints();
+ }
+
+ public AffineTransform getTransform()
+ {
+ return graphics.getTransform();
+ }
+
+ public int hashCode()
+ {
+ return graphics.hashCode();
+ }
+
+ public boolean hit(Rectangle rect, Shape s, boolean onStroke)
+ {
+ return graphics.hit(rect, s, onStroke);
+ }
+
+ public boolean hitClip(int x, int y, int width, int height)
+ {
+ return graphics.hitClip(x, y, width, height);
+ }
+
+ public void rotate(double theta)
+ {
+ graphics.rotate(theta);
+ }
+
+ public void rotate(double theta, double x, double y)
+ {
+ graphics.rotate(theta, x, y);
+ }
+
+ public void scale(double sx, double sy)
+ {
+ graphics.scale(sx, sy);
+ }
+
+ public void setBackground(Color color)
+ {
+ graphics.setBackground(color);
+ }
+
+ public void setClip(int x, int y, int width, int height)
+ {
+ graphics.setClip(x, y, width, height);
+ }
+
+ public void setClip(Shape clip)
+ {
+ graphics.setClip(clip);
+ }
+
+ public void setComposite(Composite comp)
+ {
+ graphics.setComposite(comp);
+ }
+
+ public void setRenderingHint(Key hintKey, Object hintValue)
+ {
+ graphics.setRenderingHint(hintKey, hintValue);
+ }
+
+ public void setRenderingHints(Map hints)
+ {
+ graphics.setRenderingHints(hints);
+ }
+
+ public void setTransform(AffineTransform Tx)
+ {
+ graphics.setTransform(Tx);
+ }
+
+ public void shear(double shx, double shy)
+ {
+ graphics.shear(shx, shy);
+ }
+
+ public String toString()
+ {
+ return graphics.toString();
+ }
+
+ public void transform(AffineTransform Tx)
+ {
+ graphics.transform(Tx);
+ }
+
+ public void translate(double tx, double ty)
+ {
+ graphics.translate(tx, ty);
+ }
+
+ public void translate(int x, int y)
+ {
+ graphics.translate(x, y);
+ }
+}
diff --git a/src/proguard/gui/splash/RectangleSprite.java b/src/proguard/gui/splash/RectangleSprite.java
new file mode 100644
index 0000000..146c08d
--- /dev/null
+++ b/src/proguard/gui/splash/RectangleSprite.java
@@ -0,0 +1,114 @@
+/* $Id: RectangleSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Graphics;
+
+/**
+ * This Sprite represents an animated rounded rectangle. It can optionally be filled.
+ *
+ * @author Eric Lafortune
+ */
+public class RectangleSprite implements Sprite
+{
+ private boolean filled;
+ private VariableColor color;
+ private VariableInt x;
+ private VariableInt y;
+ private VariableInt width;
+ private VariableInt height;
+ private VariableInt arcWidth;
+ private VariableInt arcHeight;
+
+
+ /**
+ * Creates a new rectangular RectangleSprite.
+ * @param filled specifies whether the rectangle should be filled.
+ * @param color the variable color of the rectangle.
+ * @param x the variable x-coordinate of the upper-left corner of the rectangle.
+ * @param y the variable y-coordinate of the upper-left corner of the rectangle.
+ * @param width the variable width of the rectangle.
+ * @param height the variable height of the rectangle.
+ */
+ public RectangleSprite(boolean filled,
+ VariableColor color,
+ VariableInt x,
+ VariableInt y,
+ VariableInt width,
+ VariableInt height)
+ {
+ this(filled, color, x, y, width, height, new ConstantInt(0), new ConstantInt(0));
+ }
+
+
+ /**
+ * Creates a new RectangleSprite with rounded corners.
+ * @param filled specifies whether the rectangle should be filled.
+ * @param color the variable color of the rectangle.
+ * @param x the variable x-coordinate of the upper-left corner of the rectangle.
+ * @param y the variable y-coordinate of the upper-left corner of the rectangle.
+ * @param width the variable width of the rectangle.
+ * @param height the variable height of the rectangle.
+ * @param arcwWidth the variable width of the corner arcs.
+ * @param arcwHeight the variable height of the corner arcs.
+ */
+ public RectangleSprite(boolean filled,
+ VariableColor color,
+ VariableInt x,
+ VariableInt y,
+ VariableInt width,
+ VariableInt height,
+ VariableInt arcWidth,
+ VariableInt arcHeight)
+ {
+ this.filled = filled;
+ this.color = color;
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.arcWidth = arcWidth;
+ this.arcHeight = arcHeight;
+ }
+
+ // Implementation for Sprite.
+
+ public void paint(Graphics graphics, long time)
+ {
+ graphics.setColor(color.getColor(time));
+
+ int xt = x.getInt(time);
+ int yt = y.getInt(time);
+ int w = width.getInt(time);
+ int h = height.getInt(time);
+ int aw = arcWidth.getInt(time);
+ int ah = arcHeight.getInt(time);
+
+ if (filled)
+ {
+ graphics.fillRoundRect(xt, yt, w, h, aw, ah);
+ }
+ else
+ {
+ graphics.drawRoundRect(xt, yt, w, h, aw, ah);
+ }
+ }
+}
diff --git a/src/proguard/gui/splash/SawToothTiming.java b/src/proguard/gui/splash/SawToothTiming.java
new file mode 100644
index 0000000..0c7c1ab
--- /dev/null
+++ b/src/proguard/gui/splash/SawToothTiming.java
@@ -0,0 +1,53 @@
+/* $Id: SawToothTiming.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This Timing ramps up linearly from 0 to 1 in a given repeated time interval.
+ *
+ * @author Eric Lafortune
+ */
+public class SawToothTiming implements Timing
+{
+ private long period;
+ private long phase;
+
+
+ /**
+ * Creates a new SawToothTiming.
+ * @param period the time period for a full cycle.
+ * @param phase the phase of the cycle, which is added to the actual time.
+ */
+ public SawToothTiming(long period, long phase)
+ {
+ this.period = period;
+ this.phase = phase;
+ }
+
+
+ // Implementation for Timing.
+
+ public double getTiming(long time)
+ {
+ // Compute the translated and scaled saw-tooth function.
+ return (double)((time + phase) % period) / (double)period;
+ }
+}
diff --git a/src/proguard/gui/splash/ShadowedSprite.java b/src/proguard/gui/splash/ShadowedSprite.java
new file mode 100644
index 0000000..64639e6
--- /dev/null
+++ b/src/proguard/gui/splash/ShadowedSprite.java
@@ -0,0 +1,102 @@
+/* $Id: ShadowedSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.*;
+
+/**
+ * This Sprite adds a drop shadow to another Sprite.
+ *
+ * @author Eric Lafortune
+ */
+public class ShadowedSprite implements Sprite
+{
+ private VariableInt xOffset;
+ private VariableInt yOffset;
+ private VariableDouble alpha;
+ private VariableInt blur;
+ private Sprite sprite;
+
+ private float cachedAlpha = -1.0f;
+ private Color cachedColor;
+
+
+ /**
+ * Creates a new ShadowedSprite.
+ * @param xOffset the variable x-offset of the shadow, relative to the sprite itself.
+ * @param yOffset the variable y-offset of the shadow, relative to the sprite itself.
+ * @param alpha the variable darkness of the shadow (between 0 and 1).
+ * @param blur the variable blur of the shadow (0 for sharp shadows, 1 or
+ * more for increasingly blurry shadows).
+ * @param sprite the Sprite to be painted with its shadow.
+ */
+ public ShadowedSprite(VariableInt xOffset,
+ VariableInt yOffset,
+ VariableDouble alpha,
+ VariableInt blur,
+ Sprite sprite)
+ {
+ this.xOffset = xOffset;
+ this.yOffset = yOffset;
+ this.alpha = alpha;
+ this.blur = blur;
+ this.sprite = sprite;
+ }
+
+
+ // Implementation for Sprite.
+
+ public void paint(Graphics graphics, long time)
+ {
+ double l = alpha.getDouble(time);
+ int b = blur.getInt(time) + 1;
+
+ // Set up the shadow graphics.
+ OverrideGraphics2D g = new OverrideGraphics2D((Graphics2D)graphics);
+
+ float a = 1.0f - (float)Math.pow(1.0 - l, 1.0/(b*b));
+ if (a != cachedAlpha)
+ {
+ cachedAlpha = a;
+ cachedColor = new Color(0f, 0f, 0f, a);
+ }
+ g.setOverrideColor(cachedColor);
+
+ int xo = xOffset.getInt(time) - b/2;
+ int yo = yOffset.getInt(time) - b/2;
+
+ // Draw the sprite's shadow in the shadow graphics.
+ for (int x = 0; x < b; x++)
+ {
+ for (int y = 0; y < b; y++)
+ {
+ int xt = xo + x;
+ int yt = yo + y;
+ g.translate(xt, yt);
+ sprite.paint(g, time);
+ g.translate(-xt, -yt);
+ }
+ }
+
+ // Draw the sprite itself in the ordinary graphics.
+ sprite.paint(graphics, time);
+ }
+}
diff --git a/src/proguard/gui/splash/SineTiming.java b/src/proguard/gui/splash/SineTiming.java
new file mode 100644
index 0000000..151ec73
--- /dev/null
+++ b/src/proguard/gui/splash/SineTiming.java
@@ -0,0 +1,53 @@
+/* $Id: SineTiming.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This Timing varies between 0 and 1, as a sine wave over time.
+ *
+ * @author Eric Lafortune
+ */
+public class SineTiming implements Timing
+{
+ private long period;
+ private long phase;
+
+
+ /**
+ * Creates a new SineTiming.
+ * @param period the time period for a full cycle.
+ * @param phase the phase of the cycle, which is added to the actual time.
+ */
+ public SineTiming(long period, long phase)
+ {
+ this.period = period;
+ this.phase = phase;
+ }
+
+
+ // Implementation for Timing.
+
+ public double getTiming(long time)
+ {
+ // Compute the translated and scaled sine function.
+ return 0.5 + 0.5 * Math.sin(2.0 * Math.PI * (time + phase) / period);
+ }
+}
diff --git a/src/proguard/gui/splash/SmoothTiming.java b/src/proguard/gui/splash/SmoothTiming.java
new file mode 100644
index 0000000..89a3cd7
--- /dev/null
+++ b/src/proguard/gui/splash/SmoothTiming.java
@@ -0,0 +1,66 @@
+/* $Id: SmoothTiming.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This Timing ramps up smoothly from 0 to 1 in a given time interval.
+ *
+ * @author Eric Lafortune
+ */
+public class SmoothTiming implements Timing
+{
+ private long fromTime;
+ private long toTime;
+
+
+ /**
+ * Creates a new SmoothTiming.
+ * @param fromTime the time at which the timing starts ramping up from 0.
+ * @param toTime the time at which the timing stops ramping up at 1.
+ */
+ public SmoothTiming(long fromTime, long toTime)
+ {
+ this.fromTime = fromTime;
+ this.toTime = toTime;
+ }
+
+
+ // Implementation for Timing.
+
+ public double getTiming(long time)
+ {
+ if (time <= fromTime)
+ {
+ return 0.0;
+ }
+
+ if (time >= toTime)
+ {
+ return 1.0;
+ }
+
+ // Compute the linear interpolation.
+ double timing = (double) (time - fromTime) / (double) (toTime - fromTime);
+
+ // Smooth the interpolation at the ends.
+ return timing * timing * (3.0 - 2.0 * timing);
+ }
+}
diff --git a/src/proguard/gui/splash/SplashPanel.java b/src/proguard/gui/splash/SplashPanel.java
new file mode 100644
index 0000000..6d30f8a
--- /dev/null
+++ b/src/proguard/gui/splash/SplashPanel.java
@@ -0,0 +1,217 @@
+/* $Id: SplashPanel.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+/**
+ * This JPanel renders an animated Sprite.
+ *
+ * @author Eric Lafortune
+ */
+public class SplashPanel extends JPanel
+{
+ private final MyAnimator animator = new MyAnimator();
+ private final MyRepainter repainter = new MyRepainter();
+
+ private Sprite sprite;
+ private double sleepFactor;
+
+ private long startTime = Long.MAX_VALUE;
+ private long stopTime;
+ private Thread animationThread;
+
+
+ /**
+ * Creates a new SplashPanel with the given Sprite, which will be animated
+ * indefinitely.
+ * @param sprite the Sprite that will be animated.
+ * @param processorLoad the fraction of processing time to be spend on
+ * animating the Sprite (between 0 and 1).
+ */
+ public SplashPanel(Sprite sprite, double processorLoad)
+ {
+ this(sprite, processorLoad, (long)Integer.MAX_VALUE);
+ }
+
+
+ /**
+ * Creates a new SplashPanel with the given Sprite, which will be animated
+ * for a limited period of time.
+ * @param sprite the Sprite that will be animated.
+ * @param processorLoad the fraction of processing time to be spend on
+ * animating the Sprite (between 0 and 1).
+ * @param stopTime the number of milliseconds after which the
+ * animation will be stopped automatically.
+ */
+ public SplashPanel(Sprite sprite, double processorLoad, long stopTime)
+ {
+ this.sprite = sprite;
+ this.sleepFactor = (1.0-processorLoad) / processorLoad;
+ this.stopTime = stopTime;
+
+ // Restart the animation on a mouse click.
+ addMouseListener(new MouseAdapter()
+ {
+ public void mouseClicked(MouseEvent e)
+ {
+ SplashPanel.this.start();
+ }
+ });
+ }
+
+
+ /**
+ * Starts the animation.
+ */
+ public void start()
+ {
+ // Go to the beginning of the animation.
+ startTime = System.currentTimeMillis();
+
+ // Make sure we have an animation thread running.
+ if (animationThread == null)
+ {
+ animationThread = new Thread(animator);
+ animationThread.start();
+ }
+ }
+
+
+ /**
+ * Stops the animation.
+ */
+ public void stop()
+ {
+ // Go to the end of the animation.
+ startTime = 0L;
+
+ // Let the animation thread stop itself.
+ animationThread = null;
+
+ // Repaint the SplashPanel one last time.
+ try
+ {
+ SwingUtilities.invokeAndWait(repainter);
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+
+
+ // Implementation for JPanel.
+
+ public void paintComponent(Graphics graphics)
+ {
+ super.paintComponent(graphics);
+
+ sprite.paint(graphics, System.currentTimeMillis() - startTime);
+ }
+
+
+ /**
+ * This Runnable makes sure its SplashPanel gets repainted regularly,
+ * depending on the targeted processor load.
+ */
+ private class MyAnimator implements Runnable
+ {
+ public void run()
+ {
+ try
+ {
+ while (animationThread != null)
+ {
+ // Check if we should stop the animation.
+ long time = System.currentTimeMillis();
+ if (time > startTime + stopTime)
+ {
+ animationThread = null;
+ }
+
+ // Do a repaint and time it.
+ SwingUtilities.invokeAndWait(repainter);
+ time = System.currentTimeMillis() - time;
+
+ // Sleep for a proportional while.
+ Thread.sleep((long)(sleepFactor * time));
+ }
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ }
+
+
+ /**
+ * This Runnable repaints its SplashPanel.
+ */
+ private class MyRepainter implements Runnable
+ {
+ public void run()
+ {
+ SplashPanel.this.repaint();
+ }
+ }
+
+
+ /**
+ * A main method for testing the splash panel.
+ */
+ public static void main(String[] args)
+ {
+ JFrame frame = new JFrame();
+ frame.setTitle("Animation");
+ frame.setSize(800, 600);
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension frameSize = frame.getSize();
+ frame.setLocation((screenSize.width - frameSize.width) / 2,
+ (screenSize.height - frameSize.height) / 2);
+
+ Sprite sprite =
+ new ClipSprite(
+ new ConstantColor(Color.white),
+ new ConstantColor(Color.lightGray),
+ new CircleSprite(true,
+ new ConstantColor(Color.green),
+ new LinearInt(200, 600, new SineTiming(2345L, 0L)),
+ new LinearInt(200, 400, new SineTiming(3210L, 0L)),
+ new ConstantInt(150)),
+ new TextSprite(new ConstantString("ProGuard"),
+ new ConstantFont(new Font("sansserif", Font.BOLD, 90)),
+ new ConstantColor(Color.gray),
+ new ConstantInt(200),
+ new ConstantInt(300)));
+
+ SplashPanel panel = new SplashPanel(sprite, 0.5);
+ panel.setBackground(Color.white);
+
+ frame.getContentPane().add(panel);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+
+ panel.start();
+ }
+}
diff --git a/src/proguard/gui/splash/Sprite.java b/src/proguard/gui/splash/Sprite.java
new file mode 100644
index 0000000..01e7fb2
--- /dev/null
+++ b/src/proguard/gui/splash/Sprite.java
@@ -0,0 +1,41 @@
+/* $Id: Sprite.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Graphics;
+
+/**
+ * This interface describes objects that can paint themselves, possibly varying
+ * as a function of time.
+ *
+ * @author Eric Lafortune
+ */
+public interface Sprite
+{
+ /**
+ * Paints the object.
+ *
+ * @param graphics the Graphics to paint on.
+ * @param time the time since the start of the animation, expressed in
+ * milliseconds.
+ */
+ public void paint(Graphics graphics, long time);
+}
diff --git a/src/proguard/gui/splash/TextSprite.java b/src/proguard/gui/splash/TextSprite.java
new file mode 100644
index 0000000..a31c9f6
--- /dev/null
+++ b/src/proguard/gui/splash/TextSprite.java
@@ -0,0 +1,102 @@
+/* $Id: TextSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.*;
+
+/**
+ * This Sprite represents a text.
+ *
+ * @author Eric Lafortune
+ */
+public class TextSprite implements Sprite
+{
+ private VariableString[] text;
+ private VariableInt spacing;
+ private VariableFont font;
+ private VariableColor color;
+ private VariableInt x;
+ private VariableInt y;
+
+
+ /**
+ * Creates a new TextSprite containing a single line of text.
+ * @param text the variable text string.
+ * @param font the variable text font.
+ * @param color the variable color.
+ * @param x the variable x-coordinate of the lower-left corner of the text.
+ * @param y the variable y-coordinate of the lower-left corner of the text.
+ */
+ public TextSprite(VariableString text,
+ VariableFont font,
+ VariableColor color,
+ VariableInt x,
+ VariableInt y)
+ {
+ this(new VariableString[] { text }, new ConstantInt(0), font, color, x, y);
+ }
+
+
+ /**
+ * Creates a new TextSprite containing a multiple lines of text.
+ * @param text the variable text strings.
+ * @param spacing the variable spacing between the lines of text.
+ * @param font the variable text font.
+ * @param color the variable color.
+ * @param x the variable x-coordinate of the lower-left corner of the
+ * first line of text.
+ * @param y the variable y-coordinate of the lower-left corner of the
+ * first line of text.
+ */
+ public TextSprite(VariableString[] text,
+ VariableInt spacing,
+ VariableFont font,
+ VariableColor color,
+ VariableInt x,
+ VariableInt y)
+ {
+
+ this.text = text;
+ this.spacing = spacing;
+ this.font = font;
+ this.color = color;
+ this.x = x;
+ this.y = y;
+ }
+
+
+ // Implementation for Sprite.
+
+ public void paint(Graphics graphics, long time)
+ {
+
+ int xt = x.getInt(time);
+ int yt = y.getInt(time);
+
+ graphics.setFont(font.getFont(time));
+ graphics.setColor(color.getColor(time));
+
+ for (int index = 0; index < text.length; index++)
+ {
+ graphics.drawString(text[index].getString(time), xt, yt + index * spacing.getInt(time));
+ }
+ }
+}
diff --git a/src/proguard/gui/splash/TimeSwitchSprite.java b/src/proguard/gui/splash/TimeSwitchSprite.java
new file mode 100644
index 0000000..53bd207
--- /dev/null
+++ b/src/proguard/gui/splash/TimeSwitchSprite.java
@@ -0,0 +1,75 @@
+/* $Id: TimeSwitchSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Graphics;
+
+/**
+ * This Sprite displays another Sprite in a given time interval.
+ * The time of the encapsulated Sprite is shifted by the start time.
+ *
+ * @author Eric Lafortune
+ */
+public class TimeSwitchSprite implements Sprite
+{
+ private long onTime;
+ private long offtime;
+ private Sprite sprite;
+
+
+ /**
+ * Creates a new TimeSwitchSprite for displaying a given Sprite starting at a
+ * given time.
+ * @param onTime the start time.
+ * @param sprite the toggled Sprite.
+ */
+ public TimeSwitchSprite(long onTime, Sprite sprite)
+ {
+ this(onTime, 0L, sprite);
+ }
+
+
+ /**
+ * Creates a new TimeSwitchSprite for displaying a given Sprite in a given
+ * time interval.
+ * @param onTime the start time.
+ * @param offTime the stop time.
+ * @param sprite the toggled Sprite.
+ */
+ public TimeSwitchSprite(long onTime, long offtime, Sprite sprite)
+ {
+ this.onTime = onTime;
+ this.offtime = offtime;
+ this.sprite = sprite;
+ }
+
+
+ // Implementation for Sprite.
+
+ public void paint(Graphics graphics, long time)
+ {
+ if (time >= onTime && (offtime <= 0 || time <= offtime))
+ {
+ sprite.paint(graphics, time - onTime);
+ }
+
+ }
+}
diff --git a/src/proguard/gui/splash/Timing.java b/src/proguard/gui/splash/Timing.java
new file mode 100644
index 0000000..e9b0029
--- /dev/null
+++ b/src/proguard/gui/splash/Timing.java
@@ -0,0 +1,34 @@
+/* $Id: Timing.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This interface maps a time to a normalized timing between 0 and 1.
+ *
+ * @author Eric Lafortune
+ */
+interface Timing
+{
+ /**
+ * Returns the timing for the given time.
+ */
+ public double getTiming(long time);
+}
diff --git a/src/proguard/gui/splash/TypeWriterString.java b/src/proguard/gui/splash/TypeWriterString.java
new file mode 100644
index 0000000..6c1fd27
--- /dev/null
+++ b/src/proguard/gui/splash/TypeWriterString.java
@@ -0,0 +1,71 @@
+/* $Id: TypeWriterString.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This VariableString produces a String that grows linearly with respect to its
+ * Timing, as if it is being written on a typewriter. A cursor at the end
+ * precedes the typed characters.
+ *
+ * @author Eric Lafortune
+ */
+public class TypeWriterString implements VariableString
+{
+ private String string;
+ private Timing timing;
+
+ private int cachedLength = -1;
+ private String cachedString;
+
+
+ /**
+ * Creates a new TypeWriterString.
+ * @param string the basic String.
+ * @param timing the applied timing.
+ */
+ public TypeWriterString(String string, Timing timing)
+ {
+ this.string = string;
+ this.timing = timing;
+ }
+
+
+ // Implementation for VariableString.
+
+ public String getString(long time)
+ {
+ double t = timing.getTiming(time);
+
+ int stringLength = string.length();
+ int length = (int)(stringLength * t + 0.5);
+ if (length != cachedLength)
+ {
+ cachedLength = length;
+ cachedString = string.substring(0, length);
+ if (t > 0.0 && length < stringLength)
+ {
+ cachedString += "_";
+ }
+ }
+
+ return cachedString;
+ }
+}
diff --git a/src/proguard/gui/splash/VariableColor.java b/src/proguard/gui/splash/VariableColor.java
new file mode 100644
index 0000000..715d353
--- /dev/null
+++ b/src/proguard/gui/splash/VariableColor.java
@@ -0,0 +1,36 @@
+/* $Id: VariableColor.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Color;
+
+/**
+ * This interface represents a Color that varies with time.
+ *
+ * @author Eric Lafortune
+ */
+interface VariableColor
+{
+ /**
+ * Returns the Color for the given time.
+ */
+ public Color getColor(long time);
+}
diff --git a/src/proguard/gui/splash/VariableDouble.java b/src/proguard/gui/splash/VariableDouble.java
new file mode 100644
index 0000000..78dab89
--- /dev/null
+++ b/src/proguard/gui/splash/VariableDouble.java
@@ -0,0 +1,34 @@
+/* $Id: VariableDouble.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This interface represents a double that varies with time.
+ *
+ * @author Eric Lafortune
+ */
+interface VariableDouble
+{
+ /**
+ * Returns the double for the given time.
+ */
+ public double getDouble(long time);
+}
diff --git a/src/proguard/gui/splash/VariableFont.java b/src/proguard/gui/splash/VariableFont.java
new file mode 100644
index 0000000..9da8e73
--- /dev/null
+++ b/src/proguard/gui/splash/VariableFont.java
@@ -0,0 +1,36 @@
+/* $Id: VariableFont.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.*;
+
+/**
+ * This interface represents a Font that varies with time.
+ *
+ * @author Eric Lafortune
+ */
+interface VariableFont
+{
+ /**
+ * Returns the Font for the given time.
+ */
+ public Font getFont(long time);
+}
diff --git a/src/proguard/gui/splash/VariableInt.java b/src/proguard/gui/splash/VariableInt.java
new file mode 100644
index 0000000..53f583d
--- /dev/null
+++ b/src/proguard/gui/splash/VariableInt.java
@@ -0,0 +1,34 @@
+/* $Id: VariableInt.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This interface represents an integer that varies with time.
+ *
+ * @author Eric Lafortune
+ */
+interface VariableInt
+{
+ /**
+ * Returns the integer for the given time.
+ */
+ public int getInt(long time);
+}
diff --git a/src/proguard/gui/splash/VariableSizeFont.java b/src/proguard/gui/splash/VariableSizeFont.java
new file mode 100644
index 0000000..db0d9d5
--- /dev/null
+++ b/src/proguard/gui/splash/VariableSizeFont.java
@@ -0,0 +1,65 @@
+/* $Id: VariableSizeFont.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+import java.awt.Font;
+
+/**
+ * This VariableFont varies in size with respect to its Timing.
+ *
+ * @author Eric Lafortune
+ */
+public class VariableSizeFont implements VariableFont
+{
+ private Font font;
+ private VariableDouble size;
+
+ private float cachedSize = -1.0f;
+ private Font cachedFont;
+
+
+ /**
+ * Creates a new VariableSizeFont
+ * @param font the base font.
+ * @param size the variable size of the font.
+ */
+ public VariableSizeFont(Font font, VariableDouble size)
+ {
+ this.font = font;
+ this.size = size;
+ }
+
+
+ // Implementation for VariableFont.
+
+ public Font getFont(long time)
+ {
+ float s = (float)size.getDouble(time);
+
+ if (s != cachedSize)
+ {
+ cachedSize = s;
+ cachedFont = font.deriveFont((float)s);
+ }
+
+ return cachedFont;
+ }
+}
diff --git a/src/proguard/gui/splash/VariableString.java b/src/proguard/gui/splash/VariableString.java
new file mode 100644
index 0000000..63e9e03
--- /dev/null
+++ b/src/proguard/gui/splash/VariableString.java
@@ -0,0 +1,34 @@
+/* $Id: VariableString.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui.splash;
+
+/**
+ * This interface represents a String that varies with time.
+ *
+ * @author Eric Lafortune
+ */
+interface VariableString
+{
+ /**
+ * Returns the String for the given time.
+ */
+ public String getString(long time);
+}
diff --git a/src/proguard/gui/splash/package.html b/src/proguard/gui/splash/package.html
new file mode 100644
index 0000000..209fad7
--- /dev/null
+++ b/src/proguard/gui/splash/package.html
@@ -0,0 +1,4 @@
+<body>
+This package contains a library for creating splash screens and animations
+with text, graphical elements, and some special effects.
+</body>
diff --git a/src/proguard/gui/vtitle.gif b/src/proguard/gui/vtitle.gif
new file mode 100644
index 0000000..646c69b
Binary files /dev/null and b/src/proguard/gui/vtitle.gif differ
diff --git a/src/proguard/io/CascadingDataEntryWriter.java b/src/proguard/io/CascadingDataEntryWriter.java
new file mode 100644
index 0000000..f967ec4
--- /dev/null
+++ b/src/proguard/io/CascadingDataEntryWriter.java
@@ -0,0 +1,86 @@
+/* $Id: CascadingDataEntryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import proguard.util.*;
+
+import java.io.*;
+
+/**
+ * This DataEntryWriter delegates to a given DataEntryWriter, or failing that,
+ * to another given DataEntryWriter.
+ *
+ * @author Eric Lafortune
+ */
+public class CascadingDataEntryWriter implements DataEntryWriter
+{
+ private DataEntryWriter dataEntryWriter1;
+ private DataEntryWriter dataEntryWriter2;
+
+
+ /**
+ * Creates a new FilteredDataEntryWriter.
+ * @param dataEntryWriter1 the DataEntryWriter to which the writing will be
+ * delegated first.
+ * @param dataEntryWriter2 the DataEntryWriter to which the writing will be
+ * delegated, if the first one can't provide an
+ * output stream.
+ */
+ public CascadingDataEntryWriter(DataEntryWriter dataEntryWriter1,
+ DataEntryWriter dataEntryWriter2)
+ {
+ this.dataEntryWriter1 = dataEntryWriter1;
+ this.dataEntryWriter2 = dataEntryWriter2;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
+ {
+ return getOutputStream(dataEntry, null);
+ }
+
+
+ public OutputStream getOutputStream(DataEntry dataEntry,
+ Finisher finisher) throws IOException
+ {
+ // Try to get an output stream from the first data entry writer.
+ OutputStream outputStream =
+ dataEntryWriter1.getOutputStream(dataEntry, finisher);
+
+ // Return it, if it's not null. Otherwise try to get an output stream
+ // from the second data entry writer.
+ return outputStream != null ?
+ outputStream :
+ dataEntryWriter2.getOutputStream(dataEntry, finisher);
+ }
+
+
+ public void close() throws IOException
+ {
+ dataEntryWriter1.close();
+ dataEntryWriter2.close();
+
+ dataEntryWriter1 = null;
+ dataEntryWriter2 = null;
+ }
+}
diff --git a/src/proguard/io/ClassFileFilter.java b/src/proguard/io/ClassFileFilter.java
new file mode 100644
index 0000000..b439b52
--- /dev/null
+++ b/src/proguard/io/ClassFileFilter.java
@@ -0,0 +1,72 @@
+/* $Id: ClassFileFilter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import proguard.classfile.*;
+import proguard.util.*;
+
+import java.io.*;
+
+
+/**
+ * This DataEntryReader delegates to one of two other DataEntryReader instances,
+ * depending on the extension of the data entry.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileFilter implements DataEntryReader
+{
+ private FilteredDataEntryReader filteredDataEntryReader;
+
+
+ /**
+ * Creates a new ClassFileFilter that delegates reading class files to the
+ * given reader.
+ */
+ public ClassFileFilter(DataEntryReader classFileReader)
+ {
+ this(classFileReader, null);
+ }
+
+
+ /**
+ * Creates a new ClassFileFilter that delegates to either of the two given
+ * readers.
+ */
+ public ClassFileFilter(DataEntryReader classFileReader,
+ DataEntryReader dataEntryReader)
+ {
+ filteredDataEntryReader =
+ new FilteredDataEntryReader(
+ new DataEntryNameFilter(
+ new ExtensionMatcher(ClassConstants.CLASS_FILE_EXTENSION)),
+ classFileReader,
+ dataEntryReader);
+ }
+
+
+ // Implementations for DataEntryReader.
+
+ public void read(DataEntry dataEntry) throws IOException
+ {
+ filteredDataEntryReader.read(dataEntry);
+ }
+}
diff --git a/src/proguard/io/ClassFileReader.java b/src/proguard/io/ClassFileReader.java
new file mode 100644
index 0000000..75b33ea
--- /dev/null
+++ b/src/proguard/io/ClassFileReader.java
@@ -0,0 +1,94 @@
+/* $Id: ClassFileReader.java,v 1.3 2004/11/20 15:08:57 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+/**
+ * This DataEntryReader applies a given ClassFileVisitor to the class file
+ * definitions that it reads.
+ * <p>
+ * Class files are read as ProgramClassFile objects or LibraryClassFile objects,
+ * depending on the <code>isLibrary</code> flag.
+ * <p>
+ * In case of libraries, only public class files are considered, if the
+ * <code>skipNonPublicLibraryClasses</code> flag is set.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileReader implements DataEntryReader
+{
+ private boolean isLibrary;
+ private boolean skipNonPublicLibraryClasses;
+ private boolean skipNonPublicLibraryClassMembers;
+ private ClassFileVisitor classFileVisitor;
+
+
+ /**
+ * Creates a new DataEntryClassFileFilter for reading the specified
+ * ClassFile objects.
+ */
+ public ClassFileReader(boolean isLibrary,
+ boolean skipNonPublicLibraryClasses,
+ boolean skipNonPublicLibraryClassMembers,
+ ClassFileVisitor classFileVisitor)
+ {
+ this.isLibrary = isLibrary;
+ this.skipNonPublicLibraryClasses = skipNonPublicLibraryClasses;
+ this.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembers;
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for DataEntryReader.
+
+ public void read(DataEntry dataEntry) throws IOException
+ {
+ try
+ {
+ // Get the input stream.
+ InputStream inputStream = dataEntry.getInputStream();
+
+ // Wrap it into a data input stream.
+ DataInputStream dataInputStream = new DataInputStream(inputStream);
+
+ // Create a ClassFile representation.
+ ClassFile classFile = isLibrary ?
+ (ClassFile)LibraryClassFile.create(dataInputStream, skipNonPublicLibraryClasses, skipNonPublicLibraryClassMembers) :
+ (ClassFile)ProgramClassFile.create(dataInputStream);
+
+ // Apply the visitor.
+ if (classFile != null)
+ {
+ classFile.accept(classFileVisitor);
+ }
+
+ dataEntry.closeInputStream();
+ }
+ catch (Exception ex)
+ {
+ throw new IOException("Can't process class file ["+dataEntry.getName()+"] ("+ex.getMessage()+")");
+ }
+ }
+}
diff --git a/src/proguard/io/ClassFileRewriter.java b/src/proguard/io/ClassFileRewriter.java
new file mode 100644
index 0000000..e50f506
--- /dev/null
+++ b/src/proguard/io/ClassFileRewriter.java
@@ -0,0 +1,77 @@
+/* $Id: ClassFileRewriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+
+/**
+ * This DataEntryReader reads class file entries and writes their corresponding
+ * versions from the ClassPool to a given DataEntryWriter.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileRewriter implements DataEntryReader
+{
+ private ClassPool classPool;
+ private DataEntryWriter dataEntryWriter;
+
+
+ public ClassFileRewriter(ClassPool classPool,
+ DataEntryWriter dataEntryWriter)
+ {
+ this.classPool = classPool;
+ this.dataEntryWriter = dataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryReader.
+
+ public void read(DataEntry dataEntry) throws IOException
+ {
+ String inputName = dataEntry.getName();
+ String className = inputName.substring(0, inputName.length() - ClassConstants.CLASS_FILE_EXTENSION.length());
+
+ // Find the modified class corrsponding to the input entry.
+ ProgramClassFile programClassFile = (ProgramClassFile)classPool.getClass(className);
+ if (programClassFile != null)
+ {
+ // Rename the data entry if necessary.
+ String newClassName = programClassFile.getName();
+ if (!className.equals(newClassName))
+ {
+ dataEntry = new RenamedDataEntry(dataEntry, newClassName + ClassConstants.CLASS_FILE_EXTENSION);
+ }
+
+ // Get the output entry corresponding to this input entry.
+ OutputStream outputStream = dataEntryWriter.getOutputStream(dataEntry);
+ if (outputStream != null)
+ {
+ // Write the class to the output entry.
+ DataOutputStream classOutputStream = new DataOutputStream(outputStream);
+ programClassFile.write(classOutputStream);
+ classOutputStream.flush();
+ }
+ }
+ }
+}
diff --git a/src/proguard/io/DataEntry.java b/src/proguard/io/DataEntry.java
new file mode 100644
index 0000000..03aeb9d
--- /dev/null
+++ b/src/proguard/io/DataEntry.java
@@ -0,0 +1,55 @@
+/* $Id: DataEntry.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+
+/**
+ * This interface describes a data entry, e.g. a ZIP entry or a file.
+ *
+ * @author Eric Lafortune
+ */
+public interface DataEntry
+{
+ /**
+ * Returns the name of this data entry.
+ */
+ public String getName();
+
+
+ /**
+ * Returns an input stream for reading the content of this data entry.
+ */
+ public InputStream getInputStream() throws IOException;
+
+
+ /**
+ * Closes the previously retrieved InputStream.
+ */
+ public void closeInputStream() throws IOException;
+
+
+ /**
+ * Returns the parent of this data entry, or <code>null</null> if it doesn't
+ * have one.
+ */
+ public DataEntry getParent();
+}
diff --git a/src/proguard/io/DataEntryCopier.java b/src/proguard/io/DataEntryCopier.java
new file mode 100644
index 0000000..23f0e5b
--- /dev/null
+++ b/src/proguard/io/DataEntryCopier.java
@@ -0,0 +1,243 @@
+/* $Id: DataEntryCopier.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import proguard.util.*;
+
+import java.io.*;
+
+
+/**
+ * This DataEntryReader writes the ZIP entries and files that it reads to a
+ * given DataEntryWriter.
+ *
+ * @author Eric Lafortune
+ */
+public class DataEntryCopier implements DataEntryReader
+{
+ private static final int BUFFER_SIZE = 1024;
+
+ private DataEntryWriter dataEntryWriter;
+ private byte[] buffer = new byte[BUFFER_SIZE];
+
+
+
+ public DataEntryCopier(DataEntryWriter dataEntryWriter)
+ {
+ this.dataEntryWriter = dataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryReader.
+
+ public void read(DataEntry dataEntry) throws IOException
+ {
+ try
+ {
+
+ // Get the output entry corresponding to this input entry.
+ OutputStream outputStream = dataEntryWriter.getOutputStream(dataEntry);
+ if (outputStream != null)
+ {
+ InputStream inputStream = dataEntry.getInputStream();
+
+ // Copy the data from the input entry to the output entry.
+ copyData(inputStream, outputStream);
+
+ // Close the data entries.
+ dataEntry.closeInputStream();
+ }
+ }
+ catch (IOException ex)
+ {
+ System.err.println("Warning: can't write resource [" + dataEntry.getName() + "] (" + ex.getMessage() + ")");
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Copies all data that it can read from the given input stream to the
+ * given output stream.
+ */
+ private void copyData(InputStream inputStream,
+ OutputStream outputStream)
+ throws IOException
+ {
+ while (true)
+ {
+ int count = inputStream.read(buffer);
+ if (count < 0)
+ {
+ break;
+ }
+ outputStream.write(buffer, 0, count);
+ }
+
+ outputStream.flush();
+ }
+
+
+ /**
+ * A main method for testing file/jar/war/directory copying.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ String input = args[0];
+ String output = args[1];
+
+ boolean outputIsJar = output.endsWith(".jar");
+ boolean outputIsWar = output.endsWith(".war");
+ boolean outputIsEar = output.endsWith(".ear");
+ boolean outputIsZip = output.endsWith(".zip");
+
+ DataEntryWriter writer = new DirectoryWriter(new File(output),
+ outputIsJar ||
+ outputIsWar ||
+ outputIsEar ||
+ outputIsZip);
+
+ if (!outputIsJar)
+ {
+ // Zip up any zips, if necessary.
+ DataEntryWriter zipWriter = new JarWriter(writer);
+ if (outputIsZip)
+ {
+ // Always zip.
+ writer = zipWriter;
+ }
+ else
+ {
+ // Only zip up zips.
+ writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
+ new DataEntryNameFilter(
+ new ExtensionMatcher(".zip"))),
+ zipWriter,
+ writer);
+ }
+
+ // Zip up any wars, if necessary.
+ DataEntryWriter warWriter = new JarWriter(writer);
+ if (outputIsWar)
+ {
+ // Always zip.
+ writer = warWriter;
+ }
+ else
+ {
+ // Only zip up wars.
+ writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
+ new DataEntryNameFilter(
+ new ExtensionMatcher(".war"))),
+ warWriter,
+ writer);
+ }
+ }
+
+ // Zip up any jars, if necessary.
+ DataEntryWriter jarWriter = new JarWriter(writer);
+ if (outputIsJar)
+ {
+ // Always zip.
+ writer = jarWriter;
+ }
+ else
+ {
+ // Only zip up jars.
+ writer = new FilteredDataEntryWriter(new DataEntryParentFilter(
+ new DataEntryNameFilter(
+ new ExtensionMatcher(".jar"))),
+ jarWriter,
+ writer);
+ }
+
+
+ // Create the copying DataEntryReader.
+ DataEntryReader reader = new DataEntryCopier(writer);
+
+
+ boolean inputIsJar = input.endsWith(".jar");
+ boolean inputIsWar = input.endsWith(".war");
+ boolean inputIsZip = input.endsWith(".zip");
+
+ // Unzip any jars, if necessary.
+ DataEntryReader jarReader = new JarReader(reader);
+ if (inputIsJar)
+ {
+ // Always unzip.
+ reader = jarReader;
+ }
+ else
+ {
+ // Only unzip jar entries.
+ reader = new FilteredDataEntryReader(new DataEntryNameFilter(
+ new ExtensionMatcher(".jar")),
+ jarReader,
+ reader);
+
+ // Unzip any wars, if necessary.
+ DataEntryReader warReader = new JarReader(reader);
+ if (inputIsWar)
+ {
+ // Always unzip.
+ reader = warReader;
+ }
+ else
+ {
+ // Only unzip war entries.
+ reader = new FilteredDataEntryReader(new DataEntryNameFilter(
+ new ExtensionMatcher(".war")),
+ warReader,
+ reader);
+ }
+
+ // Unzip any zips, if necessary.
+ DataEntryReader zipReader = new JarReader(reader);
+ if (inputIsZip)
+ {
+ // Always unzip.
+ reader = zipReader;
+ }
+ else
+ {
+ // Only unzip zip entries.
+ reader = new FilteredDataEntryReader(new DataEntryNameFilter(
+ new ExtensionMatcher(".zip")),
+ zipReader,
+ reader);
+ }
+ }
+
+ DirectoryPump directoryReader = new DirectoryPump(new File(input));
+
+ directoryReader.pumpDataEntries(reader);
+
+ writer.close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/io/DataEntryFilter.java b/src/proguard/io/DataEntryFilter.java
new file mode 100644
index 0000000..e2110e4
--- /dev/null
+++ b/src/proguard/io/DataEntryFilter.java
@@ -0,0 +1,38 @@
+/* $Id: DataEntryFilter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+
+/**
+ * This interface provides a method to filter data entries.
+ *
+ * @author Eric Lafortune
+ */
+public interface DataEntryFilter
+{
+ /**
+ * Checks whether the filter accepts the given data entry.
+ * @param dataEntry the data entry to filter.
+ * @return a boolean indicating whether the filter accepts the given data
+ * entry.
+ */
+ public boolean accepts(DataEntry dataEntry);
+}
diff --git a/src/proguard/io/DataEntryNameFilter.java b/src/proguard/io/DataEntryNameFilter.java
new file mode 100644
index 0000000..fd25b46
--- /dev/null
+++ b/src/proguard/io/DataEntryNameFilter.java
@@ -0,0 +1,54 @@
+/* $Id: DataEntryNameFilter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import proguard.util.StringMatcher;
+
+/**
+ * This DataEntryFilter filters data entries based on whether their names match
+ * a given StringMatcher.
+ *
+ * @author Eric Lafortune
+ */
+public class DataEntryNameFilter
+implements DataEntryFilter
+{
+ private StringMatcher stringMatcher;
+
+
+ /**
+ * Creates a new DataEntryNameFilter.
+ * @param stringMatcher the string matcher that will be applied to the names
+ * of the filtered data entries.
+ */
+ public DataEntryNameFilter(StringMatcher stringMatcher)
+ {
+ this.stringMatcher = stringMatcher;
+ }
+
+
+ // Implementations for DataEntryFilter.
+
+ public boolean accepts(DataEntry dataEntry)
+ {
+ return dataEntry != null && stringMatcher.matches(dataEntry.getName());
+ }
+}
diff --git a/src/proguard/io/DataEntryParentFilter.java b/src/proguard/io/DataEntryParentFilter.java
new file mode 100644
index 0000000..8f2bff6
--- /dev/null
+++ b/src/proguard/io/DataEntryParentFilter.java
@@ -0,0 +1,51 @@
+/* $Id: DataEntryParentFilter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+/**
+ * This DataEntryFilter delegates filtering to a DataEntryFilter for its parent.
+ *
+ * @author Eric Lafortune
+ */
+public class DataEntryParentFilter
+implements DataEntryFilter
+{
+ private DataEntryFilter dataEntryFilter;
+
+
+ /**
+ * Creates a new ParentFilter.
+ * @param dataEntryFilter the filter that will be applied to the data
+ * entry's parent.
+ */
+ public DataEntryParentFilter(DataEntryFilter dataEntryFilter)
+ {
+ this.dataEntryFilter = dataEntryFilter;
+ }
+
+
+ // Implementations for DataEntryFilter.
+
+ public boolean accepts(DataEntry dataEntry)
+ {
+ return dataEntry != null && dataEntryFilter.accepts(dataEntry.getParent());
+ }
+}
diff --git a/src/proguard/io/DataEntryPump.java b/src/proguard/io/DataEntryPump.java
new file mode 100644
index 0000000..2b68072
--- /dev/null
+++ b/src/proguard/io/DataEntryPump.java
@@ -0,0 +1,43 @@
+/* $Id: DataEntryPump.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+
+
+/**
+ * This interface provides a method to pump data entries. The implementation
+ * determines the source and the type of the data entries. Typical examples
+ * are zip entries coming from a zip file of file entries coming from a
+ * directory structure. The reader can for instance collect the class files,
+ * or copy the resource files that are presented.
+ *
+ * @author Eric Lafortune
+ */
+public interface DataEntryPump
+{
+ /**
+ * Applies the given DataEntryReader to all data entries that the
+ * implementation can provide.
+ */
+ public void pumpDataEntries(DataEntryReader dataEntryReader)
+ throws IOException;
+}
diff --git a/src/proguard/io/DataEntryReader.java b/src/proguard/io/DataEntryReader.java
new file mode 100644
index 0000000..7a1a7d3
--- /dev/null
+++ b/src/proguard/io/DataEntryReader.java
@@ -0,0 +1,39 @@
+/* $Id: DataEntryReader.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+import java.util.zip.*;
+
+
+/**
+ * This interface provides methods for reading data entries. The implementation
+ * determines what to do with the read data, if anything.
+ *
+ * @author Eric Lafortune
+ */
+public interface DataEntryReader
+{
+ /**
+ * Reads the given data entry.
+ */
+ public void read(DataEntry dataEntry) throws IOException;
+}
diff --git a/src/proguard/io/DataEntryWriter.java b/src/proguard/io/DataEntryWriter.java
new file mode 100644
index 0000000..1677cc3
--- /dev/null
+++ b/src/proguard/io/DataEntryWriter.java
@@ -0,0 +1,65 @@
+/* $Id: DataEntryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+
+
+/**
+ * This interface provides methods for writing data entries, such as ZIP entries
+ * or files. The implementation determines to which type of data entry the
+ * data will be written.
+ *
+ * @author Eric Lafortune
+ */
+public interface DataEntryWriter
+{
+ /**
+ * Returns an output stream for writing data. The caller must not close
+ * the output stream; closing the output stream is the responsibility of
+ * the implementation of this interface.
+ * @param dataEntry the data entry for which the output stream is to be created.
+ * @return the output stream. The stream may be <code>null</code> to indicate
+ * that the data entry should not be written.
+ */
+ public OutputStream getOutputStream(DataEntry dataEntry) throws IOException;
+
+
+ /**
+ * Returns an output stream for writing data. The caller must not close
+ * the output stream; closing the output stream is the responsibility of
+ * the implementation of this interface.
+ * @param dataEntry the data entry for which the output stream is to be created.
+ * @param finisher the optional finisher that will be called before this
+ * class closes the output stream (at some later point in
+ * time) that will be returned (now).
+ * @return the output stream. The stream may be <code>null</code> to indicate
+ * that the data entry should not be written.
+ */
+ public OutputStream getOutputStream(DataEntry dataEntry,
+ Finisher finisher) throws IOException;
+
+
+ /**
+ * Finishes writing all data entries.
+ */
+ public void close() throws IOException;
+}
diff --git a/src/proguard/io/DirectoryPump.java b/src/proguard/io/DirectoryPump.java
new file mode 100644
index 0000000..1598338
--- /dev/null
+++ b/src/proguard/io/DirectoryPump.java
@@ -0,0 +1,74 @@
+/* $Id: DirectoryPump.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+
+
+/**
+ * This class can read a given file or directory, recursively, applying a given
+ * DataEntryReader to all files it comes across.
+ *
+ * @author Eric Lafortune
+ */
+public class DirectoryPump implements DataEntryPump
+{
+ private File directory;
+
+
+ public DirectoryPump(File directory)
+ {
+ this.directory = directory;
+ }
+
+
+ // Implementations for DataEntryPump.
+
+ public void pumpDataEntries(DataEntryReader dataEntryReader)
+ throws IOException
+ {
+ readFiles(directory, dataEntryReader);
+ }
+
+
+ /**
+ * Reads the given subdirectory recursively, applying the given DataEntryReader
+ * to all files that are encountered.
+ */
+ private void readFiles(File file, DataEntryReader dataEntryReader)
+ throws IOException
+ {
+ if (file.isDirectory())
+ {
+ // Recurse into the subdirectory.
+ File[] files = file.listFiles();
+
+ for (int index = 0; index < files.length; index++)
+ {
+ readFiles(files[index], dataEntryReader);
+ }
+ }
+ else
+ {
+ dataEntryReader.read(new FileDataEntry(directory, file));
+ }
+ }
+}
diff --git a/src/proguard/io/DirectoryWriter.java b/src/proguard/io/DirectoryWriter.java
new file mode 100644
index 0000000..536e4ed
--- /dev/null
+++ b/src/proguard/io/DirectoryWriter.java
@@ -0,0 +1,145 @@
+/* $Id: DirectoryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import proguard.classfile.*;
+
+import java.io.*;
+
+
+/**
+ * This DataEntryWriter writes sends data entries to individual files in a
+ * given directory.
+ *
+ * @author Eric Lafortune
+ */
+public class DirectoryWriter implements DataEntryWriter
+{
+ private File baseFile;
+ private boolean isFile;
+
+ private File currentFile;
+ private OutputStream currentOutputStream;
+ private Finisher currentFinisher;
+
+
+ /**
+ * Creates a new DirectoryWriter.
+ * @param baseFile the base directory to which all files will be written.
+ */
+ public DirectoryWriter(File baseFile,
+ boolean isFile)
+ {
+ this.baseFile = baseFile;
+ this.isFile = isFile;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
+ {
+ return getOutputStream(dataEntry, null);
+ }
+
+
+ public OutputStream getOutputStream(DataEntry dataEntry,
+ Finisher finisher) throws IOException
+ {
+ // Should we close the current file?
+ if (!isFile &&
+ currentFile != null &&
+ !currentFile.equals(getFile(dataEntry)))
+ {
+ closeEntry();
+ }
+
+ // Do we need a new stream?
+ if (currentOutputStream == null)
+ {
+ File file = getFile(dataEntry);
+
+ // Make sure the parent directories exist.
+ File parentDirectory = file.getParentFile();
+ if (parentDirectory != null &&
+ !parentDirectory.exists() &&
+ !parentDirectory.mkdirs())
+ {
+ throw new IOException("Can't create directory [" + parentDirectory.getPath() + "]");
+ }
+
+ // Open a new output stream for writing to the file.
+ currentOutputStream =
+ new BufferedOutputStream(
+ new FileOutputStream(file));
+
+ currentFinisher = finisher;
+ currentFile = file;
+ }
+
+ return currentOutputStream;
+ }
+
+
+ public void close() throws IOException
+ {
+ // Close the file stream, if any.
+ closeEntry();
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the file for the given data entry.
+ */
+ private File getFile(DataEntry dataEntry)
+ {
+ // Use the specified file, or construct a new file.
+ return isFile ?
+ baseFile :
+ new File(baseFile,
+ dataEntry.getName().replace(ClassConstants.INTERNAL_PACKAGE_SEPARATOR,
+ File.separatorChar));
+ }
+
+
+ /**
+ * Closes the previous file, if any.
+ */
+ private void closeEntry() throws IOException
+ {
+ // Close the file stream, if any.
+ if (currentOutputStream != null)
+ {
+ // Let any finisher finish up first.
+ if (currentFinisher != null)
+ {
+ currentFinisher.finish();
+ currentFinisher = null;
+ }
+
+ currentOutputStream.close();
+ currentOutputStream = null;
+ currentFile = null;
+ }
+ }
+}
diff --git a/src/proguard/io/FileDataEntry.java b/src/proguard/io/FileDataEntry.java
new file mode 100644
index 0000000..d5b794e
--- /dev/null
+++ b/src/proguard/io/FileDataEntry.java
@@ -0,0 +1,92 @@
+/* $Id: FileDataEntry.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import proguard.classfile.ClassConstants;
+
+import java.io.*;
+
+/**
+ * This <code>DataEntry</code> represents a file.
+ *
+ * @author Eric Lafortune
+ */
+public class FileDataEntry implements DataEntry
+{
+ private File directory;
+ private File file;
+ private InputStream inputStream;
+
+
+ public FileDataEntry(File directory,
+ File file)
+ {
+ this.directory = directory;
+ this.file = file;
+ }
+
+
+ // Implementations for DataEntry.
+
+ public String getName()
+ {
+ // Chop the directory name from the file name and get the right separators.
+ return file.equals(directory) ?
+ file.getName() :
+ file.getPath()
+ .substring(directory.getPath().length() + File.separator.length())
+ .replace(File.separatorChar, ClassConstants.INTERNAL_PACKAGE_SEPARATOR);
+ }
+
+
+ // Implementations for InputEntry.
+
+ public InputStream getInputStream() throws IOException
+ {
+ if (inputStream == null)
+ {
+ inputStream = new BufferedInputStream(new FileInputStream(file));
+ }
+
+ return inputStream;
+ }
+
+
+ public void closeInputStream() throws IOException
+ {
+ inputStream.close();
+ inputStream = null;
+ }
+
+
+ public DataEntry getParent()
+ {
+ return null;
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName();
+ }
+}
diff --git a/src/proguard/io/FilteredDataEntryReader.java b/src/proguard/io/FilteredDataEntryReader.java
new file mode 100644
index 0000000..81cf923
--- /dev/null
+++ b/src/proguard/io/FilteredDataEntryReader.java
@@ -0,0 +1,96 @@
+/* $Id: FilteredDataEntryReader.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+
+
+/**
+ * This DataEntryReader delegates to one of two other DataEntryReader instances,
+ * depending on whether the data entry passes through a given data entry filter
+ * or not.
+ *
+ * @author Eric Lafortune
+ */
+public class FilteredDataEntryReader implements DataEntryReader
+{
+ private DataEntryFilter dataEntryFilter;
+ private DataEntryReader acceptedDataEntryReader;
+ private DataEntryReader rejectedDataEntryReader;
+
+
+ /**
+ * Creates a new FilteredDataEntryReader with only a reader for accepted
+ * data entries.
+ * @param dataEntryFilter the data entry filter.
+ * @param acceptedDataEntryReader the DataEntryReader to which the reading
+ * will be delegated if the filter accepts
+ * the data entry. May be <code>null</code>.
+ */
+ public FilteredDataEntryReader(DataEntryFilter dataEntryFilter,
+ DataEntryReader acceptedDataEntryReader)
+ {
+ this(dataEntryFilter, acceptedDataEntryReader, null);
+ }
+
+
+ /**
+ * Creates a new FilteredDataEntryReader.
+ * @param dataEntryFilter the data entry filter.
+ * @param acceptedDataEntryReader the DataEntryReader to which the reading
+ * will be delegated if the filter accepts
+ * the data entry. May be <code>null</code>.
+ * @param rejectedDataEntryReader the DataEntryReader to which the reading
+ * will be delegated if the filter does not
+ * accept the data entry. May be
+ * <code>null</code>.
+ */
+ public FilteredDataEntryReader(DataEntryFilter dataEntryFilter,
+ DataEntryReader acceptedDataEntryReader,
+ DataEntryReader rejectedDataEntryReader)
+ {
+ this.dataEntryFilter = dataEntryFilter;
+ this.acceptedDataEntryReader = acceptedDataEntryReader;
+ this.rejectedDataEntryReader = rejectedDataEntryReader;
+ }
+
+
+ // Implementations for DataEntryReader.
+
+ public void read(DataEntry dataEntry)
+ throws IOException
+ {
+ if (dataEntryFilter.accepts(dataEntry))
+ {
+ if (acceptedDataEntryReader != null)
+ {
+ acceptedDataEntryReader.read(dataEntry);
+ }
+ }
+ else
+ {
+ if (rejectedDataEntryReader != null)
+ {
+ rejectedDataEntryReader.read(dataEntry);
+ }
+ }
+ }
+}
diff --git a/src/proguard/io/FilteredDataEntryWriter.java b/src/proguard/io/FilteredDataEntryWriter.java
new file mode 100644
index 0000000..ffd0dc3
--- /dev/null
+++ b/src/proguard/io/FilteredDataEntryWriter.java
@@ -0,0 +1,112 @@
+/* $Id: FilteredDataEntryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+
+/**
+ * This DataEntryWriter delegates to one of two other DataEntryWriter instances,
+ * depending on whether the data entry passes through a given data entry filter
+ * or not.
+ *
+ * @author Eric Lafortune
+ */
+public class FilteredDataEntryWriter implements DataEntryWriter
+{
+ private DataEntryFilter dataEntryFilter;
+ private DataEntryWriter acceptedDataEntryWriter;
+ private DataEntryWriter rejectedDataEntryWriter;
+
+
+ /**
+ * Creates a new FilteredDataEntryWriter with only a writer for accepted
+ * data entries.
+ * @param dataEntryFilter the data entry filter.
+ * @param acceptedDataEntryWriter the DataEntryWriter to which the writing
+ * will be delegated if the filter accepts
+ * the data entry. May be <code>null</code>.
+ */
+ public FilteredDataEntryWriter(DataEntryFilter dataEntryFilter,
+ DataEntryWriter acceptedDataEntryWriter)
+ {
+ this(dataEntryFilter, acceptedDataEntryWriter, null);
+ }
+
+
+ /**
+ * Creates a new FilteredDataEntryWriter.
+ * @param dataEntryFilter the data entry filter.
+ * @param acceptedDataEntryWriter the DataEntryWriter to which the writing
+ * will be delegated if the filter accepts
+ * the data entry. May be <code>null</code>.
+ * @param rejectedDataEntryWriter the DataEntryWriter to which the writing
+ * will be delegated if the filter does not
+ * accept the data entry. May be
+ * <code>null</code>.
+ */
+ public FilteredDataEntryWriter(DataEntryFilter dataEntryFilter,
+ DataEntryWriter acceptedDataEntryWriter,
+ DataEntryWriter rejectedDataEntryWriter)
+ {
+ this.dataEntryFilter = dataEntryFilter;
+ this.acceptedDataEntryWriter = acceptedDataEntryWriter;
+ this.rejectedDataEntryWriter = rejectedDataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
+ {
+ return getOutputStream(dataEntry, null);
+ }
+
+
+ public OutputStream getOutputStream(DataEntry dataEntry,
+ Finisher finisher) throws IOException
+ {
+ // Get the right data entry writer.
+ DataEntryWriter dataEntryWriter = dataEntryFilter.accepts(dataEntry) ?
+ acceptedDataEntryWriter :
+ rejectedDataEntryWriter;
+
+ // Delegate to it, if it's not null.
+ return dataEntryWriter != null ?
+ dataEntryWriter.getOutputStream(dataEntry, finisher) :
+ null;
+ }
+
+
+ public void close() throws IOException
+ {
+ if (acceptedDataEntryWriter != null)
+ {
+ acceptedDataEntryWriter.close();
+ acceptedDataEntryWriter = null;
+ }
+
+ if (rejectedDataEntryWriter != null)
+ {
+ rejectedDataEntryWriter.close();
+ rejectedDataEntryWriter = null;
+ }
+ }
+}
diff --git a/src/proguard/io/Finisher.java b/src/proguard/io/Finisher.java
new file mode 100644
index 0000000..18b2413
--- /dev/null
+++ b/src/proguard/io/Finisher.java
@@ -0,0 +1,37 @@
+/* $Id: Finisher.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+
+/**
+ * This interface specifies a listener that is called to finish an output stream
+ * before it is closed.
+ *
+ * @author Eric Lafortune
+ */
+public interface Finisher
+{
+ /**
+ * Finishes an output stream right before it is closed.
+ */
+ public void finish() throws IOException;
+}
diff --git a/src/proguard/io/JarReader.java b/src/proguard/io/JarReader.java
new file mode 100644
index 0000000..3210122
--- /dev/null
+++ b/src/proguard/io/JarReader.java
@@ -0,0 +1,78 @@
+/* $Id: JarReader.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+import java.util.zip.*;
+
+/**
+ * This DataEntryReader lets a given DataEntryReader read all data entries of
+ * the read jar/war/zip data entries.
+ *
+ * @author Eric Lafortune
+ */
+public class JarReader implements DataEntryReader
+{
+ DataEntryReader dataEntryReader;
+
+
+ /**
+ * Creates a new JarReader.
+ */
+ public JarReader(DataEntryReader dataEntryReader)
+ {
+ this.dataEntryReader = dataEntryReader;
+ }
+
+
+ // Implementation for DataEntryReader.
+
+ public void read(DataEntry dataEntry) throws IOException
+ {
+ ZipInputStream zipInputStream = new ZipInputStream(dataEntry.getInputStream());
+
+ try
+ {
+ // Get all entries from the input jar.
+ while (true)
+ {
+ // Can we get another entry?
+ ZipEntry zipEntry = zipInputStream.getNextEntry();
+ if (zipEntry == null)
+ {
+ break;
+ }
+
+ if (!zipEntry.isDirectory())
+ {
+ // Delegate the actual reading to the data entry reader.
+ dataEntryReader.read(new ZipDataEntry(dataEntry,
+ zipEntry,
+ zipInputStream));
+ }
+ }
+ }
+ finally
+ {
+ dataEntry.closeInputStream();
+ }
+ }
+}
diff --git a/src/proguard/io/JarWriter.java b/src/proguard/io/JarWriter.java
new file mode 100644
index 0000000..9e62949
--- /dev/null
+++ b/src/proguard/io/JarWriter.java
@@ -0,0 +1,183 @@
+/* $Id: JarWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+import java.util.jar.*;
+import java.util.*;
+import java.util.zip.*;
+
+
+/**
+ * This DataEntryWriter sends data entries to a given jar/zip file.
+ * The manifest and comment properties can optionally be set.
+ *
+ * @author Eric Lafortune
+ */
+public class JarWriter implements DataEntryWriter, Finisher
+{
+ private DataEntryWriter dataEntryWriter;
+ private Manifest manifest;
+ private String comment;
+
+ private OutputStream currentParentOutputStream;
+ private ZipOutputStream currentJarOutputStream;
+ private Finisher currentFinisher;
+ private String currentEntryName;
+
+ // The names of the jar entries that are already in the jar.
+ private Set jarEntryNames = new HashSet();
+
+
+ /**
+ * Creates a new JarWriter without manifest or comment.
+ */
+ public JarWriter(DataEntryWriter dataEntryWriter)
+ {
+ this(dataEntryWriter, null, null);
+ }
+
+
+ /**
+ * Creates a new JarWriter.
+ */
+ public JarWriter(DataEntryWriter dataEntryWriter,
+ Manifest manifest,
+ String comment)
+ {
+ this.dataEntryWriter = dataEntryWriter;
+ this.manifest = manifest;
+ this.comment = comment;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
+ {
+ return getOutputStream(dataEntry, null);
+ }
+
+
+ public OutputStream getOutputStream(DataEntry dataEntry,
+ Finisher finisher) throws IOException
+ {
+ // Get the parent stream, new or exisiting.
+ // This may finish our own jar output stream.
+ OutputStream parentOutputStream =
+ dataEntryWriter.getOutputStream(dataEntry.getParent(), this);
+
+ // Did we get a stream?
+ if (parentOutputStream == null)
+ {
+ return null;
+ }
+
+ // Do we need a new stream?
+ if (currentParentOutputStream == null)
+ {
+ currentParentOutputStream = parentOutputStream;
+
+ // Create a new jar stream, with a manifest, if set.
+ currentJarOutputStream = manifest != null ?
+ new JarOutputStream(parentOutputStream, manifest) :
+ new ZipOutputStream(parentOutputStream);
+
+ // Add a comment, if set.
+ if (comment != null)
+ {
+ currentJarOutputStream.setComment(comment);
+ }
+ }
+
+ // Get the entry name.
+ String name = dataEntry.getName();
+
+ // Do we need a new entry?
+ if (!name.equals(currentEntryName))
+ {
+ // Close the previous ZIP entry, if any.
+ closeEntry();
+
+ // We have to check if the name is already used, because ZipOutputStream
+ // doesn't handle this case properly (it throws an exception which can
+ // be caught, but the ZipDataEntry is remembered anyway).
+ if (!jarEntryNames.add(name))
+ {
+ throw new IOException("Duplicate zip entry ["+dataEntry+"]");
+ }
+
+ // Create a new entry.
+ currentJarOutputStream.putNextEntry(new ZipEntry(name));
+
+ currentFinisher = finisher;
+ currentEntryName = name;
+ }
+
+ return currentJarOutputStream;
+ }
+
+
+ public void finish() throws IOException
+ {
+ // Finish the entire ZIP stream, if any.
+ if (currentJarOutputStream != null)
+ {
+ // Close the previous ZIP entry, if any.
+ closeEntry();
+
+ // Finish the entire ZIP stream.
+ currentJarOutputStream.finish();
+ currentJarOutputStream = null;
+ currentParentOutputStream = null;
+ jarEntryNames.clear();
+ }
+ }
+
+
+ public void close() throws IOException
+ {
+ // Close the parent stream.
+ dataEntryWriter.close();
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Closes the previous ZIP entry, if any.
+ */
+ private void closeEntry() throws IOException
+ {
+ if (currentEntryName != null)
+ {
+ // Let any finisher finish up first.
+ if (currentFinisher != null)
+ {
+ currentFinisher.finish();
+ currentFinisher = null;
+ }
+
+ currentJarOutputStream.closeEntry();
+ currentEntryName = null;
+ }
+ }
+}
diff --git a/src/proguard/io/ParentDataEntryWriter.java b/src/proguard/io/ParentDataEntryWriter.java
new file mode 100644
index 0000000..097965b
--- /dev/null
+++ b/src/proguard/io/ParentDataEntryWriter.java
@@ -0,0 +1,67 @@
+/* $Id: ParentDataEntryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+
+/**
+ * This DataEntryWriter lets another DataEntryWriter write the parent data
+ * entries.
+ *
+ * @author Eric Lafortune
+ */
+public class ParentDataEntryWriter implements DataEntryWriter
+{
+ private DataEntryWriter dataEntryWriter;
+
+
+ /**
+ * Creates a new ParentDataEntryWriter.
+ * @param dataEntryWriter the DataEntryWriter to which the writing will be
+ * delegated, passing the data entries' parents.
+ */
+ public ParentDataEntryWriter(DataEntryWriter dataEntryWriter)
+ {
+ this.dataEntryWriter = dataEntryWriter;
+ }
+
+
+ // Implementations for DataEntryWriter.
+
+ public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
+ {
+ return getOutputStream(dataEntry, null);
+ }
+
+
+ public OutputStream getOutputStream(DataEntry dataEntry,
+ Finisher finisher) throws IOException
+ {
+ return dataEntryWriter.getOutputStream(dataEntry.getParent(),
+ finisher);
+ }
+
+
+ public void close() throws IOException
+ {
+ dataEntryWriter.close();
+ }
+}
diff --git a/src/proguard/io/RenamedDataEntry.java b/src/proguard/io/RenamedDataEntry.java
new file mode 100644
index 0000000..79be047
--- /dev/null
+++ b/src/proguard/io/RenamedDataEntry.java
@@ -0,0 +1,77 @@
+/* $Id: RenamedDataEntry.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+
+/**
+ * This DataEntry wraps another data entry, returning a different name instead
+ * of the wrapped data entry's name.
+ *
+ * @author Eric Lafortune
+ */
+public class RenamedDataEntry implements DataEntry
+{
+ private DataEntry dataEntry;
+ private String name;
+
+
+ public RenamedDataEntry(DataEntry dataEntry,
+ String name)
+ {
+ this.dataEntry = dataEntry;
+ this.name = name;
+ }
+
+
+ // Implementations for DataEntry.
+
+ public String getName()
+ {
+ return name;
+ }
+
+
+ public InputStream getInputStream() throws IOException
+ {
+ return dataEntry.getInputStream();
+ }
+
+
+ public void closeInputStream() throws IOException
+ {
+ dataEntry.closeInputStream();
+ }
+
+
+ public DataEntry getParent()
+ {
+ return dataEntry.getParent();
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return name + " == " + dataEntry;
+ }
+}
diff --git a/src/proguard/io/ZipDataEntry.java b/src/proguard/io/ZipDataEntry.java
new file mode 100644
index 0000000..ff7a3bc
--- /dev/null
+++ b/src/proguard/io/ZipDataEntry.java
@@ -0,0 +1,85 @@
+/* $Id: ZipDataEntry.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.io;
+
+import java.io.*;
+import java.util.zip.*;
+
+import proguard.classfile.ClassConstants;
+
+/**
+ * This <code>DataEntry</code> represents a ZIP entry.
+ *
+ * @author Eric Lafortune
+ */
+public class ZipDataEntry implements DataEntry
+{
+ private DataEntry parent;
+ private ZipEntry zipEntry;
+ private ZipInputStream zipInputStream;
+
+
+ public ZipDataEntry(DataEntry parent,
+ ZipEntry zipEntry,
+ ZipInputStream zipInputStream)
+ {
+ this.parent = parent;
+ this.zipEntry = zipEntry;
+ this.zipInputStream = zipInputStream;
+ }
+
+
+ // Implementations for DataEntry.
+
+ public String getName()
+ {
+ // Chop the directory name from the file name and get the right separators.
+ return zipEntry.getName()
+ .replace(File.separatorChar, ClassConstants.INTERNAL_PACKAGE_SEPARATOR);
+ }
+
+
+ public InputStream getInputStream() throws IOException
+ {
+ return zipInputStream;
+ }
+
+
+ public void closeInputStream() throws IOException
+ {
+ zipInputStream.closeEntry();
+ zipInputStream = null;
+ }
+
+
+ public DataEntry getParent()
+ {
+ return parent;
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return parent.toString() + ':' + getName();
+ }
+}
diff --git a/src/proguard/io/package.html b/src/proguard/io/package.html
new file mode 100644
index 0000000..4ad9f41
--- /dev/null
+++ b/src/proguard/io/package.html
@@ -0,0 +1,4 @@
+<body>
+This package contains classes to read and write files, optionally wrapped in
+jars, wars, ears, zips, directories,...
+</body>
diff --git a/src/proguard/obfuscate/AttributeShrinker.java b/src/proguard/obfuscate/AttributeShrinker.java
new file mode 100644
index 0000000..1fb95ef
--- /dev/null
+++ b/src/proguard/obfuscate/AttributeShrinker.java
@@ -0,0 +1,160 @@
+/* $Id: AttributeShrinker.java,v 1.16 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassFileVisitor removes attributes that are not marked
+ * as being used or required.
+ *
+ * @see AttributeUsageMarker
+ *
+ * @author Eric Lafortune
+ */
+public class AttributeShrinker
+ implements ClassFileVisitor,
+ MemberInfoVisitor,
+ AttrInfoVisitor
+{
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Compact the array for class attributes.
+ programClassFile.u2attributesCount =
+ shrinkArray(programClassFile.attributes,
+ programClassFile.u2attributesCount);
+
+ // Compact the attributes in fields, methods, and class attributes,
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+ programClassFile.attributesAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ // Library class files are left unchanged.
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ // Compact the attributes array.
+ programMemberInfo.u2attributesCount =
+ shrinkArray(programMemberInfo.attributes,
+ programMemberInfo.u2attributesCount);
+
+ // Compact any attributes of the remaining attributes.
+ programMemberInfo.attributesAccept(programClassFile, this);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ // Library class files are left unchanged.
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ // Library class files are left unchanged.
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ // Compact the attributes array.
+ codeAttrInfo.u2attributesCount =
+ shrinkArray(codeAttrInfo.attributes,
+ codeAttrInfo.u2attributesCount);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Removes all VisitorAccepter objects that are not marked as being used
+ * from the given array.
+ * @return the new number of VisitorAccepter objects.
+ */
+ private static int shrinkArray(VisitorAccepter[] array, int length)
+ {
+ int counter = 0;
+
+ // Shift the used objects together.
+ for (int index = 0; index < length; index++)
+ {
+ if (AttributeUsageMarker.isUsed(array[index]))
+ {
+ array[counter++] = array[index];
+ }
+ }
+
+ // Clear the remaining array elements.
+ for (int index = counter; index < length; index++)
+ {
+ array[index] = null;
+ }
+
+ return counter;
+ }
+}
diff --git a/src/proguard/obfuscate/AttributeUsageMarker.java b/src/proguard/obfuscate/AttributeUsageMarker.java
new file mode 100644
index 0000000..4f8ecb0
--- /dev/null
+++ b/src/proguard/obfuscate/AttributeUsageMarker.java
@@ -0,0 +1,401 @@
+/* $Id: AttributeUsageMarker.java,v 1.23 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.visitor.*;
+import proguard.util.*;
+
+import java.util.*;
+
+
+/**
+ * This ClassFileVisitor marks all attributes that should be kept in the classes
+ * it visits.
+ *
+ * @see AttributeShrinker
+ *
+ * @author Eric Lafortune
+ */
+public class AttributeUsageMarker
+ implements ClassFileVisitor,
+ MemberInfoVisitor,
+ AttrInfoVisitor,
+ InnerClassesInfoVisitor
+{
+ // A visitor info flag to indicate the attribute is being used.
+ private static final Object USED = new Object();
+
+
+ // Flags to specify whether optional attributes should be kept anyway.
+ private boolean keepAllAttributes;
+ private boolean keepAllUnknownAttributes;
+ private boolean keepAllKnownAttributes;
+ private StringMatcher keepAttributes;
+
+ private boolean keepInnerClassNameAttribute;
+ private boolean keepEnclosingMethodAttribute;
+ private boolean keepLineNumberTableAttribute;
+ private boolean keepLocalVariableTableAttribute;
+ private boolean keepLocalVariableTypeTableAttribute;
+ private boolean keepSourceFileAttribute;
+ private boolean keepSourceDirAttribute;
+ private boolean keepDeprecatedAttribute;
+ private boolean keepSyntheticAttribute;
+ private boolean keepSignatureAttribute;
+ private boolean keepRuntimeVisibleAnnotationsAttribute;
+ private boolean keepRuntimeInvisibleAnnotationsAttribute;
+ private boolean keepRuntimeVisibleParameterAnnotationsAttribute;
+ private boolean keepRuntimeInvisibleParameterAnnotationsAttribute;
+ private boolean keepAnnotationDefaultAttribute;
+
+
+ /**
+ * Specifies to keep all optional attributes.
+ */
+ public void setKeepAllAttributes()
+ {
+ keepAllAttributes = true;
+ }
+
+ /**
+ * Specifies to keep all unknown attributes.
+ */
+ public void setKeepAllUnknownAttributes()
+ {
+ keepAllUnknownAttributes = true;
+ }
+
+ /**
+ * Specifies to keep all known attributes.
+ */
+ public void setKeepAllKnownAttributes()
+ {
+ keepAllKnownAttributes = true;
+ }
+
+
+ /**
+ * Specifies to keep optional attributes with the given names. The attribute
+ * names may contain "*" or "?" wildcards, and they may be preceded by the
+ * "!" negator.
+ */
+ public void setKeepAttributes(List attributeNames)
+ {
+ keepAttributes = new BasicListMatcher(attributeNames);
+
+ // Precompute whether the list of attribute names matches the supported
+ // attributes.
+ keepInnerClassNameAttribute = keepAttributes.matches(ClassConstants.ATTR_InnerClasses);
+ keepEnclosingMethodAttribute = keepAttributes.matches(ClassConstants.ATTR_EnclosingMethod);
+ keepLineNumberTableAttribute = keepAttributes.matches(ClassConstants.ATTR_LineNumberTable);
+ keepLocalVariableTableAttribute = keepAttributes.matches(ClassConstants.ATTR_LocalVariableTable);
+ keepLocalVariableTypeTableAttribute = keepAttributes.matches(ClassConstants.ATTR_LocalVariableTypeTable);
+ keepSourceFileAttribute = keepAttributes.matches(ClassConstants.ATTR_SourceFile);
+ keepSourceDirAttribute = keepAttributes.matches(ClassConstants.ATTR_SourceDir);
+ keepDeprecatedAttribute = keepAttributes.matches(ClassConstants.ATTR_Deprecated);
+ keepSyntheticAttribute = keepAttributes.matches(ClassConstants.ATTR_Synthetic);
+ keepSignatureAttribute = keepAttributes.matches(ClassConstants.ATTR_Signature);
+ keepRuntimeVisibleAnnotationsAttribute = keepAttributes.matches(ClassConstants.ATTR_RuntimeVisibleAnnotations);
+ keepRuntimeInvisibleAnnotationsAttribute = keepAttributes.matches(ClassConstants.ATTR_RuntimeInvisibleAnnotations);
+ keepRuntimeVisibleParameterAnnotationsAttribute = keepAttributes.matches(ClassConstants.ATTR_RuntimeVisibleParameterAnnotations);
+ keepRuntimeInvisibleParameterAnnotationsAttribute = keepAttributes.matches(ClassConstants.ATTR_RuntimeInvisibleParameterAnnotations);
+ keepAnnotationDefaultAttribute = keepAttributes.matches(ClassConstants.ATTR_AnnotationDefault);
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Mark the class member attributes that should be kept.
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+
+ // Mark the class attributes that should be kept.
+ programClassFile.attributesAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ // Mark the class member attributes that should be kept.
+ programMemberInfo.attributesAccept(programClassFile, this);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllUnknownAttributes ||
+ (keepAttributes != null &&
+ keepAttributes.matches(unknownAttrInfo.getAttributeName(classFile))))
+ {
+ markAsUsed(unknownAttrInfo);
+ }
+ }
+
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ markAsUsed(innerClassesAttrInfo);
+
+ if (!keepAllAttributes &&
+ !keepAllKnownAttributes &&
+ !keepInnerClassNameAttribute)
+ {
+ // Clear references to the original inner class names.
+ innerClassesAttrInfo.innerClassEntriesAccept(classFile, this);
+ }
+ }
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepEnclosingMethodAttribute)
+ {
+ markAsUsed(enclosingMethodAttrInfo);
+ }
+ }
+
+
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo)
+ {
+ markAsUsed(constantValueAttrInfo);
+ }
+
+
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo)
+ {
+ markAsUsed(exceptionsAttrInfo);
+ }
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ markAsUsed(codeAttrInfo);
+
+ // Mark the code attributes that should be kept.
+ codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+ }
+
+
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepLineNumberTableAttribute)
+ {
+ markAsUsed(lineNumberTableAttrInfo);
+ }
+ }
+
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepLocalVariableTableAttribute)
+ {
+ markAsUsed(localVariableTableAttrInfo);
+ }
+ }
+
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepLocalVariableTypeTableAttribute)
+ {
+ markAsUsed(localVariableTypeTableAttrInfo);
+ }
+ }
+
+
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepSourceFileAttribute)
+ {
+ markAsUsed(sourceFileAttrInfo);
+ }
+ }
+
+
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepSourceDirAttribute)
+ {
+ markAsUsed(sourceDirAttrInfo);
+ }
+ }
+
+
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepDeprecatedAttribute)
+ {
+ markAsUsed(deprecatedAttrInfo);
+ }
+ }
+
+
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepSyntheticAttribute)
+ {
+ markAsUsed(syntheticAttrInfo);
+ }
+ }
+
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepSignatureAttribute)
+ {
+ markAsUsed(signatureAttrInfo);
+ }
+ }
+
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepRuntimeVisibleAnnotationsAttribute)
+ {
+ markAsUsed(runtimeVisibleAnnotationsAttrInfo);
+ }
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepRuntimeInvisibleAnnotationsAttribute)
+ {
+ markAsUsed(runtimeInvisibleAnnotationsAttrInfo);
+ }
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepRuntimeVisibleParameterAnnotationsAttribute)
+ {
+ markAsUsed(runtimeVisibleParameterAnnotationsAttrInfo);
+ }
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepRuntimeInvisibleParameterAnnotationsAttribute)
+ {
+ markAsUsed(runtimeInvisibleParameterAnnotationsAttrInfo);
+ }
+ }
+
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ if (keepAllAttributes ||
+ keepAllKnownAttributes ||
+ keepAnnotationDefaultAttribute)
+ {
+ markAsUsed(annotationDefaultAttrInfo);
+ }
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(ClassFile classFile, InnerClassesInfo innerClassesInfo)
+ {
+ // Clear the reference to the original inner class name, as used in
+ // the source code.
+ innerClassesInfo.u2innerNameIndex = 0;
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given VisitorAccepter as being used (or useful).
+ * In this context, the VisitorAccepter will be an AttrInfo object.
+ */
+ private static void markAsUsed(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(USED);
+ }
+
+
+ /**
+ * Returns whether the given VisitorAccepter has been marked as being used.
+ * In this context, the VisitorAccepter will be an AttrInfo object.
+ */
+ static boolean isUsed(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == USED;
+ }
+}
diff --git a/src/proguard/obfuscate/ClassFileObfuscator.java b/src/proguard/obfuscate/ClassFileObfuscator.java
new file mode 100644
index 0000000..98f0275
--- /dev/null
+++ b/src/proguard/obfuscate/ClassFileObfuscator.java
@@ -0,0 +1,179 @@
+/* $Id: ClassFileObfuscator.java,v 1.23 2004/11/01 21:17:51 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+import java.util.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> comes up with obfuscated names for the
+ * class files it visits, and for their class members. The actual renaming is
+ * done afterward.
+ *
+ * @see ClassFileRenamer
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileObfuscator
+ implements ClassFileVisitor
+{
+ private boolean useMixedCaseClassNames;
+ private String defaultPackageName;
+
+ // Map: [package name - class name factory]
+ private final Map packageMap = new HashMap();
+ private final NameFactory defaultPackageClassNameFactory;
+ private final Set namesToAvoid = new HashSet();
+
+
+ /**
+ * Creates a new ClassFileObfuscator.
+ * @param programClassPool the class pool in which class names have to be
+ * unique.
+ * @param defaultPackageName the package in which all classes that don't
+ * have fixed names will be put, or <code>null</code>,
+ * if all classes can remain in their original
+ * packages.
+ * @param allowAggressiveOverloading a flag that specifies whether class
+ * members can be overloaded aggressively.
+ */
+ public ClassFileObfuscator(ClassPool programClassPool,
+ String defaultPackageName,
+ boolean useMixedCaseClassNames)
+ {
+ this.defaultPackageName = defaultPackageName;
+ this.useMixedCaseClassNames = useMixedCaseClassNames;
+ this.defaultPackageClassNameFactory = new SimpleNameFactory(useMixedCaseClassNames);
+
+ // Collect all names that have been taken already.
+ programClassPool.classFilesAccept(new ClassFileVisitor()
+ {
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ String newClassName = newClassName(programClassFile);
+ if (newClassName != null)
+ {
+ namesToAvoid.add(newClassName);
+ }
+ }
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+ });
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Does this class file still need a new name?
+ if (newClassName(programClassFile) == null)
+ {
+ // Figure out a new name.
+ String className = programClassFile.getName();
+ String packageName = ClassUtil.internalPackageName(className);
+
+ String newPackageName = packageName;
+
+ // Find the right name factory for this package, or use the default.
+ NameFactory packageClassNameFactory = (NameFactory)packageMap.get(packageName);
+ if (packageClassNameFactory == null)
+ {
+ // Do we have a default package name?
+ if (defaultPackageName == null)
+ {
+ // We haven't seen this package before. Create a new name factory
+ // for it.
+ packageClassNameFactory = new SimpleNameFactory(useMixedCaseClassNames);
+ packageMap.put(packageName, packageClassNameFactory);
+ }
+ else
+ {
+ // Fall back on the default package class name factory and name.
+ packageClassNameFactory = defaultPackageClassNameFactory;
+ newPackageName = defaultPackageName;
+ }
+ }
+
+ // Come up with class names until we get an original one.
+ String newClassName;
+ do
+ {
+ // Let the factory produce a class name.
+ newClassName = packageClassNameFactory.nextName();
+
+ // We may have to add a package part to the class name.
+ if (newPackageName.length() > 0)
+ {
+ newClassName =
+ newPackageName +
+ ClassConstants.INTERNAL_PACKAGE_SEPARATOR +
+ newClassName;
+ }
+
+ }
+ while (namesToAvoid.contains(newClassName));
+
+ setNewClassName(programClassFile, newClassName);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Assigns a new name to the given class file.
+ * @param classFile the given class file.
+ * @param name the new name.
+ */
+ static void setNewClassName(ClassFile classFile, String name)
+ {
+ classFile.setVisitorInfo(name);
+ }
+
+
+
+ /**
+ * Retrieves the new name of the given class file.
+ * @param classFile the given class file.
+ * @return the class file's new name, or <code>null</code> if it doesn't
+ * have one yet.
+ */
+ static String newClassName(ClassFile classFile)
+ {
+ Object visitorInfo = classFile.getVisitorInfo();
+
+ return visitorInfo instanceof String ?
+ (String)visitorInfo :
+ null;
+ }
+}
diff --git a/src/proguard/obfuscate/ClassFileRenamer.java b/src/proguard/obfuscate/ClassFileRenamer.java
new file mode 100644
index 0000000..7e23ca2
--- /dev/null
+++ b/src/proguard/obfuscate/ClassFileRenamer.java
@@ -0,0 +1,716 @@
+/* $Id: ClassFileRenamer.java,v 1.37 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This <code>ClassFileVisitor</code> renames the class names and class member
+ * names of the classes it visits, using names previously determined by the
+ * obfuscator. It can also make package visible classes and class members public,
+ * and it can replace the source file attribute by a given constant string.
+ *
+ * @see ClassFileObfuscator
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileRenamer
+ implements ClassFileVisitor,
+ MemberInfoVisitor,
+ CpInfoVisitor,
+ AttrInfoVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor
+{
+ private MyNameAndTypeRenamer nameAndTypeRenamer = new MyNameAndTypeRenamer();
+
+ private boolean openUpPackages;
+ private String newSourceFileAttribute;
+
+
+ /**
+ * Creates a new ClassFileRenamer.
+ * @param openUpPackages specifies whether to make package visible
+ * classes and class members public.
+ * @param newSourceFileAttribute the new string to be put in the source file
+ * attribute (if present) of the visited classes,
+ * or <code>null</code> to leave it unchanged.
+ */
+ public ClassFileRenamer(boolean openUpPackages,
+ String newSourceFileAttribute)
+ {
+ this.openUpPackages = openUpPackages;
+ this.newSourceFileAttribute = newSourceFileAttribute;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Rename class members.
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+
+ // Rename NameAndTypeCpInfo type references in the constant pool.
+ programClassFile.constantPoolEntriesAccept(nameAndTypeRenamer);
+
+ // Rename class references and class member references in the constant pool.
+ programClassFile.constantPoolEntriesAccept(this);
+
+ // Make package visible classes public, if specified.
+ if (openUpPackages && isPackageVisible(programClassFile.u2accessFlags))
+ {
+ programClassFile.u2accessFlags = makePublic(programClassFile.u2accessFlags);
+ }
+
+ programClassFile.attributesAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ String name = programMemberInfo.getName(programClassFile);
+ String descriptor = programMemberInfo.getDescriptor(programClassFile);
+
+ // The new name is stored with the class member.
+ String newName = MemberInfoObfuscator.newMemberName(programMemberInfo);
+ if (newName != null &&
+ !newName.equals(name))
+ {
+ programMemberInfo.u2nameIndex =
+ createUtf8CpInfo(programClassFile, newName);
+ }
+
+ // Compute the new descriptor.
+ String newDescriptor = newDescriptor(programMemberInfo.getDescriptor(programClassFile),
+ programMemberInfo.referencedClassFiles);
+ if (newDescriptor != null)
+ {
+ programMemberInfo.u2descriptorIndex =
+ createUtf8CpInfo(programClassFile, newDescriptor);
+ }
+
+ // Make package visible class members public, if specified.
+ if (openUpPackages && isPackageVisible(programMemberInfo.u2accessFlags))
+ {
+ programMemberInfo.u2accessFlags = makePublic(programMemberInfo.u2accessFlags);
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ /**
+ * This CpInfoVisitor renames all type elements in all NameAndTypeCpInfo
+ * constant pool entries it visits.
+ */
+ private class MyNameAndTypeRenamer
+ implements CpInfoVisitor
+ {
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ // Compute the new descriptor.
+ String newDescriptor = newDescriptor(nameAndTypeCpInfo.getType(classFile),
+ nameAndTypeCpInfo.referencedClassFiles);
+ if (newDescriptor != null)
+ {
+ nameAndTypeCpInfo.u2descriptorIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newDescriptor);
+ }
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ // If the string is being used in a Class.forName construct, the new
+ // class name can be retrieved from the referenced ClassFile.
+ String newClassName = newClassName(stringCpInfo.getString(classFile),
+ stringCpInfo.referencedClassFile);
+ if (newClassName != null)
+ {
+ String newExternalClassName = ClassUtil.externalClassName(newClassName);
+
+ // Refer to a new Utf8 entry.
+ stringCpInfo.u2stringIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newExternalClassName);
+ }
+ }
+
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ // Compute the new class name (or type).
+ String newClassName = newClassName(classCpInfo.getName(classFile),
+ classCpInfo.referencedClassFile);
+ if (newClassName != null)
+ {
+ // Refer to a new Utf8 entry.
+ classCpInfo.u2nameIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newClassName);
+ }
+ }
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ visitRefCpInfo(classFile, fieldrefCpInfo);
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, interfaceMethodrefCpInfo);
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, methodrefCpInfo);
+ }
+
+
+ private void visitRefCpInfo(ClassFile classFile, RefCpInfo refCpInfo)
+ {
+ // Compute the new class member name.
+ String newMemberName = newMemberName(refCpInfo.referencedMemberInfo);
+
+ if (newMemberName != null)
+ {
+ // Refer to a new NameAndType entry.
+ refCpInfo.u2nameAndTypeIndex =
+ createNameAndTypeCpInfo((ProgramClassFile)classFile,
+ newMemberName,
+ refCpInfo.getType(classFile));
+ }
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ // Compute the new class member name.
+ String newMethodName = newMemberName(enclosingMethodAttrInfo.referencedMethodInfo);
+
+ if (newMethodName != null)
+ {
+ // Refer to a new NameAndType entry.
+ enclosingMethodAttrInfo.u2nameAndTypeIndex =
+ createNameAndTypeCpInfo((ProgramClassFile)classFile,
+ newMethodName,
+ enclosingMethodAttrInfo.getType(classFile));
+ }
+ }
+
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ // Rename the types of the local variables.
+ localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ // Rename the signatures of the local variables.
+ localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+ {
+ // Rename the source file attribute, if specified.
+ if (newSourceFileAttribute != null)
+ {
+ sourceFileAttrInfo.u2sourceFileIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newSourceFileAttribute);
+ }
+ }
+
+
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
+ {
+ // Rename the source file attribute, if specified.
+ if (newSourceFileAttribute != null)
+ {
+ sourceDirAttrInfo.u2sourceDirIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newSourceFileAttribute);
+ }
+ }
+
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ // Compute the new signature.
+ String newSignature = newDescriptor(classFile.getCpString(signatureAttrInfo.u2signatureIndex),
+ signatureAttrInfo.referencedClassFiles);
+ if (newSignature != null)
+ {
+ signatureAttrInfo.u2signatureIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newSignature);
+ }
+ }
+
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ // Rename the annotations.
+ runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ // Rename the annotations.
+ runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ // Rename the annotations.
+ runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ // Rename the annotations.
+ runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ // Rename the annotation.
+ annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+ {
+ // Compute the new descriptor.
+ String newDescriptor = newClassName(classFile.getCpString(localVariableInfo.u2descriptorIndex),
+ localVariableInfo.referencedClassFile);
+ if (newDescriptor != null)
+ {
+ // Refer to a new Utf8 entry.
+ localVariableInfo.u2descriptorIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newDescriptor);
+ }
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ // Compute the new signature.
+ String newSignature = newDescriptor(classFile.getCpString(localVariableTypeInfo.u2signatureIndex),
+ localVariableTypeInfo.referencedClassFiles);
+ if (newSignature != null)
+ {
+ localVariableTypeInfo.u2signatureIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newSignature);
+ }
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(ClassFile classFile, Annotation annotation)
+ {
+ // Compute the new type name.
+ String newTypeName = newDescriptor(classFile.getCpString(annotation.u2typeIndex),
+ annotation.referencedClassFiles);
+ if (newTypeName != null)
+ {
+ // Refer to a new Utf8 entry.
+ annotation.u2typeIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newTypeName);
+ }
+
+ // Rename the element values.
+ annotation.elementValuesAccept(classFile, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ renameElementValue(classFile, constantElementValue);
+ }
+
+
+ public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ renameElementValue(classFile, enumConstantElementValue);
+
+ // Compute the new type name.
+ String newTypeName = newDescriptor(classFile.getCpString(enumConstantElementValue.u2typeNameIndex),
+ enumConstantElementValue.referencedClassFiles);
+ if (newTypeName != null)
+ {
+ // Refer to a new Utf8 entry.
+ enumConstantElementValue.u2typeNameIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newTypeName);
+ }
+ }
+
+
+ public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
+ {
+ renameElementValue(classFile, classElementValue);
+
+ // Compute the new class name.
+ String newClassName = newDescriptor(classFile.getCpString(classElementValue.u2classInfoIndex),
+ classElementValue.referencedClassFiles);
+
+ if (newClassName != null)
+ {
+ // Refer to a new Utf8 entry.
+ classElementValue.u2classInfoIndex =
+ createUtf8CpInfo((ProgramClassFile)classFile, newClassName);
+ }
+ }
+
+
+ public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ renameElementValue(classFile, annotationElementValue);
+
+ // Rename the annotation.
+ annotationElementValue.annotationAccept(classFile, this);
+ }
+
+
+ public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ renameElementValue(classFile, arrayElementValue);
+
+ // Rename the element values.
+ arrayElementValue.elementValuesAccept(classFile, annotation, this);
+ }
+
+
+ /**
+ * Renames the method reference of the element value, if any.
+ */
+ public void renameElementValue(ClassFile classFile, ElementValue elementValue)
+ {
+ // Compute the new class member name.
+ String newMethodName = newMemberName(elementValue.referencedMethodInfo);
+
+ if (newMethodName != null)
+ {
+ // Refer to a new NameAndType entry.
+ elementValue.u2elementName =
+ createUtf8CpInfo((ProgramClassFile)classFile, newMethodName);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Finds or creates a NameAndTypeCpInfo constant pool entry with the given
+ * name and type, in the given class file.
+ * @return the constant pool index of the NameAndTypeCpInfo.
+ */
+ private int createNameAndTypeCpInfo(ProgramClassFile programClassFile,
+ String name,
+ String type)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int u2constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Pick up the right list of referenced class files, in case we need to
+ // create a new NameAndTypeCpInfo.
+ ClassFile[] referencedClassFiles = null;
+
+ // Check if there is a NameAndTypeCpInfo with the given name and type already.
+ for (int index = 1; index < u2constantPoolCount; index++)
+ {
+ CpInfo cpInfo = constantPool[index];
+
+ if (cpInfo != null &&
+ cpInfo.getTag() == ClassConstants.CONSTANT_NameAndType)
+ {
+ NameAndTypeCpInfo nameAndTypeCpInfo = (NameAndTypeCpInfo)cpInfo;
+ if (nameAndTypeCpInfo.getType(programClassFile).equals(type))
+ {
+ if (nameAndTypeCpInfo.getName(programClassFile).equals(name))
+ {
+ return index;
+ }
+
+ referencedClassFiles = nameAndTypeCpInfo.referencedClassFiles;
+ }
+ }
+ }
+
+ int u2nameIndex = createUtf8CpInfo(programClassFile, name);
+ int u2descriptorIndex = createUtf8CpInfo(programClassFile, type);
+
+ return addCpInfo(programClassFile, new NameAndTypeCpInfo(u2nameIndex,
+ u2descriptorIndex,
+ referencedClassFiles));
+ }
+
+
+ /**
+ * Finds or creates an Utf8CpInfo constant pool entry for the given string,
+ * in the given class file.
+ * @return the constant pool index of the Utf8CpInfo.
+ */
+ private int createUtf8CpInfo(ProgramClassFile programClassFile, String string)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int u2constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Check if there is a Utf8CpInfo with the given string already.
+ for (int index = 1; index < u2constantPoolCount; index++)
+ {
+ CpInfo cpInfo = constantPool[index];
+
+ if (cpInfo != null &&
+ cpInfo.getTag() == ClassConstants.CONSTANT_Utf8)
+ {
+ Utf8CpInfo utf8CpInfo = (Utf8CpInfo)cpInfo;
+ if (utf8CpInfo.getString().equals(string))
+ {
+ return index;
+ }
+ }
+ }
+
+ return addCpInfo(programClassFile, new Utf8CpInfo(string));
+ }
+
+
+ /**
+ * Adds a given constant pool entry to the end of the constant pool.
+ * @return the constant pool index for the added entry.
+ */
+ private int addCpInfo(ProgramClassFile programClassFile, CpInfo cpInfo)
+ {
+ CpInfo[] constantPool = programClassFile.constantPool;
+ int u2constantPoolCount = programClassFile.u2constantPoolCount;
+
+ // Make sure there is enough space for another constant pool entry.
+ if (u2constantPoolCount == constantPool.length)
+ {
+ programClassFile.constantPool = new CpInfo[u2constantPoolCount+1];
+ System.arraycopy(constantPool, 0,
+ programClassFile.constantPool, 0,
+ u2constantPoolCount);
+ constantPool = programClassFile.constantPool;
+
+ }
+
+ // Create a new Utf8CpInfo for the given string.
+ constantPool[programClassFile.u2constantPoolCount++] = cpInfo;
+
+ return u2constantPoolCount;
+ }
+
+
+ /**
+ * Returns the new descriptor based on the given descriptor and the new
+ * names of the given referenced class files.
+ */
+ private String newDescriptor(String descriptor,
+ ClassFile[] referencedClassFiles)
+ {
+ // If there are no referenced classes, the descriptor doesn't change.
+ if (referencedClassFiles == null)
+ {
+ return null;
+ }
+
+ // Unravel and reconstruct the class elements of the descriptor.
+ DescriptorClassEnumeration descriptorClassEnumeration =
+ new DescriptorClassEnumeration(descriptor);
+
+ String newDescriptor = descriptorClassEnumeration.nextFluff();
+
+ int index = 0;
+ while (descriptorClassEnumeration.hasMoreClassNames())
+ {
+ String className = descriptorClassEnumeration.nextClassName();
+ String fluff = descriptorClassEnumeration.nextFluff();
+
+ String newClassName = newClassName(className,
+ referencedClassFiles[index++]);
+
+ // Fall back on the original class name if there is no new name.
+ if (newClassName == null)
+ {
+ newClassName = className;
+ }
+
+ newDescriptor = newDescriptor + newClassName + fluff;
+ }
+
+ // If the descriptor hasn't changed after all, just return null.
+ if (descriptor.equals(newDescriptor))
+ {
+ return null;
+ }
+
+ return newDescriptor;
+ }
+
+
+ /**
+ * Returns the new class name based on the given class name and the new
+ * name of the given referenced class file. Class names of array types
+ * are handled properly.
+ */
+ private String newClassName(String className,
+ ClassFile referencedClassFile)
+ {
+ // If there is no referenced class, the descriptor doesn't change.
+ if (referencedClassFile == null)
+ {
+ return null;
+ }
+
+ String newClassName =
+ ClassFileObfuscator.newClassName(referencedClassFile);
+
+ // If there is no new class name, the descriptor doesn't change.
+ if (newClassName == null)
+ {
+ return null;
+ }
+
+ // Is it an array type?
+ if (className.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY)
+ {
+ // Add the array prefixes and suffix "[L...;".
+ newClassName =
+ className.substring(0, className.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START)+1) +
+ newClassName +
+ ClassConstants.INTERNAL_TYPE_CLASS_END;
+ }
+
+ return newClassName;
+ }
+
+
+ /**
+ * Returns the new class member name based on the given referenced class
+ * member.
+ */
+ private String newMemberName(MemberInfo referencedMemberInfo)
+ {
+ if (referencedMemberInfo == null)
+ {
+ return null;
+ }
+
+ return MemberInfoObfuscator.newMemberName(referencedMemberInfo);
+ }
+
+
+ /**
+ * Returns whether the given access flags specify a package visible class
+ * or class member (including public or protected access).
+ */
+ private boolean isPackageVisible(int accessFlags)
+ {
+ return AccessUtil.accessLevel(accessFlags) >= AccessUtil.PACKAGE_VISIBLE;
+ }
+
+
+ /**
+ * Returns the given access flags, modified such that the class or class
+ * member becomes public.
+ */
+ private int makePublic(int accessFlags)
+ {
+ return AccessUtil.replaceAccessFlags(accessFlags,
+ ClassConstants.INTERNAL_ACC_PUBLIC);
+ }
+}
diff --git a/src/proguard/obfuscate/MappingKeeper.java b/src/proguard/obfuscate/MappingKeeper.java
new file mode 100644
index 0000000..69494a9
--- /dev/null
+++ b/src/proguard/obfuscate/MappingKeeper.java
@@ -0,0 +1,119 @@
+/* $Id: MappingKeeper.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.util.ClassUtil;
+
+
+/**
+ * This MappingKeeper applies the mappings that it receives to its class pool,
+ * so these mappings are ensured in a subsequent obfuscation step.
+ *
+ * @author Eric Lafortune
+ */
+public class MappingKeeper implements MappingProcessor
+{
+ private ClassPool classPool;
+
+ // A field acting as a parameter.
+ private ClassFile classFile;
+
+
+ /**
+ * Creates a new MappingKeeper.
+ * @param classPool the class pool in which class names and class member names
+ * have to be mapped.
+ */
+ public MappingKeeper(ClassPool classPool)
+ {
+ this.classPool = classPool;
+ }
+
+
+ // Implementations for MappingProcessor.
+
+ public boolean processClassFileMapping(String className,
+ String newClassName)
+ {
+ // Find the class.
+ String name = ClassUtil.internalClassName(className);
+
+ classFile = classPool.getClass(name);
+ if (classFile != null)
+ {
+ // Make sure the mapping name will be kept.
+ String newName = ClassUtil.internalClassName(newClassName);
+
+ ClassFileObfuscator.setNewClassName(classFile, newName);
+
+ // The class members have to be kept as well.
+ return true;
+ }
+
+ return false;
+ }
+
+
+ public void processFieldMapping(String className,
+ String fieldType,
+ String fieldName,
+ String newFieldName)
+ {
+ if (classFile != null)
+ {
+ // Find the field.
+ String name = fieldName;
+ String descriptor = ClassUtil.internalType(fieldType);
+
+ FieldInfo fieldInfo = classFile.findField(name, descriptor);
+ if (fieldInfo != null)
+ {
+ // Make sure the mapping name will be kept.
+ MemberInfoObfuscator.setNewMemberName(fieldInfo, newFieldName);
+ }
+ }
+ }
+
+
+ public void processMethodMapping(String className,
+ int firstLineNumber,
+ int lastLineNumber,
+ String methodReturnType,
+ String methodNameAndArguments,
+ String newMethodName)
+ {
+ if (classFile != null)
+ {
+ // Find the method.
+ String name = ClassUtil.externalMethodName(methodNameAndArguments);
+ String descriptor = ClassUtil.internalMethodDescriptor(methodReturnType,
+ methodNameAndArguments);
+
+ MethodInfo methodInfo = classFile.findMethod(name, descriptor);
+ if (methodInfo != null)
+ {
+ // Make sure the mapping name will be kept.
+ MemberInfoObfuscator.setNewMemberName(methodInfo, newMethodName);
+ }
+ }
+ }
+}
diff --git a/src/proguard/obfuscate/MappingPrinter.java b/src/proguard/obfuscate/MappingPrinter.java
new file mode 100644
index 0000000..dd38362
--- /dev/null
+++ b/src/proguard/obfuscate/MappingPrinter.java
@@ -0,0 +1,170 @@
+/* $Id: MappingPrinter.java,v 1.15 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+
+/**
+ * This ClassFileVisitor prints out the renamed class files and class members with
+ * their old names and new names.
+ *
+ * @see ClassFileRenamer
+ *
+ * @author Eric Lafortune
+ */
+public class MappingPrinter
+ implements ClassFileVisitor,
+ MemberInfoVisitor
+{
+ private PrintStream ps;
+
+ // A field to remember the class name, if a header is needed for class members.
+ private String className;
+
+
+ /**
+ * Creates a new MappingPrinter that prints to <code>System.out</code>.
+ */
+ public MappingPrinter()
+ {
+ this(System.out);
+ }
+
+
+ /**
+ * Creates a new MappingPrinter that prints to the given stream.
+ * @param printStream the stream to which to print
+ */
+ public MappingPrinter(PrintStream printStream)
+ {
+ this.ps = printStream;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ className = programClassFile.getName();
+
+ String newClassName = ClassFileObfuscator.newClassName(programClassFile);
+
+ if (newClassName != null)
+ {
+ ps.println(ClassUtil.externalClassName(className) +
+ " -> " +
+ ClassUtil.externalClassName(newClassName) +
+ ":");
+
+ className = null;
+ }
+
+ // Print out the class members.
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ String newMemberName = MemberInfoObfuscator.newMemberName(programFieldInfo);
+
+ if (newMemberName != null)
+ {
+ printClassNameHeader();
+
+ ps.println(" " +
+ lineNumberRange(programClassFile, programFieldInfo) +
+ ClassUtil.externalFullFieldDescription(
+ 0,
+ programFieldInfo.getName(programClassFile),
+ programFieldInfo.getDescriptor(programClassFile)) +
+ " -> " +
+ newMemberName);
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ String newMemberName = MemberInfoObfuscator.newMemberName(programMethodInfo);
+
+ if (newMemberName != null)
+ {
+ printClassNameHeader();
+
+ ps.println(" " +
+ lineNumberRange(programClassFile, programMethodInfo) +
+ ClassUtil.externalFullMethodDescription(
+ programClassFile.getName(),
+ 0,
+ programMethodInfo.getName(programClassFile),
+ programMethodInfo.getDescriptor(programClassFile)) +
+ " -> " +
+ newMemberName);
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Small utility methods.
+
+ /**
+ * Prints the class name field. The field is then cleared, so it is not
+ * printed again.
+ */
+ private void printClassNameHeader()
+ {
+ if (className != null)
+ {
+ ps.println(ClassUtil.externalClassName(className) + ":");
+ className = null;
+ }
+ }
+
+
+ /**
+ * Returns the line number range of the given class member, followed by a
+ * colon, or just an empty String if no range is available.
+ */
+ private static String lineNumberRange(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ String range = programMemberInfo.getLineNumberRange(programClassFile);
+ return range != null ?
+ (range + ":") :
+ "";
+ }
+}
diff --git a/src/proguard/obfuscate/MappingProcessor.java b/src/proguard/obfuscate/MappingProcessor.java
new file mode 100644
index 0000000..a37df97
--- /dev/null
+++ b/src/proguard/obfuscate/MappingProcessor.java
@@ -0,0 +1,78 @@
+/* $Id: MappingProcessor.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+
+/**
+ * This interface specifies methods to process name mappings between original
+ * class files and their obfuscated versions. The mappings are typically read
+ * from a mapping file.
+ *
+ * @see MappingReader
+ *
+ * @author Eric Lafortune
+ */
+public interface MappingProcessor
+{
+ /**
+ * Processes the given class name mapping.
+ *
+ * @param className the original class name.
+ * @param newClassName the new class name.
+ * @return whether the processor is interested in receiving mappings of the
+ * class members of this class.
+ */
+ public boolean processClassFileMapping(String className,
+ String newClassName);
+
+ /**
+ * Processes the given field name mapping.
+ *
+ * @param className the original class name.
+ * @param fieldType the original external field type.
+ * @param fieldName the original field name.
+ * @param newFieldName the new field name.
+ */
+ public void processFieldMapping(String className,
+ String fieldType,
+ String fieldName,
+ String newFieldName);
+
+ /**
+ * Processes the given method name mapping.
+ *
+ * @param className the original class name.
+ * @param firstLineNumber the first line number of the method, or
+ * 0 if it is not known.
+ * @param lastLineNumber the last line number of the method, or
+ * 0 if it is not known.
+ * @param methodReturnType the original external method return type.
+ * @param methodNameAndArguments the original external method name and
+ * arguments.
+ * @param newMethodName the new method name.
+ */
+ public void processMethodMapping(String className,
+ int firstLineNumber,
+ int lastLineNumber,
+ String methodReturnType,
+ String methodNameAndArguments,
+ String newMethodName);
+}
diff --git a/src/proguard/obfuscate/MappingReader.java b/src/proguard/obfuscate/MappingReader.java
new file mode 100644
index 0000000..bad1218
--- /dev/null
+++ b/src/proguard/obfuscate/MappingReader.java
@@ -0,0 +1,195 @@
+/* $Id: MappingReader.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import java.io.*;
+
+
+/**
+ * This class can parse mapping files and invoke a processor for each of the
+ * mapping entries.
+ *
+ * @author Eric Lafortune
+ */
+public class MappingReader
+{
+ private String mappingFileName;
+
+
+ public MappingReader(String mappingFileName)
+ {
+ this.mappingFileName = mappingFileName;
+ }
+
+
+ /**
+ * Reads the mapping file, presenting all of the encountered mapping entries
+ * to the given processor.
+ */
+ public void pump(MappingProcessor mappingProcessor) throws IOException
+ {
+ LineNumberReader reader = null;
+
+ try
+ {
+ reader = new LineNumberReader(
+ new BufferedReader(
+ new FileReader(mappingFileName)));
+
+ String className = null;
+
+ // Read the subsequent class mappings and class member mappings.
+ while (true)
+ {
+ String line = reader.readLine();
+
+ if (line == null)
+ {
+ break;
+ }
+
+ // The distinction between a class file mapping and a class
+ // member mapping is the initial whitespace.
+ if (!line.startsWith(" "))
+ {
+ // Process the class file mapping and remember the class's
+ // old name.
+ className = processClassFileMapping(line, mappingProcessor);
+ }
+ else if (className != null)
+ {
+ // Process the class member mapping, in the context of the
+ // current old class name.
+ processClassMemberMapping(className, line, mappingProcessor);
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new IOException("Can't process mapping file (" + ex.getMessage() + ")");
+ }
+ finally
+ {
+ if (reader != null)
+ {
+ try
+ {
+ reader.close();
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Parses the given line with a class file mapping and processes the
+ * results with the given mapping processor. Returns the old class name,
+ * or null if any subsequent class member lines can be ignored.
+ */
+ private String processClassFileMapping(String line,
+ MappingProcessor mappingProcessor)
+ {
+ // See if we can parse "___ -> ___:", containing the original
+ // class name and the new class name.
+
+ line = line.trim();
+
+ int arrowIndex = line.indexOf("->");
+ if (arrowIndex < 0)
+ {
+ return null;
+ }
+
+ int colonIndex = line.indexOf(':', arrowIndex + 2);
+ if (colonIndex < 0)
+ {
+ return null;
+ }
+
+ // Extract the elements.
+ String className = line.substring(0, arrowIndex).trim();
+ String newClassName = line.substring(arrowIndex + 2, colonIndex).trim();
+
+ // Process this class name mapping.
+ boolean interested = mappingProcessor.processClassFileMapping(className, newClassName);
+
+ return interested ? className : null;
+ }
+
+
+ /**
+ * Parses the given line with a class member mapping and processes the
+ * results with the given mapping processor.
+ */
+ private void processClassMemberMapping(String className,
+ String line,
+ MappingProcessor mappingProcessor)
+ {
+ // See if we can parse " ___:___:___ ___ -> ___",
+ // containing the optional line numbers, the return type, the original
+ // field/method name (including arguments), and the new method name.
+
+ line = line.trim();
+
+ int colonIndex1 = line.indexOf(':');
+ int colonIndex2 = line.indexOf(':', colonIndex1 + 1);
+
+ int spaceIndex = line.indexOf(' ', colonIndex2 + 1);
+ if (spaceIndex < 0)
+ {
+ return;
+ }
+
+ int arrowIndex = line.indexOf("->", spaceIndex + 1);
+ if (arrowIndex < 1)
+ {
+ return;
+ }
+
+ int firstLineNumber = colonIndex1 < 0 ? 0 :
+ Integer.parseInt(line.substring(0, colonIndex1).trim());
+
+ int lastLineNumber = colonIndex1 < 0 ||
+ colonIndex2 < 0 ? 0 :
+ Integer.parseInt(line.substring(colonIndex1 + 1, colonIndex2).trim());
+
+ // Extract the elements.
+ String type = line.substring(colonIndex2 + 1, spaceIndex).trim();
+ String name = line.substring(spaceIndex + 1, arrowIndex).trim();
+ String newName = line.substring(arrowIndex + 2).trim();
+
+ // Process this class member mapping.
+ if (type.length() > 0 && name.length() > 0)
+ {
+ if (name.charAt(name.length() - 1) != ')')
+ {
+ mappingProcessor.processFieldMapping(className, type, name, newName);
+ }
+ else
+ {
+ mappingProcessor.processMethodMapping(className, firstLineNumber, lastLineNumber, type, name, newName);
+ }
+ }
+ }
+}
diff --git a/src/proguard/obfuscate/MemberInfoLinker.java b/src/proguard/obfuscate/MemberInfoLinker.java
new file mode 100644
index 0000000..6afe6a0
--- /dev/null
+++ b/src/proguard/obfuscate/MemberInfoLinker.java
@@ -0,0 +1,185 @@
+/* $Id: MemberInfoLinker.java,v 1.9 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+import java.util.*;
+
+
+/**
+ * This ClassFileVisitor links all methods that should get the same names
+ * in the name spaces of all visited class files. A class file's name space
+ * encompasses all of its subclasses and interfaces. It is typically a class file
+ * that is not being subclassed. Chains of links that have been created in
+ * previous invocations are merged with new chains of links, in order to create
+ * a consistent set of chains. Class initialization methods and constructors are
+ * ignored.
+ *
+ * @see MemberInfoObfuscator
+ *
+ * @author Eric Lafortune
+ */
+public class MemberInfoLinker
+ implements ClassFileVisitor,
+ MemberInfoVisitor
+{
+ // An object that is reset and reused every time.
+ // The map: [class member name+descriptor - class member info]
+ private final Map methodInfoMap = new HashMap();
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Collect all members in this class's name space.
+ programClassFile.hierarchyAccept(true, true, true, false,
+ new AllMemberInfoVisitor(this));
+
+ // Clean up for obfuscation of the next name space.
+ methodInfoMap.clear();
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMethodInfo(programClassFile, programMethodInfo);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ visitMethodInfo(libraryClassFile, libraryMethodInfo);
+ }
+
+
+ /**
+ * Links the given method into the chains of links. Class initialization
+ * methods and constructors are ignored.
+ * @param classFile the class file of the given method.
+ * @param methodInfo the method to be linked.
+ */
+ private void visitMethodInfo(ClassFile classFile, MethodInfo methodInfo)
+ {
+ // Private methods don't have to be linked.
+ if ((methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_PRIVATE) != 0)
+ {
+ return;
+ }
+
+ // Get the method's original name and descriptor.
+ String name = methodInfo.getName(classFile);
+ String descriptor = methodInfo.getDescriptor(classFile);
+
+ // Special cases: <clinit> and <init> are always kept unchanged.
+ // We can ignore them here.
+ if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
+ name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+ {
+ return;
+ }
+
+ // Get the last method in the chain.
+ MemberInfo thisLastMemberInfo = lastMemberInfo(methodInfo);
+
+ // See if we've already come across a method with the same name and
+ // descriptor.
+ String key = name + descriptor;
+ MethodInfo otherMethodInfo = (MethodInfo)methodInfoMap.get(key);
+
+ if (otherMethodInfo == null)
+ {
+ // Store the new class method info in the map.
+ methodInfoMap.put(key, thisLastMemberInfo);
+ }
+ else
+ {
+ // Get the last method in the other chain.
+ MemberInfo otherLastMemberInfo = lastMemberInfo(otherMethodInfo);
+
+ // Check if both link chains aren't already ending in the same element.
+ if (thisLastMemberInfo != otherLastMemberInfo)
+ {
+ // Merge the two chains, making sure LibraryMethodInfo elements,
+ // if any, are at the end of the resulting chain.
+ if (thisLastMemberInfo instanceof LibraryMethodInfo)
+ {
+ // This class method chain ends with a library class method.
+ // Link this chain to the end of the other one.
+ otherLastMemberInfo.setVisitorInfo(thisLastMemberInfo);
+ }
+ /* We can skip this test and go straight to the final case.
+ else if (otherLastVisitorAccepter instanceof LibraryMethodInfo)
+ {
+ // The other method chain ends with a library class method.
+ // Link the other chain to the end of this one.
+ thisLastVisitorAccepter.setVisitorInfo(otherLastVisitorAccepter);
+ }
+ */
+ else
+ {
+ // We have two non-library methods. Link their chains
+ // one way or another.
+ thisLastMemberInfo.setVisitorInfo(otherLastMemberInfo);
+ }
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Finds the last class member in the linked list of class members.
+ * @param memberInfo the given class member.
+ * @return the last class member in the linked list.
+ */
+ static MemberInfo lastMemberInfo(MemberInfo memberInfo)
+ {
+ VisitorAccepter lastVisitorAccepter = memberInfo;
+ while (lastVisitorAccepter.getVisitorInfo() != null &&
+ lastVisitorAccepter.getVisitorInfo() instanceof VisitorAccepter)
+ {
+ lastVisitorAccepter = (VisitorAccepter)lastVisitorAccepter.getVisitorInfo();
+ }
+
+ return (MemberInfo)lastVisitorAccepter;
+ }
+}
diff --git a/src/proguard/obfuscate/MemberInfoObfuscator.java b/src/proguard/obfuscate/MemberInfoObfuscator.java
new file mode 100644
index 0000000..94d3171
--- /dev/null
+++ b/src/proguard/obfuscate/MemberInfoObfuscator.java
@@ -0,0 +1,404 @@
+/* $Id: MemberInfoObfuscator.java,v 1.12 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+import java.io.IOException;
+import java.util.*;
+
+
+/**
+ * This ClassFileVisitor obfuscates all class members in the name spaces of all
+ * visited class file. The class members must have been linked before applying this
+ * visitor. The class file is typically a class file that is not being subclassed.
+ *
+ * @see MemberInfoLinker
+ *
+ * @author Eric Lafortune
+ */
+public class MemberInfoObfuscator implements ClassFileVisitor
+{
+ private static final char UNIQUE_SUFFIX = '_';
+
+ private boolean allowAggressiveOverloading;
+
+ private NameFactory nameFactory = new SimpleNameFactory();
+ private NameFactory uniqueNameFactory = new SimpleNameFactory();
+
+ // Some objects that are reset and reused every time.
+
+ // The main maps: [class member descriptor - new name - name]
+ private final Map nonPrivateDescriptorMap = new HashMap();
+ private final Map privateDescriptorMap = new HashMap();
+
+
+
+ /**
+ * Creates a new MemberObfuscator.
+ * @param allowAggressiveOverloading a flag that specifies whether class
+ * members can be overloaded aggressively.
+ * @param obfuscationDictionary the optional name of a file from which
+ * obfuscated method names can be read.
+ */
+ public MemberInfoObfuscator(boolean allowAggressiveOverloading,
+ String obfuscationDictionary)
+ throws IOException
+ {
+ this.allowAggressiveOverloading = allowAggressiveOverloading;
+
+ // Get names from the obfuscation dictionary, if specified.
+ if (obfuscationDictionary != null)
+ {
+ nameFactory = new ReadNameFactory(obfuscationDictionary, nameFactory);
+ }
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Collect all preset new member names in this class's name space.
+ // This actually includes preset new private member names.
+ programClassFile.hierarchyAccept(true, true, true, false,
+ new AllMemberInfoVisitor(
+ new MyNewNameCollector(nonPrivateDescriptorMap)));
+
+ // Assign new names to all non-private members in this class's name space.
+ programClassFile.hierarchyAccept(true, true, true, false,
+ new MyNonPrivateMemberInfoObfuscator());
+
+ // Assign new names to all private members in this class's name space.
+ programClassFile.hierarchyAccept(true, true, true, false,
+ new MyPrivateMemberInfoObfuscator());
+
+ // Clean up for obfuscation of the next name space.
+ nonPrivateDescriptorMap.clear();
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ private class MyNonPrivateMemberInfoObfuscator implements ClassFileVisitor
+ {
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ MemberInfoAccessFilter nonPrivateNewNameAssigner =
+ new MemberInfoAccessFilter(
+ 0,
+ ClassConstants.INTERNAL_ACC_PRIVATE,
+ new MyNewNameAssigner(nonPrivateDescriptorMap));
+
+ programClassFile.fieldsAccept(nonPrivateNewNameAssigner);
+ programClassFile.methodsAccept(nonPrivateNewNameAssigner);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+ }
+
+
+ private class MyPrivateMemberInfoObfuscator implements ClassFileVisitor
+ {
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ MemberInfoAccessFilter privateNewNameAssigner =
+ new MemberInfoAccessFilter(
+ ClassConstants.INTERNAL_ACC_PRIVATE,
+ 0,
+ new MyNewNameAssigner(privateDescriptorMap, nonPrivateDescriptorMap));
+
+ programClassFile.fieldsAccept(privateNewNameAssigner);
+ programClassFile.methodsAccept(privateNewNameAssigner);
+
+ // Clean up for obfuscation of the next class.
+ privateDescriptorMap.clear();
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+ }
+
+
+ private class MyNewNameCollector implements MemberInfoVisitor
+ {
+ private final Map descriptorMap;
+
+
+ public MyNewNameCollector(Map descriptorMap)
+ {
+ this.descriptorMap = descriptorMap;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ // Make sure the library field keeps its name.
+ String name = libraryFieldInfo.getName(libraryClassFile);
+ setNewMemberName(libraryFieldInfo, name);
+
+ visitMemberInfo(libraryClassFile, libraryFieldInfo);
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ // Make sure the library method keeps its name.
+ String name = libraryMethodInfo.getName(libraryClassFile);
+ setNewMemberName(libraryMethodInfo, name);
+
+ visitMemberInfo(libraryClassFile, libraryMethodInfo);
+ }
+
+
+ /**
+ * Inserts the new name of the given class member into the main map.
+ * @param classFile the class file of the given member.
+ * @param memberInfo the class member to be linked.
+ */
+ private void visitMemberInfo(ClassFile classFile, MemberInfo memberInfo)
+ {
+ // Special cases: <clinit> and <init> are always kept unchanged.
+ // We can ignore them here.
+ String name = memberInfo.getName(classFile);
+ if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
+ name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+ {
+ return;
+ }
+
+ // Get the member's new name.
+ String newName = newMemberName(memberInfo);
+
+ // Remember it, if it was set.
+ if (newName != null)
+ {
+ // Get the member's descriptor.
+ String descriptor = memberInfo.getDescriptor(classFile);
+
+ // Check whether we're allowed to do aggressive overloading
+ if (!allowAggressiveOverloading)
+ {
+ // Trim the return argument from the descriptor if not.
+ // Works for fields and methods alike.
+ descriptor = descriptor.substring(0, descriptor.indexOf(')')+1);
+ }
+
+ // Put the [descriptor - new name] in the map,
+ // creating a new set of new names if necessary.
+ Map newNameMap = retrieveNameMap(descriptorMap, descriptor);
+
+ // Is the other original name different from this original
+ // name?
+ String otherName = (String)newNameMap.get(newName);
+ if (otherName != null &&
+ !otherName.equals(name))
+ {
+ // There's a conflict! A member (with a given old name) in a
+ // first namespace has received the same new name as this
+ // member (with a different old name) in a second name space,
+ // and now these two have to live together in this name space.
+ // Assign a truly unique new name to this member.
+ setNewMemberName(memberInfo, uniqueNameFactory.nextName() + UNIQUE_SUFFIX);
+ }
+ else
+ {
+ // Remember not to use the new name again in this name space.
+ newNameMap.put(newName, name);
+ }
+ }
+ }
+ }
+
+
+ private class MyNewNameAssigner implements MemberInfoVisitor
+ {
+ private final Map descriptorMap;
+ private final Map secondaryDescriptorMap;
+
+
+ public MyNewNameAssigner(Map descriptorMap)
+ {
+ this(descriptorMap, null);
+ }
+
+
+ public MyNewNameAssigner(Map descriptorMap,
+ Map secondaryDescriptorMap)
+ {
+ this.descriptorMap = descriptorMap;
+ this.secondaryDescriptorMap = secondaryDescriptorMap;
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ /**
+ * Inserts the given class member into the main map.
+ * @param classFile the class file of the given member.
+ * @param memberInfo the class member to be linked.
+ */
+ private void visitMemberInfo(ClassFile classFile, MemberInfo memberInfo)
+ {
+ // Special cases: <clinit> and <init> are always kept unchanged.
+ // We can ignore them here.
+ String name = memberInfo.getName(classFile);
+ if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
+ name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+ {
+ return;
+ }
+
+ // Get the member's new name.
+ String newName = newMemberName(memberInfo);
+
+ // Assign a new one, if necessary.
+ if (newName == null)
+ {
+ // Get the member's descriptor.
+ String descriptor = memberInfo.getDescriptor(classFile);
+
+ // Check whether we're allowed to do aggressive overloading
+ if (!allowAggressiveOverloading)
+ {
+ // Trim the return argument from the descriptor if not.
+ // Works for fields and methods alike.
+ descriptor = descriptor.substring(0, descriptor.indexOf(')')+1);
+ }
+
+ // Retrieve the new [ new name - old name ] map for the given
+ // descriptor, creating a new one if necessary.
+ Map newNameMap = retrieveNameMap(descriptorMap, descriptor);
+ Map secondaryNewNameMap = secondaryDescriptorMap == null ? null :
+ (Map)secondaryDescriptorMap.get(descriptor);
+
+ // Find a unique new name.
+ nameFactory.reset();
+
+ do
+ {
+ newName = nameFactory.nextName();
+ }
+ while (newNameMap.containsKey(newName) ||
+ (secondaryNewNameMap != null &&
+ secondaryNewNameMap.containsKey(newName)));
+
+ // Assign the new name.
+ setNewMemberName(memberInfo, newName);
+
+ // Remember not to use the new name again in this name space.
+ newNameMap.put(newName, name);
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Gets the nested set of new names, based on the given map
+ * [descriptor - nested set of new names] and a given descriptor.
+ * A new empty set is created if necessary.
+ * @param descriptorMap the map of descriptors to [ new name - member info ] maps.
+ * @param descriptor the class member descriptor.
+ * @return the nested set of new names.
+ */
+ private Map retrieveNameMap(Map descriptorMap, String descriptor)
+ {
+ // See if we can find the nested map with this descriptor key.
+ Map nameMap = (Map)descriptorMap.get(descriptor);
+
+ // Create a new one if not.
+ if (nameMap == null)
+ {
+ nameMap = new HashMap();
+ descriptorMap.put(descriptor, nameMap);
+ }
+
+ return nameMap;
+ }
+
+
+ /**
+ * Assigns a new name to the given class member.
+ * @param memberInfo the given class member.
+ * @param name the new name.
+ */
+ static void setNewMemberName(MemberInfo memberInfo, String name)
+ {
+ MemberInfoLinker.lastMemberInfo(memberInfo).setVisitorInfo(name);
+ }
+
+
+ /**
+ * Retrieves the new name of the given class member.
+ * @param memberInfo the given class member.
+ * @return the class member's new name, or <code>null</code> if it doesn't
+ * have one yet.
+ */
+ static String newMemberName(MemberInfo memberInfo)
+ {
+ return (String)MemberInfoLinker.lastMemberInfo(memberInfo).getVisitorInfo();
+ }
+}
diff --git a/src/proguard/obfuscate/MultiMappingProcessor.java b/src/proguard/obfuscate/MultiMappingProcessor.java
new file mode 100644
index 0000000..14de028
--- /dev/null
+++ b/src/proguard/obfuscate/MultiMappingProcessor.java
@@ -0,0 +1,98 @@
+/* $Id: MultiMappingProcessor.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.util.ClassUtil;
+
+
+/**
+ * This MappingKeeper delegates all method calls to each MappingProcessor
+ * in a given list.
+ *
+ * @author Eric Lafortune
+ */
+public class MultiMappingProcessor implements MappingProcessor
+{
+ private MappingProcessor[] mappingProcessors;
+
+
+ /**
+ * Creates a new MultiMappingProcessor.
+ * @param mappingProcessors the mapping processors to which method calls
+ * will be delegated.
+ */
+ public MultiMappingProcessor(MappingProcessor[] mappingProcessors)
+ {
+ this.mappingProcessors = mappingProcessors;
+ }
+
+
+ // Implementations for MappingProcessor.
+
+ public boolean processClassFileMapping(String className,
+ String newClassName)
+ {
+ boolean result = false;
+
+ for (int index = 0; index < mappingProcessors.length; index++)
+ {
+ result |= mappingProcessors[index].processClassFileMapping(className,
+ newClassName);
+ }
+
+ return result;
+ }
+
+
+ public void processFieldMapping(String className,
+ String fieldType,
+ String fieldName,
+ String newFieldName)
+ {
+ for (int index = 0; index < mappingProcessors.length; index++)
+ {
+ mappingProcessors[index].processFieldMapping(className,
+ fieldType,
+ fieldName,
+ newFieldName);
+ }
+ }
+
+
+ public void processMethodMapping(String className,
+ int firstLineNumber,
+ int lastLineNumber,
+ String methodReturnType,
+ String methodNameAndArguments,
+ String newMethodName)
+ {
+ for (int index = 0; index < mappingProcessors.length; index++)
+ {
+ mappingProcessors[index].processMethodMapping(className,
+ firstLineNumber,
+ lastLineNumber,
+ methodReturnType,
+ methodNameAndArguments,
+ newMethodName);
+ }
+ }
+}
diff --git a/src/proguard/obfuscate/NameAndTypeShrinker.java b/src/proguard/obfuscate/NameAndTypeShrinker.java
new file mode 100644
index 0000000..ceccded
--- /dev/null
+++ b/src/proguard/obfuscate/NameAndTypeShrinker.java
@@ -0,0 +1,124 @@
+/* $Id: NameAndTypeShrinker.java,v 1.23 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.editor.ConstantPoolRemapper;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor removes NameAndType constant pool entries
+ * that are not marked as being used.
+ *
+ * @see NameAndTypeUsageMarker
+ *
+ * @author Eric Lafortune
+ */
+public class NameAndTypeShrinker implements ClassFileVisitor
+{
+ private int[] cpIndexMap;
+ private ConstantPoolRemapper constantPoolRemapper;
+
+
+ /**
+ * Creates a new NameAndTypeShrinker.
+ * @param codeLength an estimate of the maximum length of all the code that
+ * will be edited.
+ */
+ public NameAndTypeShrinker(int codeLength)
+ {
+ constantPoolRemapper = new ConstantPoolRemapper(codeLength);
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Shift the used constant pool entries together, filling out the
+ // index map.
+ programClassFile.u2constantPoolCount =
+ shrinkConstantPool(programClassFile.constantPool,
+ programClassFile.u2constantPoolCount);
+
+
+ // Remap all constant pool references.
+ constantPoolRemapper.setCpIndexMap(cpIndexMap);
+ constantPoolRemapper.visitProgramClassFile(programClassFile);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Removes all NameAndType entries that are not marked as being used
+ * from the given constant pool.
+ * @return the new number of entries.
+ */
+ private int shrinkConstantPool(CpInfo[] constantPool, int length)
+ {
+ // Create a new index map, if necessary.
+ if (cpIndexMap == null ||
+ cpIndexMap.length < length)
+ {
+ cpIndexMap = new int[length];
+ }
+
+ int counter = 1;
+ boolean isUsed = false;
+
+ // Shift the used constant pool entries together.
+ for (int index = 1; index < length; index++)
+ {
+ cpIndexMap[index] = counter;
+
+ CpInfo cpInfo = constantPool[index];
+
+ // Don't update the flag if this is the second half of a long entry.
+ if (cpInfo != null)
+ {
+ isUsed = cpInfo.getTag() != ClassConstants.CONSTANT_NameAndType ||
+ NameAndTypeUsageMarker.isUsed(cpInfo);
+ }
+
+ if (isUsed)
+ {
+ constantPool[counter++] = cpInfo;
+ }
+ }
+
+ // Clear the remaining constant pool elements.
+ for (int index = counter; index < length; index++)
+ {
+ constantPool[index] = null;
+ }
+
+ return counter;
+ }
+}
diff --git a/src/proguard/obfuscate/NameAndTypeUsageMarker.java b/src/proguard/obfuscate/NameAndTypeUsageMarker.java
new file mode 100644
index 0000000..578a9f0
--- /dev/null
+++ b/src/proguard/obfuscate/NameAndTypeUsageMarker.java
@@ -0,0 +1,160 @@
+/* $Id: NameAndTypeUsageMarker.java,v 1.13 2004/11/26 12:46:43 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassFileVisitor marks all NameAndType constant pool entries that are
+ * being used in the classes it visits.
+ *
+ * @see NameAndTypeShrinker
+ *
+ * @author Eric Lafortune
+ */
+public class NameAndTypeUsageMarker
+ implements ClassFileVisitor,
+ CpInfoVisitor,
+ AttrInfoVisitor
+{
+ // A visitor info flag to indicate the NameAndType constant pool entry is being used.
+ private static final Object USED = new Object();
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Mark the NameAndType entries referenced by all other constant pool
+ // entries.
+ programClassFile.constantPoolEntriesAccept(this);
+
+ // Mark the NameAndType entries referenced by all EnclosingMethod
+ // attributes.
+ programClassFile.attributesAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ visitRefCpInfo(classFile, fieldrefCpInfo);
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, interfaceMethodrefCpInfo);
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, methodrefCpInfo);
+ }
+
+
+ private void visitRefCpInfo(ClassFile classFile, RefCpInfo refCpInfo)
+ {
+ markNameAndTypeCpEntry(classFile, refCpInfo.u2nameAndTypeIndex);
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ if (enclosingMethodAttrInfo.u2nameAndTypeIndex != 0)
+ {
+ markNameAndTypeCpEntry(classFile, enclosingMethodAttrInfo.u2nameAndTypeIndex);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given UTF-8 constant pool entry of the given class.
+ */
+ private void markNameAndTypeCpEntry(ClassFile classFile, int index)
+ {
+ markAsUsed((NameAndTypeCpInfo)((ProgramClassFile)classFile).getCpEntry(index));
+ }
+
+
+ /**
+ * Marks the given VisitorAccepter as being used.
+ * In this context, the VisitorAccepter will be a NameAndTypeCpInfo object.
+ */
+ private static void markAsUsed(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(USED);
+ }
+
+
+ /**
+ * Returns whether the given VisitorAccepter has been marked as being used.
+ * In this context, the VisitorAccepter will be a NameAndTypeCpInfo object.
+ */
+ static boolean isUsed(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == USED;
+ }
+}
diff --git a/src/proguard/obfuscate/NameFactory.java b/src/proguard/obfuscate/NameFactory.java
new file mode 100644
index 0000000..0d06c5d
--- /dev/null
+++ b/src/proguard/obfuscate/NameFactory.java
@@ -0,0 +1,36 @@
+/* $Id: NameFactory.java,v 1.13 2004/11/01 21:17:51 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import java.util.*;
+
+/**
+ * This interfaces provides methods to generate unique sequences of names.
+ * The names must be valid Java identifiers.
+ *
+ * @author Eric Lafortune
+ */
+public interface NameFactory
+{
+ public void reset();
+
+ public String nextName();
+}
diff --git a/src/proguard/obfuscate/NameMarker.java b/src/proguard/obfuscate/NameMarker.java
new file mode 100644
index 0000000..ea359e9
--- /dev/null
+++ b/src/proguard/obfuscate/NameMarker.java
@@ -0,0 +1,78 @@
+/* $Id: NameMarker.java,v 1.14 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> and <code>MemberInfoVisitor</code>
+ * marks names of the class files and class members it visits. The marked names
+ * will remain unchanged in the obfuscation step.
+ *
+ * @see ClassFileObfuscator
+ * @see MemberInfoObfuscator
+ *
+ * @author Eric Lafortune
+ */
+public class NameMarker
+ implements ClassFileVisitor,
+ MemberInfoVisitor
+{
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Make sure the class name will be kept.
+ ClassFileObfuscator.setNewClassName(programClassFile,
+ programClassFile.getName());
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ // Make sure the class member name will be kept.
+ MemberInfoObfuscator.setNewMemberName(programMemberInfo,
+ programMemberInfo.getName(programClassFile));
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+}
diff --git a/src/proguard/obfuscate/ReadNameFactory.java b/src/proguard/obfuscate/ReadNameFactory.java
new file mode 100644
index 0000000..97ca12d
--- /dev/null
+++ b/src/proguard/obfuscate/ReadNameFactory.java
@@ -0,0 +1,171 @@
+/* $Id: ReadNameFactory.java,v 1.2 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This <code>NameFactory</code> generates names that are read from a
+ * specified input file.
+ * Comments (everything starting with '#' on a single line) are ignored.
+ *
+ * @author Eric Lafortune
+ */
+public class ReadNameFactory implements NameFactory
+{
+ private static final char COMMENT_CHARACTER = '#';
+
+
+ private final NameFactory nameFactory;
+ private final List names = new ArrayList();
+
+ private int index = 0;
+
+
+ /**
+ * Creates a new <code>ReadNameFactory</code>.
+ * @param fileName the name of the file from which the names can be read.
+ * @param nameFactory the name factory from which names will be retrieved
+ * if the list of read names has been exhausted.
+ */
+ public ReadNameFactory(String fileName,
+ NameFactory nameFactory) throws IOException
+ {
+ this.nameFactory = nameFactory;
+
+ Reader reader = new FileReader(fileName);
+
+ try
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ while (true)
+ {
+ // Read the next character.
+ int c = reader.read();
+
+ // Is it a valid identifier character?
+ if (c != -1 &&
+ (buffer.length() == 0 ?
+ Character.isJavaIdentifierStart((char)c) :
+ Character.isJavaIdentifierPart((char)c)))
+ {
+ // Append it to the current identifier.
+ buffer.append((char)c);
+ }
+ else
+ {
+ // Did we collect a new identifier?
+ if (buffer.length() > 0)
+ {
+ // Add the completed name to the list of names, if it's
+ // not in it yet.
+ String name = buffer.toString();
+ if (!names.contains(name))
+ {
+ names.add(name);
+ }
+
+ // Clear the buffer.
+ buffer.setLength(0);
+ }
+
+ // Is this the beginning of a comment line?
+ if (c == COMMENT_CHARACTER)
+ {
+ // Skip all characters till the end of the line.
+ do
+ {
+ c = reader.read();
+ }
+ while (c != -1 &&
+ c != '\n' &&
+ c != '\r');
+ }
+
+ // Is this the end of the file?
+ if (c == -1)
+ {
+ // Just return.
+ return;
+ }
+ }
+ }
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+
+
+ // Implementations for NameFactory.
+
+ public void reset()
+ {
+ index = 0;
+
+ nameFactory.reset();
+ }
+
+
+ public String nextName()
+ {
+ String name;
+
+ // Do we still have names?
+ if (index < names.size())
+ {
+ // Return the next name.
+ name = (String)names.get(index++);
+ }
+ else
+ {
+ // Return the next different name from the other name factory.
+ do
+ {
+ name = nameFactory.nextName();
+ }
+ while (names.contains(name));
+ }
+
+ return name;
+ }
+
+
+ public static void main(String[] args)
+ {
+ try
+ {
+ ReadNameFactory factory = new ReadNameFactory(args[0], new SimpleNameFactory());
+
+ for (int counter = 0; counter < 50; counter++)
+ {
+ System.out.println("["+factory.nextName()+"]");
+ }
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/obfuscate/SimpleNameFactory.java b/src/proguard/obfuscate/SimpleNameFactory.java
new file mode 100644
index 0000000..aae8e05
--- /dev/null
+++ b/src/proguard/obfuscate/SimpleNameFactory.java
@@ -0,0 +1,156 @@
+/* $Id: SimpleNameFactory.java,v 1.2 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import java.util.*;
+
+
+/**
+ * This <code>NameFactory</code> generates unique short names, using mixed-case
+ * characters or lower-case characters only.
+ *
+ * @author Eric Lafortune
+ */
+public class SimpleNameFactory implements NameFactory
+{
+ private static final int CHARACTER_COUNT = 26;
+
+ private static final List cachedMixedCaseNames = new ArrayList();
+ private static final List cachedLowerCaseNames = new ArrayList();
+
+ private boolean generateMixedCaseNames;
+ private int index = 0;
+
+
+ /**
+ * Creates a new <code>SimpleNameFactory</code> that generates mixed-case names.
+ */
+ public SimpleNameFactory()
+ {
+ this(true);
+ }
+
+
+ /**
+ * Creates a new <code>SimpleNameFactory</code>.
+ * @param generateMixedCaseNames a flag to indicate whether the generated
+ * names will be mixed-case, or lower-case only.
+ */
+ public SimpleNameFactory(boolean generateMixedCaseNames)
+ {
+ this.generateMixedCaseNames = generateMixedCaseNames;
+ }
+
+
+ // Implementations for NameFactory.
+
+ public void reset()
+ {
+ index = 0;
+ }
+
+
+ public String nextName()
+ {
+ return name(index++);
+ }
+
+
+ /**
+ * Returns the name at the given index.
+ */
+ private String name(int index)
+ {
+ // Which cache do we need?
+ List cachedNames = generateMixedCaseNames ?
+ cachedMixedCaseNames :
+ cachedLowerCaseNames;
+
+ // Do we have the name in the cache?
+ if (index < cachedNames.size())
+ {
+ return (String)cachedNames.get(index);
+ }
+
+ // Create a new name and cache it.
+ String name = newName(index);
+ cachedNames.add(index, name);
+
+ return name;
+ }
+
+
+ /**
+ * Creates and returns the name at the given index.
+ */
+ private String newName(int index)
+ {
+ // If we're allowed to generate mixed-case names, we can use twice as
+ // many characters.
+ int totalCharacterCount = generateMixedCaseNames ?
+ 2 * CHARACTER_COUNT :
+ CHARACTER_COUNT;
+
+ int baseIndex = index / totalCharacterCount;
+ int offset = index % totalCharacterCount;
+
+ char newChar = charAt(offset);
+
+ String newName = baseIndex == 0 ?
+ new String(new char[] { newChar }) :
+ (name(baseIndex-1) + newChar);
+
+ return newName;
+ }
+
+
+ /**
+ * Returns the character with the given index, between 0 and the number of
+ * acceptable characters.
+ */
+ private char charAt(int index)
+ {
+ return (char)((index < CHARACTER_COUNT ? 'a' - 0 :
+ 'A' - CHARACTER_COUNT) + index);
+ }
+
+
+ public static void main(String[] args)
+ {
+ System.out.println("Some mixed-case names:");
+ printNameSamples(new SimpleNameFactory(true), 60);
+ System.out.println("Some lower-case names:");
+ printNameSamples(new SimpleNameFactory(false), 60);
+ System.out.println("Some more mixed-case names:");
+ printNameSamples(new SimpleNameFactory(true), 80);
+ System.out.println("Some more lower-case names:");
+ printNameSamples(new SimpleNameFactory(false), 80);
+ }
+
+
+ private static void printNameSamples(SimpleNameFactory factory, int count)
+ {
+ for (int counter = 0; counter < count; counter++)
+ {
+ System.out.println(" ["+factory.nextName()+"]");
+ }
+ }
+}
diff --git a/src/proguard/obfuscate/Utf8Shrinker.java b/src/proguard/obfuscate/Utf8Shrinker.java
new file mode 100644
index 0000000..e01bbce
--- /dev/null
+++ b/src/proguard/obfuscate/Utf8Shrinker.java
@@ -0,0 +1,121 @@
+/* $Id: Utf8Shrinker.java,v 1.26 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.editor.ConstantPoolRemapper;
+import proguard.classfile.visitor.ClassFileVisitor;
+
+
+/**
+ * This ClassFileVisitor removes UTF-8 constant pool entries that are not marked
+ * as being used.
+ *
+ * @see Utf8UsageMarker
+ *
+ * @author Eric Lafortune
+ */
+public class Utf8Shrinker implements ClassFileVisitor
+{
+ private int[] cpIndexMap;
+ private ConstantPoolRemapper constantPoolRemapper;
+
+
+ /**
+ * Creates a new Utf8Shrinker.
+ * @param codeLength an estimate of the maximum length of all the code that
+ * will be edited.
+ */
+ public Utf8Shrinker(int codeLength)
+ {
+ constantPoolRemapper = new ConstantPoolRemapper(codeLength);
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Shift the used constant pool entries together, filling out the
+ // index map.
+ programClassFile.u2constantPoolCount =
+ shrinkConstantPool(programClassFile.constantPool,
+ programClassFile.u2constantPoolCount);
+
+ // Remap all constant pool references.
+ constantPoolRemapper.setCpIndexMap(cpIndexMap);
+ constantPoolRemapper.visitProgramClassFile(programClassFile);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Removes all UTF-8 entries that are not marked as being used
+ * from the given constant pool.
+ * @return the new number of entries.
+ */
+ private int shrinkConstantPool(CpInfo[] constantPool, int length)
+ {
+ // Create a new index map, if necessary.
+ if (cpIndexMap == null ||
+ cpIndexMap.length < length)
+ {
+ cpIndexMap = new int[length];
+ }
+
+ int counter = 1;
+ boolean isUsed = false;
+
+ // Shift the used constant pool entries together.
+ for (int index = 1; index < length; index++)
+ {
+ cpIndexMap[index] = counter;
+
+ CpInfo cpInfo = constantPool[index];
+
+ // Don't update the flag if this is the second half of a long entry.
+ if (cpInfo != null)
+ {
+ isUsed = cpInfo.getTag() != ClassConstants.CONSTANT_Utf8 ||
+ Utf8UsageMarker.isUsed(cpInfo);
+ }
+
+ if (isUsed)
+ {
+ constantPool[counter++] = cpInfo;
+ }
+ }
+
+ // Clear the remaining constant pool elements.
+ for (int index = counter; index < length; index++)
+ {
+ constantPool[index] = null;
+ }
+
+ return counter;
+ }
+}
diff --git a/src/proguard/obfuscate/Utf8UsageMarker.java b/src/proguard/obfuscate/Utf8UsageMarker.java
new file mode 100644
index 0000000..f34abf0
--- /dev/null
+++ b/src/proguard/obfuscate/Utf8UsageMarker.java
@@ -0,0 +1,419 @@
+/* $Id: Utf8UsageMarker.java,v 1.22 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassFileVisitor marks all UTF-8 constant pool entries that are
+ * being used in the classes it visits.
+ *
+ * @see Utf8Shrinker
+ *
+ * @author Eric Lafortune
+ */
+public class Utf8UsageMarker
+ implements ClassFileVisitor,
+ MemberInfoVisitor,
+ CpInfoVisitor,
+ AttrInfoVisitor,
+ InnerClassesInfoVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor
+{
+ // A visitor info flag to indicate the UTF-8 constant pool entry is being used.
+ private static final Object USED = new Object();
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Mark the UTF-8 entries referenced by the other constant pool entries.
+ programClassFile.constantPoolEntriesAccept(this);
+
+ // Mark the UTF-8 entries referenced by the fields and methods.
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+
+ // Mark the UTF-8 entries referenced by the attributes.
+ programClassFile.attributesAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ // Mark the name and descriptor UTF-8 entries.
+ markCpUtf8Entry(programClassFile, programMemberInfo.u2nameIndex);
+ markCpUtf8Entry(programClassFile, programMemberInfo.u2descriptorIndex);
+
+ // Mark the UTF-8 entries referenced by the attributes.
+ programMemberInfo.attributesAccept(programClassFile, this);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ markCpUtf8Entry(classFile, stringCpInfo.u2stringIndex);
+ }
+
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ markCpUtf8Entry(classFile, classCpInfo.u2nameIndex);
+ }
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ markCpUtf8Entry(classFile, nameAndTypeCpInfo.u2nameIndex);
+ markCpUtf8Entry(classFile, nameAndTypeCpInfo.u2descriptorIndex);
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo)
+ {
+ // This is the best we can do for unknown attributes.
+ markCpUtf8Entry(classFile, unknownAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ markCpUtf8Entry(classFile, innerClassesAttrInfo.u2attrNameIndex);
+
+ // Mark the UTF-8 entries referenced by the inner classes.
+ innerClassesAttrInfo.innerClassEntriesAccept(classFile, this);
+ }
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ markCpUtf8Entry(classFile, enclosingMethodAttrInfo.u2attrNameIndex);
+
+ // These entries have already been marked in the constant pool.
+ //classFile.constantPoolEntryAccept(this, enclosingMethodAttrInfo.u2classIndex);
+ //classFile.constantPoolEntryAccept(this, enclosingMethodAttrInfo.u2nameAndTypeIndex);
+ }
+
+
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo)
+ {
+ markCpUtf8Entry(classFile, constantValueAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo)
+ {
+ markCpUtf8Entry(classFile, exceptionsAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ markCpUtf8Entry(classFile, codeAttrInfo.u2attrNameIndex);
+
+ // Mark the UTF-8 entries referenced by the attributes.
+ codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+ }
+
+
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo)
+ {
+ markCpUtf8Entry(classFile, lineNumberTableAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ markCpUtf8Entry(classFile, localVariableTableAttrInfo.u2attrNameIndex);
+
+ // Mark the UTF-8 entries referenced by the local variables.
+ localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ markCpUtf8Entry(classFile, localVariableTypeTableAttrInfo.u2attrNameIndex);
+
+ // Mark the UTF-8 entries referenced by the local variable types.
+ localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+ {
+ markCpUtf8Entry(classFile, sourceFileAttrInfo.u2attrNameIndex);
+
+ markCpUtf8Entry(classFile, sourceFileAttrInfo.u2sourceFileIndex);
+ }
+
+
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
+ {
+ markCpUtf8Entry(classFile, sourceDirAttrInfo.u2attrNameIndex);
+
+ markCpUtf8Entry(classFile, sourceDirAttrInfo.u2sourceDirIndex);
+ }
+
+
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo)
+ {
+ markCpUtf8Entry(classFile, deprecatedAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo)
+ {
+ markCpUtf8Entry(classFile, syntheticAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ markCpUtf8Entry(classFile, signatureAttrInfo.u2attrNameIndex);
+
+ markCpUtf8Entry(classFile, signatureAttrInfo.u2signatureIndex);
+ }
+
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ markCpUtf8Entry(classFile, runtimeVisibleAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Mark the UTF-8 entries referenced by the annotations.
+ runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ markCpUtf8Entry(classFile, runtimeInvisibleAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Mark the UTF-8 entries referenced by the annotations.
+ runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ markCpUtf8Entry(classFile, runtimeVisibleParameterAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Mark the UTF-8 entries referenced by the annotations.
+ runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ markCpUtf8Entry(classFile, runtimeInvisibleParameterAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Mark the UTF-8 entries referenced by the annotations.
+ runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ markCpUtf8Entry(classFile, annotationDefaultAttrInfo.u2attrNameIndex);
+
+ // Mark the UTF-8 entries referenced by the element value.
+ annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(ClassFile classFile, InnerClassesInfo innerClassesInfo)
+ {
+ if (innerClassesInfo.u2innerNameIndex != 0)
+ {
+ markCpUtf8Entry(classFile, innerClassesInfo.u2innerNameIndex);
+ }
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+ {
+ markCpUtf8Entry(classFile, localVariableInfo.u2nameIndex);
+ markCpUtf8Entry(classFile, localVariableInfo.u2descriptorIndex);
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ markCpUtf8Entry(classFile, localVariableTypeInfo.u2nameIndex);
+ markCpUtf8Entry(classFile, localVariableTypeInfo.u2signatureIndex);
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(ClassFile classFile, Annotation annotation)
+ {
+ markCpUtf8Entry(classFile, annotation.u2typeIndex);
+
+ // Mark the UTF-8 entries referenced by the element values.
+ annotation.elementValuesAccept(classFile, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ if (constantElementValue.u2elementName != 0)
+ {
+ markCpUtf8Entry(classFile, constantElementValue.u2elementName);
+ }
+
+ // Only the string constant element value refers to a UTF-8 entry.
+ if (constantElementValue.u1tag == ClassConstants.ELEMENT_VALUE_STRING_CONSTANT)
+ {
+ markCpUtf8Entry(classFile, constantElementValue.u2constantValueIndex);
+ }
+ }
+
+
+ public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ if (enumConstantElementValue.u2elementName != 0)
+ {
+ markCpUtf8Entry(classFile, enumConstantElementValue.u2elementName);
+ }
+
+ markCpUtf8Entry(classFile, enumConstantElementValue.u2typeNameIndex);
+ markCpUtf8Entry(classFile, enumConstantElementValue.u2constantNameIndex);
+ }
+
+
+ public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
+ {
+ if (classElementValue.u2elementName != 0)
+ {
+ markCpUtf8Entry(classFile, classElementValue.u2elementName);
+ }
+
+ markCpUtf8Entry(classFile, classElementValue.u2classInfoIndex);
+ }
+
+
+ public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ if (annotationElementValue.u2elementName != 0)
+ {
+ markCpUtf8Entry(classFile, annotationElementValue.u2elementName);
+ }
+
+ // Mark the UTF-8 entries referenced by the annotation.
+ annotationElementValue.annotationAccept(classFile, this);
+ }
+
+
+ public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ if (arrayElementValue.u2elementName != 0)
+ {
+ markCpUtf8Entry(classFile, arrayElementValue.u2elementName);
+ }
+
+ // Mark the UTF-8 entries referenced by the element values.
+ arrayElementValue.elementValuesAccept(classFile, annotation, this);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given UTF-8 constant pool entry of the given class.
+ */
+ private void markCpUtf8Entry(ClassFile classFile, int index)
+ {
+ markAsUsed((Utf8CpInfo)((ProgramClassFile)classFile).getCpEntry(index));
+ }
+
+
+ /**
+ * Marks the given VisitorAccepter as being used.
+ * In this context, the VisitorAccepter will be a Utf8CpInfo object.
+ */
+ private static void markAsUsed(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(USED);
+ }
+
+
+ /**
+ * Returns whether the given VisitorAccepter has been marked as being used.
+ * In this context, the VisitorAccepter will be a Utf8CpInfo object.
+ */
+ static boolean isUsed(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == USED;
+ }
+}
diff --git a/src/proguard/obfuscate/package.html b/src/proguard/obfuscate/package.html
new file mode 100644
index 0000000..a82d266
--- /dev/null
+++ b/src/proguard/obfuscate/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains classes to perform obfuscation of class files.
+</body>
diff --git a/src/proguard/optimize/ChangedCodePrinter.java b/src/proguard/optimize/ChangedCodePrinter.java
new file mode 100644
index 0000000..ab6875a
--- /dev/null
+++ b/src/proguard/optimize/ChangedCodePrinter.java
@@ -0,0 +1,203 @@
+/* $Id: ChangedCodePrinter.java,v 1.6 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.util.ClassUtil;
+import proguard.classfile.visitor.*;
+
+/**
+ * This AttrInfoVisitor delegates its call to another AttrInfoVisitor, and
+ * prints out the code if the other visitor has changed it.
+ *
+ * @author Eric Lafortune
+ */
+public class ChangedCodePrinter implements AttrInfoVisitor
+{
+ private AttrInfoVisitor attrInfoVisitor;
+
+
+ public ChangedCodePrinter(AttrInfoVisitor attrInfoVisitor)
+ {
+ this.attrInfoVisitor = attrInfoVisitor;
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo)
+ {
+ attrInfoVisitor.visitUnknownAttrInfo(classFile, unknownAttrInfo);
+ }
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ attrInfoVisitor.visitInnerClassesAttrInfo(classFile, innerClassesAttrInfo);
+ }
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ attrInfoVisitor.visitEnclosingMethodAttrInfo(classFile, enclosingMethodAttrInfo);
+ }
+
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo)
+ {
+ attrInfoVisitor.visitConstantValueAttrInfo(classFile, fieldInfo, constantValueAttrInfo);
+ }
+
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo)
+ {
+ attrInfoVisitor.visitExceptionsAttrInfo(classFile, methodInfo, exceptionsAttrInfo);
+ }
+
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo)
+ {
+ attrInfoVisitor.visitLineNumberTableAttrInfo(classFile, methodInfo, codeAttrInfo, lineNumberTableAttrInfo);
+ }
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ attrInfoVisitor.visitLocalVariableTableAttrInfo(classFile, methodInfo, codeAttrInfo, localVariableTableAttrInfo);
+ }
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ attrInfoVisitor.visitLocalVariableTypeTableAttrInfo(classFile, methodInfo, codeAttrInfo, localVariableTypeTableAttrInfo);
+ }
+
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+ {
+ attrInfoVisitor.visitSourceFileAttrInfo(classFile, sourceFileAttrInfo);
+ }
+
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
+ {
+ attrInfoVisitor.visitSourceDirAttrInfo(classFile, sourceDirAttrInfo);
+ }
+
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo)
+ {
+ attrInfoVisitor.visitDeprecatedAttrInfo(classFile, deprecatedAttrInfo);
+ }
+
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo)
+ {
+ attrInfoVisitor.visitSyntheticAttrInfo(classFile, syntheticAttrInfo);
+ }
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ attrInfoVisitor.visitSignatureAttrInfo(classFile, signatureAttrInfo);
+ }
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ attrInfoVisitor.visitRuntimeVisibleAnnotationAttrInfo(classFile, runtimeVisibleAnnotationsAttrInfo);
+ }
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ attrInfoVisitor.visitRuntimeInvisibleAnnotationAttrInfo(classFile, runtimeInvisibleAnnotationsAttrInfo);
+ }
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ attrInfoVisitor.visitRuntimeVisibleParameterAnnotationAttrInfo(classFile, runtimeVisibleParameterAnnotationsAttrInfo);
+ }
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ attrInfoVisitor.visitRuntimeInvisibleParameterAnnotationAttrInfo(classFile, runtimeInvisibleParameterAnnotationsAttrInfo);
+ }
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ attrInfoVisitor.visitAnnotationDefaultAttrInfo(classFile, annotationDefaultAttrInfo);
+ }
+
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ byte[] code = codeAttrInfo.code;
+ byte[] oldCode = new byte[code.length];
+
+ // Copy the current code.
+ for (int index = 0; index < codeAttrInfo.u4codeLength; index++)
+ {
+ oldCode[index] = code[index];
+ }
+
+ // Delegate to the real visitor.
+ attrInfoVisitor.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
+
+ // Check if the code has changed.
+ if (codeHasChanged(codeAttrInfo, oldCode))
+ {
+ printChangedCode(classFile, methodInfo, codeAttrInfo, oldCode);
+ }
+ }
+
+
+ // Small utility methods.
+
+ private boolean codeHasChanged(CodeAttrInfo codeAttrInfo, byte[] oldCode)
+ {
+ if (oldCode.length != codeAttrInfo.u4codeLength)
+ {
+ return true;
+ }
+
+ for (int index = 0; index < codeAttrInfo.u4codeLength; index++)
+ {
+ if (oldCode[index] != codeAttrInfo.code[index])
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ private void printChangedCode(ClassFile classFile,
+ MethodInfo methodInfo,
+ CodeAttrInfo codeAttrInfo,
+ byte[] oldCode)
+ {
+ System.out.println("Class "+ClassUtil.externalClassName(classFile.getName()));
+ System.out.println("Method "+ClassUtil.externalFullMethodDescription(classFile.getName(),
+ 0,
+ methodInfo.getName(classFile),
+ methodInfo.getDescriptor(classFile)));
+
+ for (int index = 0; index < codeAttrInfo.u4codeLength; index++)
+ {
+ System.out.println(
+ (oldCode[index] == codeAttrInfo.code[index]? " -- ":" => ")+
+ index+": "+
+ Integer.toHexString(0x100|oldCode[index] &0xff).substring(1)+" "+
+ Integer.toHexString(0x100|codeAttrInfo.code[index]&0xff).substring(1));
+ }
+ }
+}
diff --git a/src/proguard/optimize/KeepMarker.java b/src/proguard/optimize/KeepMarker.java
new file mode 100644
index 0000000..1f5a52e
--- /dev/null
+++ b/src/proguard/optimize/KeepMarker.java
@@ -0,0 +1,92 @@
+/* $Id: KeepMarker.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This <code>ClassFileVisitor</code> and <code>MemberInfoVisitor</code>
+ * marks class files and class members it visits. The marked elements
+ * will remain unchanged as necessary in the optimization step.
+ *
+ * @author Eric Lafortune
+ */
+public class KeepMarker
+ implements ClassFileVisitor,
+ MemberInfoVisitor
+{
+ // A visitor info flag to indicate the visitor accepter is being kept.
+ private static final Object KEPT = new Object();
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Make sure the class will be kept.
+ markAsKept(programClassFile);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ // Make sure the class member will be kept.
+ markAsKept(programMemberInfo);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Small utility methods.
+
+ public static void markAsKept(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(KEPT);
+ }
+
+
+ public static boolean isKept(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter == null ||
+ visitorAccepter.getVisitorInfo() == KEPT;
+ }
+}
diff --git a/src/proguard/optimize/NoSideEffectMethodMarker.java b/src/proguard/optimize/NoSideEffectMethodMarker.java
new file mode 100644
index 0000000..2b69044
--- /dev/null
+++ b/src/proguard/optimize/NoSideEffectMethodMarker.java
@@ -0,0 +1,74 @@
+/* $Id: NoSideEffectMethodMarker.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This MemberInfoVisitor marks all methods that it visits as not having any side
+ * effects. It will make the SideEffectMethodMarker consider them as such
+ * without further analysis.
+ *
+ * @see SideEffectMethodMarker
+ * @author Eric Lafortune
+ */
+public class NoSideEffectMethodMarker
+ implements MemberInfoVisitor
+{
+ // A visitor info flag to indicate that a MethodInfo object doesn't have
+ // anyside effects.
+ private static final Object NO_SIDE_EFFECTS = new Object();
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ markAsNoSideEffects(programMethodInfo);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ markAsNoSideEffects(libraryMethodInfo);
+ }
+
+
+ // Small utility methods.
+
+ public static void markAsNoSideEffects(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(NO_SIDE_EFFECTS);
+ }
+
+
+ public static boolean hasNoSideEffects(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter != null &&
+ visitorAccepter.getVisitorInfo() == NO_SIDE_EFFECTS;
+ }
+}
diff --git a/src/proguard/optimize/SideEffectInstructionChecker.java b/src/proguard/optimize/SideEffectInstructionChecker.java
new file mode 100644
index 0000000..ae7d569
--- /dev/null
+++ b/src/proguard/optimize/SideEffectInstructionChecker.java
@@ -0,0 +1,246 @@
+/* $Id: SideEffectInstructionChecker.java,v 1.8 2004/12/11 20:10:10 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This class can tell whether an instruction has any side effects. Return
+ * instructions can be included or not.
+ *
+ * @see WriteOnlyFieldMarker
+ * @see NoSideEffectMethodMarker
+ * @see SideEffectMethodMarker
+ * @author Eric Lafortune
+ */
+public class SideEffectInstructionChecker
+ implements InstructionVisitor,
+ CpInfoVisitor,
+ MemberInfoVisitor
+{
+ private boolean includeReturnInstructions;
+
+ // Parameters and values for visitor methods.
+ private boolean hasSideEffects;
+ private boolean virtual;
+
+
+ public SideEffectInstructionChecker(boolean includeReturnInstructions)
+ {
+ this.includeReturnInstructions = includeReturnInstructions;
+ }
+
+
+ public boolean hasSideEffects(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, Instruction instruction)
+ {
+ hasSideEffects = false;
+
+ instruction.accept(classFile, methodInfo, codeAttrInfo, offset, this);
+
+ return hasSideEffects;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
+ {
+ byte opcode = simpleInstruction.opcode;
+
+ // Check for instructions that might cause side effects.
+ if (opcode == InstructionConstants.OP_IASTORE ||
+ opcode == InstructionConstants.OP_LASTORE ||
+ opcode == InstructionConstants.OP_FASTORE ||
+ opcode == InstructionConstants.OP_DASTORE ||
+ opcode == InstructionConstants.OP_AASTORE ||
+ opcode == InstructionConstants.OP_BASTORE ||
+ opcode == InstructionConstants.OP_CASTORE ||
+ opcode == InstructionConstants.OP_SASTORE ||
+ opcode == InstructionConstants.OP_ATHROW ||
+ opcode == InstructionConstants.OP_MONITORENTER ||
+ opcode == InstructionConstants.OP_MONITOREXIT ||
+ (includeReturnInstructions &&
+ (opcode == InstructionConstants.OP_IRETURN ||
+ opcode == InstructionConstants.OP_LRETURN ||
+ opcode == InstructionConstants.OP_FRETURN ||
+ opcode == InstructionConstants.OP_DRETURN ||
+ opcode == InstructionConstants.OP_ARETURN ||
+ opcode == InstructionConstants.OP_RETURN))) {
+
+ // These instructions always cause a side effect.
+ hasSideEffects = true;
+ }
+
+ }
+
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ byte opcode = variableInstruction.opcode;
+
+ // Check for instructions that might cause side effects.
+ if (includeReturnInstructions &&
+ opcode == InstructionConstants.OP_RET)
+ {
+ hasSideEffects = true;
+ }
+ }
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ byte opcode = cpInstruction.opcode;
+
+ // Check for instructions that might cause side effects.
+ if (opcode == InstructionConstants.OP_PUTSTATIC ||
+ opcode == InstructionConstants.OP_PUTFIELD)
+ {
+ // Check if the field is write-only.
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+ }
+ else if (opcode == InstructionConstants.OP_INVOKESPECIAL ||
+ opcode == InstructionConstants.OP_INVOKESTATIC)
+ {
+ // Check if the invoked method is causing any side effects.
+ virtual = false;
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+ }
+ else if (opcode == InstructionConstants.OP_INVOKEVIRTUAL ||
+ opcode == InstructionConstants.OP_INVOKEINTERFACE)
+ {
+ // Check if the invoked method is causing any side effects.
+ virtual = true;
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ hasSideEffects = !WriteOnlyFieldMarker.isWriteOnly(fieldrefCpInfo.referencedMemberInfo);
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ // Do we have a reference to the interface method?
+ if (interfaceMethodrefCpInfo.referencedMemberInfo == null)
+ {
+ // We'll have to assume the unknown interface method has side effects.
+ hasSideEffects = true;
+ }
+ else
+ {
+ // First check the referenced interface method itself.
+ interfaceMethodrefCpInfo.referencedMemberInfoAccept(this);
+
+ // If the result isn't conclusive, check up and down the hierarchy.
+ if (!hasSideEffects)
+ {
+ String name = interfaceMethodrefCpInfo.getName(classFile);
+ String type = interfaceMethodrefCpInfo.getType(classFile);
+
+ // Check all implementations of the method.
+ // First go to all concrete classes of the interface.
+ // From there, travel up and down the class hierarchy to check
+ // the method.
+ //
+ // This way, we're also catching retro-fitted interfaces, where
+ // a class's implementation of an interface method is hiding
+ // higher up its class hierarchy.
+ interfaceMethodrefCpInfo.referencedClassAccept(
+ new ConcreteClassFileDownTraveler(
+ new ClassFileHierarchyTraveler(true, true, false, true,
+ new NamedMethodVisitor(name, type, this))));
+ }
+ }
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ // Do we have a reference to the method?
+ if (methodrefCpInfo.referencedMemberInfo == null)
+ {
+ // We'll have to assume the unknown method has side effects.
+ hasSideEffects = true;
+ }
+ else
+ {
+ // First check the referenced method itself.
+ methodrefCpInfo.referencedMemberInfoAccept(this);
+
+ // If the result isn't conclusive, check down the hierarchy.
+ if (!hasSideEffects &&
+ virtual)
+ {
+ String name = methodrefCpInfo.getName(classFile);
+ String type = methodrefCpInfo.getType(classFile);
+
+ // Check all overriding implementations of the method,
+ // down the class hierarchy.
+ methodrefCpInfo.referencedClassAccept(
+ new ClassFileHierarchyTraveler(false, false, false, true,
+ new NamedMethodVisitor(name, type, this)));
+ }
+ }
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ hasSideEffects = hasSideEffects ||
+ SideEffectMethodMarker.hasSideEffects(programMethodInfo);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ hasSideEffects = hasSideEffects ||
+ !NoSideEffectMethodMarker.hasNoSideEffects(libraryMethodInfo);
+ }
+}
diff --git a/src/proguard/optimize/SideEffectMethodMarker.java b/src/proguard/optimize/SideEffectMethodMarker.java
new file mode 100644
index 0000000..982500c
--- /dev/null
+++ b/src/proguard/optimize/SideEffectMethodMarker.java
@@ -0,0 +1,172 @@
+/* $Id: SideEffectMethodMarker.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassPoolVisitor marks all methods that have side effects.
+ *
+ * @see WriteOnlyFieldMarker
+ * @see NoSideEffectMethodMarker
+ * @author Eric Lafortune
+ */
+public class SideEffectMethodMarker
+ implements ClassPoolVisitor,
+ ClassFileVisitor,
+ MemberInfoVisitor,
+ AttrInfoVisitor
+{
+ // A visitor info flag to indicate that a MethodInfo object has side effects.
+ private static final Object SIDE_EFFECTS = new Object();
+
+
+ // A reusable object for checking whether instructions have side effects.
+ private SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(false);
+
+ // Parameters and values for visitor methods.
+ private int newSideEffectCount;
+ private boolean hasSideEffects;
+
+
+ // Implementations for ClassPoolVisitor.
+
+ public void visitClassPool(ClassPool classPool)
+ {
+ // Go over all class files and their methods, marking if they have side
+ // effects, until no new cases can be found.
+ do
+ {
+ newSideEffectCount = 0;
+
+ // Go over all class files and their methods once.
+ classPool.classFilesAccept(this);
+ }
+ while (newSideEffectCount > 0);
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Go over all methods.
+ programClassFile.methodsAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ if (!hasSideEffects(programMethodInfo) &&
+ !NoSideEffectMethodMarker.hasNoSideEffects(programMethodInfo))
+ {
+ // Set the return value, in case the method doesn't have a code
+ // attribute (a native method or an abstract method).
+ hasSideEffects = (programMethodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_NATIVE) != 0;
+
+ programMethodInfo.attributesAccept(programClassFile, this);
+
+ // Mark the method depending on the return value.
+ if (hasSideEffects)
+ {
+ markAsSideEffects(programMethodInfo);
+
+ newSideEffectCount++;
+ }
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ byte[] code = codeAttrInfo.code;
+ int length = codeAttrInfo.u4codeLength;
+
+ // Go over all instructions.
+ int offset = 0;
+ do
+ {
+ // Get the current instruction.
+ Instruction instruction = InstructionFactory.create(code, offset);
+
+ // Check if it is causing any side effects.
+ hasSideEffects = sideEffectInstructionChecker.hasSideEffects(classFile, methodInfo, codeAttrInfo, offset, instruction);
+
+ // Go to the next instruction.
+ offset += instruction.length(offset);
+ }
+ while (offset < length && !hasSideEffects);
+ }
+
+
+ // Small utility methods.
+
+ public static void markAsSideEffects(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(SIDE_EFFECTS);
+ }
+
+
+ public static boolean hasSideEffects(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter == null ||
+ visitorAccepter.getVisitorInfo() == SIDE_EFFECTS ||
+ KeepMarker.isKept(visitorAccepter);
+ }
+}
diff --git a/src/proguard/optimize/WriteOnlyFieldMarker.java b/src/proguard/optimize/WriteOnlyFieldMarker.java
new file mode 100644
index 0000000..5d7e773
--- /dev/null
+++ b/src/proguard/optimize/WriteOnlyFieldMarker.java
@@ -0,0 +1,158 @@
+/* $Id: WriteOnlyFieldMarker.java,v 1.5 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This InstructionVisitor marks all fields that are write-only.
+ *
+ * @author Eric Lafortune
+ */
+public class WriteOnlyFieldMarker
+ implements InstructionVisitor,
+ CpInfoVisitor,
+ MemberInfoVisitor
+{
+ // Visitor info flags to indicate whether a FieldInfo object is write-only.
+ private static final Object READ = new Object();
+ private static final Object WRITE_ONLY = new Object();
+
+
+ // Parameters and values for visitor methods.
+ private boolean reading;
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ byte opcode = cpInstruction.opcode;
+
+ // Check for instructions that involve fields.
+ if (opcode == InstructionConstants.OP_GETSTATIC ||
+ opcode == InstructionConstants.OP_GETFIELD)
+ {
+ // Mark the field as being read from.
+ reading = true;
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+ }
+ else if (opcode == InstructionConstants.OP_PUTSTATIC ||
+ opcode == InstructionConstants.OP_PUTFIELD)
+ {
+ // Mark the field as being written to.
+ reading = false;
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ MemberInfo referencedMemberInfo = fieldrefCpInfo.referencedMemberInfo;
+
+ if (referencedMemberInfo != null)
+ {
+ referencedMemberInfo.accept(fieldrefCpInfo.referencedClassFile, this);
+ }
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ // Hasn't the field been marked as being read yet?
+ if (!isRead(programFieldInfo))
+ {
+ // Mark it now, depending on whther this is a reading operation
+ // or a writing operation.
+ if (reading)
+ {
+ markAsRead(programFieldInfo);
+ }
+ else
+ {
+ markAsWriteOnly(programFieldInfo);
+ }
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo) {}
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Small utility methods.
+
+ private static void markAsRead(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(READ);
+ }
+
+
+ private static boolean isRead(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter == null ||
+ visitorAccepter.getVisitorInfo() == READ ||
+ KeepMarker.isKept(visitorAccepter);
+ }
+
+
+ public static void markAsWriteOnly(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(WRITE_ONLY);
+ }
+
+
+ public static boolean isWriteOnly(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter != null &&
+ visitorAccepter.getVisitorInfo() == WRITE_ONLY &&
+ !KeepMarker.isKept(visitorAccepter);
+ }
+}
diff --git a/src/proguard/optimize/evaluation/BranchUnit.java b/src/proguard/optimize/evaluation/BranchUnit.java
new file mode 100644
index 0000000..e2f405d
--- /dev/null
+++ b/src/proguard/optimize/evaluation/BranchUnit.java
@@ -0,0 +1,64 @@
+/* $Id: BranchUnit.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.optimize.evaluation.value.*;
+
+/**
+ * This InstructionVisitor evaluates the instructions that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public interface BranchUnit
+{
+ /**
+ * Sets the new instruction offset.
+ */
+ public void branch(ClassFile classFile,
+ CodeAttrInfo codeAttrInfo,
+ int offset,
+ int branchTarget);
+
+
+ /**
+ * Sets the new instruction offset, depending on the certainty of the
+ * conditional branch.
+ */
+ public void branchConditionally(ClassFile classFile,
+ CodeAttrInfo codeAttrInfo,
+ int offset,
+ int branchTarget,
+ int conditional);
+
+
+ /**
+ * Returns from the method with the given value.
+ */
+ public void returnFromMethod(Value returnValue);
+
+
+ /**
+ * Handles the throwing of an exception.
+ */
+ public void throwException();
+}
diff --git a/src/proguard/optimize/evaluation/PartialEvaluator.java b/src/proguard/optimize/evaluation/PartialEvaluator.java
new file mode 100644
index 0000000..766ae68
--- /dev/null
+++ b/src/proguard/optimize/evaluation/PartialEvaluator.java
@@ -0,0 +1,2016 @@
+/* $Id: PartialEvaluator.java,v 1.26 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.optimize.*;
+import proguard.optimize.evaluation.value.*;
+
+/**
+ * This MemberInfoVisitor performs partial evaluation on the program methods
+ * that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class PartialEvaluator
+implements MemberInfoVisitor,
+ AttrInfoVisitor,
+ ExceptionInfoVisitor,
+ InstructionVisitor,
+ CpInfoVisitor
+{
+ //*
+ private static final boolean DEBUG_RESULTS = false;
+ private static final boolean DEBUG_ANALYSIS = false;
+ private static final boolean DEBUG = false;
+ /*/
+ private static boolean DEBUG_RESULTS = true;
+ private static boolean DEBUG_ANALYSIS = true;
+ private static boolean DEBUG = true;
+ //*/
+
+ private static final int INITIAL_CODE_LENGTH = 1024;
+ private static final int INITIAL_VALUE_COUNT = 32;
+
+ private static final int MAXIMUM_EVALUATION_COUNT = 100;
+
+
+ private InstructionOffsetValue[] varTraceValues = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
+ private InstructionOffsetValue[] stackTraceValues = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
+ private InstructionOffsetValue[] branchOriginValues = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
+ private InstructionOffsetValue[] branchTargetValues = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
+ private TracedVariables[] vars = new TracedVariables[INITIAL_CODE_LENGTH];
+ private TracedStack[] stacks = new TracedStack[INITIAL_CODE_LENGTH];
+ private int[] evaluationCounts = new int[INITIAL_CODE_LENGTH];
+ private boolean[] initialization = new boolean[INITIAL_CODE_LENGTH];
+ private boolean[] isNecessary = new boolean[INITIAL_CODE_LENGTH];
+ private boolean evaluateExceptions;
+
+ private TracedVariables parameters = new TracedVariables(INITIAL_VALUE_COUNT);
+ private TracedVariables variables = new TracedVariables(INITIAL_VALUE_COUNT);
+ private TracedStack stack = new TracedStack(INITIAL_VALUE_COUNT);
+ private TracedBranchUnit branchUnit = new TracedBranchUnit();
+
+ private ClassFileCleaner classFileCleaner = new ClassFileCleaner();
+ private SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true);
+ private CodeAttrInfoEditor codeAttrInfoEditor = new CodeAttrInfoEditor(INITIAL_CODE_LENGTH);
+
+ private boolean isInitializer;
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+// DEBUG = DEBUG_ANALYSIS = DEBUG_RESULTS =
+// programClassFile.getName().equals("abc/Def") &&
+// programMethodInfo.getName(programClassFile).equals("abc");
+
+ // Initialize the parameters.
+ boolean isStatic =
+ (programMethodInfo.u2accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0;
+
+ // Count the number of parameters, taking into account their Categories.
+ String parameterDescriptor = programMethodInfo.getDescriptor(programClassFile);
+ int count = (isStatic ? 0 : 1) +
+ ClassUtil.internalMethodParameterSize(parameterDescriptor);
+
+ // Reuse the existing parameters object, ensuring the right size.
+ parameters.reset(count);
+
+ // Go over the parameters again.
+ InternalTypeEnumeration internalTypeEnumeration =
+ new InternalTypeEnumeration(parameterDescriptor);
+
+ int index = 0;
+
+ // Clear the store value of each parameter.
+ parameters.setStoreValue(InstructionOffsetValueFactory.create());
+
+ // Put the caller's reference in parameter 0.
+ if (!isStatic)
+ {
+ parameters.store(index++, ReferenceValueFactory.create(false));
+ }
+
+ while (internalTypeEnumeration.hasMoreTypes())
+ {
+ String type = internalTypeEnumeration.nextType();
+
+ // Get a generic corresponding value.
+ Value value = ValueFactory.create(type);
+
+ // Store the value in the parameter.
+ parameters.store(index, value);
+
+ // Increment the index according to the Category of the value.
+ index += value.isCategory2() ? 2 : 1;
+ }
+
+ // Reset the return value.
+ branchUnit.setTraceReturnValue(null);
+
+ try
+ {
+ // Process the code.
+ programMethodInfo.attributesAccept(programClassFile, this);
+ }
+ catch (RuntimeException ex)
+ {
+ // TODO: Remove this when the partial evaluator has stabilized.
+ System.err.println("Unexpected error while optimizing after partial evaluation:");
+ System.err.println(" ClassFile = ["+programClassFile.getName()+"]");
+ System.err.println(" Method = ["+programMethodInfo.getName(programClassFile)+programMethodInfo.getDescriptor(programClassFile)+"]");
+ System.err.println("Not optimizing this method");
+
+ if (DEBUG)
+ {
+ throw ex;
+ }
+ }
+
+ if (DEBUG)
+ {
+ Value returnValue = branchUnit.getTraceReturnValue();
+ if (returnValue != null)
+ {
+ System.out.println("Return value for method "+
+ ClassUtil.externalFullMethodDescription(programClassFile.getName(),
+ 0,
+ programMethodInfo.getName(programClassFile),
+ programMethodInfo.getDescriptor(programClassFile))+
+ " -> ["+returnValue.toString()+"]");
+ System.out.println();
+ }
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ if (DEBUG_RESULTS)
+ {
+ System.out.println();
+ System.out.println("Class "+ClassUtil.externalClassName(classFile.getName()));
+ System.out.println("Method "+ClassUtil.externalFullMethodDescription(classFile.getName(),
+ 0,
+ methodInfo.getName(classFile),
+ methodInfo.getDescriptor(classFile)));
+ System.out.println(" Params:"+parameters);
+ }
+
+ int codeLength = codeAttrInfo.u4codeLength;
+
+ // Reset the code changes.
+ codeAttrInfoEditor.reset(codeLength);
+
+ if (DEBUG)
+ {
+ System.out.println(" Max locals = "+codeAttrInfo.u2maxLocals);
+ System.out.println(" Max stack = "+codeAttrInfo.u2maxStack);
+ }
+
+ // Create new arrays for storing a stack and a set of variables at each
+ // branch target.
+ if (isNecessary.length < codeLength)
+ {
+ varTraceValues = new InstructionOffsetValue[codeLength];
+ stackTraceValues = new InstructionOffsetValue[codeLength];
+ branchOriginValues = new InstructionOffsetValue[codeLength];
+ branchTargetValues = new InstructionOffsetValue[codeLength];
+ vars = new TracedVariables[codeLength];
+ stacks = new TracedStack[codeLength];
+ evaluationCounts = new int[codeLength];
+ initialization = new boolean[codeLength];
+ isNecessary = new boolean[codeLength];
+ }
+ else
+ {
+ for (int index = 0; index < codeLength; index++)
+ {
+ varTraceValues[index] = null;
+ stackTraceValues[index] = null;
+ branchOriginValues[index] = null;
+ branchTargetValues[index] = null;
+ evaluationCounts[index] = 0;
+ initialization[index] = false;
+ isNecessary[index] = false;
+
+ if (vars[index] != null)
+ {
+ vars[index].reset(codeAttrInfo.u2maxLocals);
+ }
+
+ if (stacks[index] != null)
+ {
+ stacks[index].reset(codeAttrInfo.u2maxStack);
+ }
+ }
+ }
+
+ // Reuse the existing variables and stack objects, ensuring the right size.
+ variables.reset(codeAttrInfo.u2maxLocals);
+ stack.reset(codeAttrInfo.u2maxStack);
+
+ // Initialize the local variables with the parameters.
+ variables.initialize(parameters);
+
+ // Evaluate the instructions, starting at the entry point.
+ if (DEBUG) System.out.println("Partial evaluation: ");
+
+ evaluateInstructionBlock(classFile,
+ methodInfo,
+ codeAttrInfo,
+ variables,
+ stack,
+ branchUnit,
+ 0);
+
+ // Evaluate the exception catch blocks, until their entry variables
+ // have stabilized.
+ do
+ {
+ // Reset the flag to stop evaluating.
+ evaluateExceptions = false;
+
+ // Evaluate all relevant exception catch blocks once.
+ codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
+ }
+ while (evaluateExceptions);
+
+ // Clean up the visitor information in the exceptions right away.
+ codeAttrInfo.exceptionsAccept(classFile, methodInfo, classFileCleaner);
+
+ // Replace any instructions that can be simplified.
+ if (DEBUG_ANALYSIS) System.out.println("Instruction simplification:");
+
+ codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
+
+
+ // Mark all essential instructions that have been encountered as used.
+ if (DEBUG_ANALYSIS) System.out.println("Usage initialization: ");
+
+ // The invocation of the "super" or "this" <init> method inside a
+ // constructor is always necessary, even if it is assumed to have no
+ // side effects.
+ boolean markSuperOrThis =
+ methodInfo.getName(classFile).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
+
+ int aload0Index = 0;
+
+ int index = 0;
+ do
+ {
+ if (isTraced(index))
+ {
+ Instruction instruction = InstructionFactory.create(codeAttrInfo.code,
+ index);
+
+ // Remember the most recent aload0 instruction index.
+ if (instruction.opcode == InstructionConstants.OP_ALOAD_0)
+ {
+ aload0Index = index;
+ }
+
+ // Mark the instruction as necessary if it is the first
+ // invocation of the "super" or "this" <init> method
+ // inside a constructor.
+ else if (markSuperOrThis &&
+ instruction.opcode == InstructionConstants.OP_INVOKESPECIAL &&
+ stackTraceValues[index].contains(aload0Index))
+ {
+ markSuperOrThis = false;
+
+ if (DEBUG_ANALYSIS) System.out.print(index+",");
+ isNecessary[index] = true;
+ }
+
+ // Mark the instruction as necessary if it has side effects.
+ else if (sideEffectInstructionChecker.hasSideEffects(classFile,
+ methodInfo,
+ codeAttrInfo,
+ index,
+ instruction))
+ {
+ if (DEBUG_ANALYSIS) System.out.print(index+",");
+ isNecessary[index] = true;
+ }
+ }
+
+ index++;
+ }
+ while (index < codeLength);
+ if (DEBUG_ANALYSIS) System.out.println();
+
+
+ // Mark all other instructions on which the essential instructions
+ // depend. Instead of doing this recursively, we loop across all
+ // instructions, starting at the last one, and restarting at any
+ // higher, previously unmarked instruction that is being marked.
+ if (DEBUG_ANALYSIS) System.out.println("Usage marking:");
+
+ int lowestNecessaryIndex = codeLength;
+ index = codeLength - 1;
+ do
+ {
+ int nextIndex = index - 1;
+
+ // Update the lowest index of all marked instructions higher up.
+ if (isNecessary[index])
+ {
+ lowestNecessaryIndex = index;
+ }
+
+ // Check if this instruction is a branch origin from a branch that
+ // straddles some marked code.
+ nextIndex = markStraddlingBranches(index,
+ branchTargetValues[index],
+ true,
+ lowestNecessaryIndex,
+ nextIndex);
+
+ // Mark the instructions on which this instruction depends.
+ nextIndex = markDependencies(index,
+ nextIndex);
+
+ // Update the lowest index of all marked instructions higher up.
+ if (isNecessary[index])
+ {
+ lowestNecessaryIndex = index;
+ }
+
+ // Check if this instruction is a branch target from a branch that
+ // straddles some marked code.
+ nextIndex = markStraddlingBranches(index,
+ branchOriginValues[index],
+ false,
+ lowestNecessaryIndex,
+ nextIndex);
+
+ if (DEBUG_ANALYSIS)
+ {
+ if (nextIndex >= index)
+ {
+ System.out.println();
+ }
+ }
+
+ // Update the lowest index of all marked instructions higher up.
+ if (isNecessary[index])
+ {
+ lowestNecessaryIndex = index;
+ }
+
+ // Update the index of the instruction to be investigated next.
+ index = nextIndex;
+ }
+ while (index >= 0);
+ if (DEBUG_ANALYSIS) System.out.println();
+
+
+ // Insert pop instructions where necessary, to keep the stack consistent.
+ if (DEBUG_ANALYSIS) System.out.println("Stack consistency marking:");
+
+ index = codeLength - 1;
+ do
+ {
+ if (isTraced(index) &&
+ !isNecessary[index])
+ {
+ // Make sure the stack is always consistent at this offset.
+ fixStackConsistency(classFile,
+ codeAttrInfo,
+ index);
+ }
+
+ index--;
+ }
+ while (index >= 0);
+ if (DEBUG_ANALYSIS) System.out.println();
+
+
+ // Fix dup/swap instructions where necessary, to keep the stack consistent.
+ if (DEBUG_ANALYSIS) System.out.println("Dup/swap fixing:");
+
+ index = 0;
+ do
+ {
+ if (isNecessary[index])
+ {
+ // Make sure any dup/swap instructions are always consistent at this offset.
+ fixDupInstruction(codeAttrInfo,
+ index);
+ }
+
+ index++;
+ }
+ while (index < codeLength);
+ if (DEBUG_ANALYSIS) System.out.println();
+
+
+ // Mark branches straddling just inserted push/pop instructions.
+ if (DEBUG_ANALYSIS) System.out.println("Final straddling branch marking:");
+
+ lowestNecessaryIndex = codeLength;
+ index = codeLength - 1;
+ do
+ {
+ int nextIndex = index - 1;
+
+ // Update the lowest index of all marked instructions higher up.
+ if (isNecessary[index])
+ {
+ lowestNecessaryIndex = index;
+ }
+
+ // Check if this instruction is a branch origin from a branch that
+ // straddles some marked code.
+ nextIndex = markAndSimplifyStraddlingBranches(index,
+ branchTargetValues[index],
+ lowestNecessaryIndex,
+ nextIndex);
+
+ // Update the lowest index of all marked instructions higher up.
+ if (isNecessary[index])
+ {
+ lowestNecessaryIndex = index;
+ }
+
+ // Check if this instruction is a branch target from a branch that
+ // straddles some marked code.
+ nextIndex = markAndSimplifyStraddlingBranches(branchOriginValues[index],
+ index,
+ lowestNecessaryIndex,
+ nextIndex);
+
+ if (DEBUG_ANALYSIS)
+ {
+ if (nextIndex >= index)
+ {
+ System.out.println();
+ }
+ }
+
+ // Update the lowest index of all marked instructions higher up.
+ if (isNecessary[index])
+ {
+ lowestNecessaryIndex = index;
+ }
+
+ // Update the index of the instruction to be investigated next.
+ index = nextIndex;
+ }
+ while (index >= 0);
+ if (DEBUG_ANALYSIS) System.out.println();
+
+
+ // Mark variable initializations, even if they aren't strictly necessary.
+ // The virtual machine is not smart enough to see this, and may complain
+ // otherwise.
+ if (DEBUG_ANALYSIS) System.out.println("Initialization marking: ");
+
+ // TODO: Find a better way.
+ index = 0;
+ do
+ {
+ // Is it an initialization that hasn't been marked yet?
+ if (initialization[index] &&
+ !isNecessary[index])
+ {
+ if (DEBUG_ANALYSIS) System.out.println(index+",");
+
+ // Figure out what kind of initialization value has to be stored.
+ int pushInstructionOffset = stackTraceValues[index].instructionOffset(0);
+ int pushComputationalType = stacks[pushInstructionOffset].getTop(0).computationalType();
+ increaseStackSize(index, pushComputationalType, false);
+ }
+
+ index++;
+ }
+ while (index < codeLength);
+ if (DEBUG_ANALYSIS) System.out.println();
+
+
+ if (DEBUG_RESULTS)
+ {
+ System.out.println("Results:");
+ int offset = 0;
+ do
+ {
+ Instruction instruction = InstructionFactory.create(codeAttrInfo.code,
+ offset);
+ System.out.println((isNecessary[offset] ? " + " : " - ")+instruction.toString(offset));
+ if (isTraced(offset))
+ {
+ if (varTraceValues[offset] != null &&
+ varTraceValues[offset].instructionOffsetCount() > 0)
+ {
+ System.out.println(" has overall been using information from instructions setting vars: "+varTraceValues[offset]);
+ }
+ if (stackTraceValues[offset] != null &&
+ stackTraceValues[offset].instructionOffsetCount() > 0)
+ {
+ System.out.println(" has overall been using information from instructions setting stack: "+stackTraceValues[offset]);
+ }
+ if (branchTargetValues[offset] != null)
+ {
+ System.out.println(" has overall been branching to "+branchTargetValues[offset]);
+ }
+ if (codeAttrInfoEditor.preInsertions[offset] != null)
+ {
+ System.out.println(" is preceded by: "+codeAttrInfoEditor.preInsertions[offset]);
+ }
+ if (codeAttrInfoEditor.postInsertions[offset] != null)
+ {
+ System.out.println(" is followed by: "+codeAttrInfoEditor.preInsertions[offset]);
+ }
+ System.out.println(" Vars: "+vars[offset]);
+ System.out.println(" Stack: "+stacks[offset]);
+ }
+
+ offset += instruction.length(offset);
+ }
+ while (offset < codeLength);
+ }
+
+ // Delete all instructions that are not used.
+ int offset = 0;
+ do
+ {
+ Instruction instruction = InstructionFactory.create(codeAttrInfo.code,
+ offset);
+ if (!isNecessary[offset])
+ {
+ codeAttrInfoEditor.replaceInstruction(offset, null);
+ codeAttrInfoEditor.replaceInstruction2(offset, null);
+ }
+
+ offset += instruction.length(offset);
+ }
+ while (offset < codeLength);
+
+ // Apply all accumulated changes to the code.
+ codeAttrInfoEditor.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
+ }
+
+
+ /**
+ * Marks the instructions at the given offsets, if the current instruction
+ * itself has been marked.
+ * @param index the offset of the current instruction.
+ * @param nextIndex the index of the instruction to be investigated next.
+ * @return the updated index of the instruction to be investigated next.
+ * It is always greater than or equal, because instructions are
+ * investigated starting at the highest index.
+ */
+ private int markDependencies(int index,
+ int nextIndex)
+ {
+ if (isNecessary[index] &&
+ !codeAttrInfoEditor.isModified(index))
+ {
+ if (DEBUG_ANALYSIS) System.out.print(index);
+
+ // Mark all instructions whose variable values are used.
+ nextIndex = markDependencies(varTraceValues[index], nextIndex);
+
+ // Mark all instructions whose stack values are used.
+ nextIndex = markDependencies(stackTraceValues[index], nextIndex);
+
+ if (DEBUG_ANALYSIS) System.out.print(",");
+ }
+
+ return nextIndex;
+ }
+
+
+ /**
+ * Marks the instructions at the given offsets.
+ * @param traceOffsetValue the offsets of the instructions to be marked.
+ * @param nextIndex the index of the instruction to be investigated
+ * next.
+ * @return the updated index of the instruction to be investigated next.
+ * It is always greater than or equal, because instructions are
+ * investigated starting at the highest index.
+ */
+ private int markDependencies(InstructionOffsetValue traceOffsetValue,
+ int nextIndex)
+ {
+ if (traceOffsetValue != null)
+ {
+ int traceOffsetCount = traceOffsetValue.instructionOffsetCount();
+ for (int traceOffsetIndex = 0; traceOffsetIndex < traceOffsetCount; traceOffsetIndex++)
+ {
+ // Has the other instruction been marked yet?
+ int traceOffset = traceOffsetValue.instructionOffset(traceOffsetIndex);
+ if (!isNecessary[traceOffset])
+ {
+ if (DEBUG_ANALYSIS) System.out.print("["+traceOffset+"]");
+
+ // Mark it.
+ isNecessary[traceOffset] = true;
+
+ // Restart at this instruction if it has a higher offset.
+ if (nextIndex < traceOffset)
+ {
+ if (DEBUG_ANALYSIS) System.out.print("!");
+
+ nextIndex = traceOffset;
+ }
+ }
+ }
+ }
+
+ return nextIndex;
+ }
+
+
+ /**
+ * Marks the branch instructions of straddling branches, if they straddle
+ * some code that has been marked.
+ * @param index the offset of the branch origin or branch target.
+ * @param branchValue the offsets of the straddling branch targets
+ * or branch origins.
+ * @param isPointingToTargets <code>true</code> if the above offsets are
+ * branch targets, <code>false</code> if they
+ * are branch origins.
+ * @param lowestNecessaryIndex the lowest offset of all instructions marked
+ * so far.
+ * @param nextIndex the index of the instruction to be investigated
+ * next.
+ * @return the updated index of the instruction to be investigated next.
+ * It is always greater than or equal the original index, because
+ * instructions are investigated starting at the highest index.
+ */
+ private int markStraddlingBranches(int index,
+ InstructionOffsetValue branchValue,
+ boolean isPointingToTargets,
+ int lowestNecessaryIndex,
+ int nextIndex)
+ {
+ if (branchValue != null)
+ {
+ // Loop over all branch origins.
+ int branchCount = branchValue.instructionOffsetCount();
+ for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
+ {
+ // Is the branch straddling any necessary instructions?
+ int branch = branchValue.instructionOffset(branchIndex);
+
+ // Is the offset pointing to a branch origin or to a branch target?
+ nextIndex = isPointingToTargets ?
+ markStraddlingBranch(index, branch, lowestNecessaryIndex, nextIndex) :
+ markStraddlingBranch(branch, index, lowestNecessaryIndex, nextIndex);
+ }
+ }
+
+ return nextIndex;
+ }
+
+
+ /**
+ * Marks the given branch instruction, if it straddles some code that has
+ * been marked.
+ * @param branchOrigin the branch origin.
+ * @param branchTarget the branch target.
+ * @param lowestNecessaryIndex the lowest offset of all instructions marked
+ * so far.
+ * @param nextIndex the index of the instruction to be investigated
+ * next.
+ * @return the updated index of the instruction to be investigated next.
+ * It is always greater than or equal the original index, because
+ * instructions are investigated starting at the highest index.
+ */
+ private int markStraddlingBranch(int branchOrigin,
+ int branchTarget,
+ int lowestNecessaryIndex,
+ int nextIndex)
+ {
+ // Has the branch origin been marked yet, and is it straddling the
+ // lowest necessary instruction?
+ if (!isNecessary[branchOrigin] &&
+ isStraddlingBranch(branchOrigin, branchTarget, lowestNecessaryIndex))
+ {
+ if (DEBUG_ANALYSIS) System.out.print("["+branchOrigin+"->"+branchTarget+"]");
+
+ // Mark the branch origin.
+ isNecessary[branchOrigin] = true;
+
+ // Restart at the branch origin if it has a higher offset.
+ if (nextIndex < branchOrigin)
+ {
+ if (DEBUG_ANALYSIS) System.out.print("!");
+
+ nextIndex = branchOrigin;
+ }
+ }
+
+ return nextIndex;
+ }
+
+
+ /**
+ * Marks and simplifies the branch instructions of straddling branches,
+ * if they straddle some code that has been marked.
+ * @param branchOrigin the branch origin.
+ * @param branchTargets the branch targets.
+ * @param lowestNecessaryIndex the lowest offset of all instructions marked
+ * so far.
+ * @param nextIndex the index of the instruction to be investigated
+ * next.
+ * @return the updated index of the instruction to be investigated next.
+ * It is always greater than or equal the original index, because
+ * instructions are investigated starting at the highest index.
+ */
+ private int markAndSimplifyStraddlingBranches(int branchOrigin,
+ InstructionOffsetValue branchTargets,
+ int lowestNecessaryIndex,
+ int nextIndex)
+ {
+ if (branchTargets != null &&
+ !isNecessary[branchOrigin])
+ {
+ // Loop over all branch targets.
+ int branchCount = branchTargets.instructionOffsetCount();
+ if (branchCount > 0)
+ {
+ for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
+ {
+ // Is the branch straddling any necessary instructions?
+ int branchTarget = branchTargets.instructionOffset(branchIndex);
+
+ if (!isStraddlingBranch(branchOrigin,
+ branchTarget,
+ lowestNecessaryIndex))
+ {
+ return nextIndex;
+ }
+ }
+
+ nextIndex = markAndSimplifyStraddlingBranch(branchOrigin,
+ branchTargets.instructionOffset(0),
+ lowestNecessaryIndex,
+ nextIndex);
+ }
+ }
+
+ return nextIndex;
+ }
+
+
+ /**
+ * Marks and simplifies the branch instructions of straddling branches,
+ * if they straddle some code that has been marked.
+ * @param branchOrigins the branch origins.
+ * @param branchTarget the branch target.
+ * @param lowestNecessaryIndex the lowest offset of all instructions marked
+ * so far.
+ * @param nextIndex the index of the instruction to be investigated
+ * next.
+ * @return the updated index of the instruction to be investigated next.
+ * It is always greater than or equal the original index, because
+ * instructions are investigated starting at the highest index.
+ */
+ private int markAndSimplifyStraddlingBranches(InstructionOffsetValue branchOrigins,
+ int branchTarget,
+ int lowestNecessaryIndex,
+ int nextIndex)
+ {
+ if (branchOrigins != null)
+ {
+ // Loop over all branch origins.
+ int branchCount = branchOrigins.instructionOffsetCount();
+ for (int branchIndex = 0; branchIndex < branchCount; branchIndex++)
+ {
+ // Is the branch straddling any necessary instructions?
+ int branchOrigin = branchOrigins.instructionOffset(branchIndex);
+
+ nextIndex = markAndSimplifyStraddlingBranch(branchOrigin,
+ branchTarget,
+ lowestNecessaryIndex,
+ nextIndex);
+ }
+ }
+
+ return nextIndex;
+ }
+
+
+ /**
+ * Marks and simplifies the given branch instruction, if it straddles some
+ * code that has been marked.
+ * @param branchOrigin the branch origin.
+ * @param branchTarget the branch target.
+ * @param lowestNecessaryIndex the lowest offset of all instructions marked
+ * so far.
+ * @param nextIndex the index of the instruction to be investigated
+ * next.
+ * @return the updated index of the instruction to be investigated next.
+ * It is always greater than or equal the original index, because
+ * instructions are investigated starting at the highest index.
+ */
+ private int markAndSimplifyStraddlingBranch(int branchOrigin,
+ int branchTarget,
+ int lowestNecessaryIndex,
+ int nextIndex)
+ {
+ // Has the branch origin been marked yet, and is it straddling the
+ // lowest necessary instruction?
+ if (!isNecessary[branchOrigin] &&
+ isStraddlingBranch(branchOrigin, branchTarget, lowestNecessaryIndex))
+ {
+ if (DEBUG_ANALYSIS) System.out.print("["+branchOrigin+"->"+branchTarget+"]");
+
+ // Mark the branch origin.
+ isNecessary[branchOrigin] = true;
+
+ // Replace the branch instruction by a simple branch instrucion.
+ Instruction replacementInstruction =
+ new BranchInstruction(InstructionConstants.OP_GOTO_W,
+ branchTarget - branchOrigin).shrink();
+
+ codeAttrInfoEditor.replaceInstruction(branchOrigin,
+ replacementInstruction);
+
+ // Restart at the branch origin if it has a higher offset.
+ if (nextIndex < branchOrigin)
+ {
+ if (DEBUG_ANALYSIS) System.out.print("!");
+
+ nextIndex = branchOrigin;
+ }
+ }
+
+ return nextIndex;
+ }
+
+
+ /**
+ * Returns whether the given branch straddling some code that has been marked.
+ * @param branchOrigin the branch origin.
+ * @param branchTarget the branch target.
+ * @param lowestNecessaryIndex the lowest offset of all instructions marked
+ * so far.
+ */
+ private boolean isStraddlingBranch(int branchOrigin,
+ int branchTarget,
+ int lowestNecessaryIndex)
+ {
+ return branchOrigin <= lowestNecessaryIndex ^
+ branchTarget <= lowestNecessaryIndex;
+ }
+
+
+ /**
+ * Inserts pop instructions where necessary, in order to make sure the
+ * stack is consistent at the given index.
+ * @param classFile the class file that is being checked.
+ * @param codeAttrInfo the code that is being checked.
+ * @param index the offset of the dependent instruction.
+ */
+ private void fixStackConsistency(ClassFile classFile,
+ CodeAttrInfo codeAttrInfo,
+ int index)
+ {
+ // Is the unnecessary instruction popping values (but not a dup/swap
+ // instruction)?
+ Instruction popInstruction = InstructionFactory.create(codeAttrInfo.code,
+ index);
+ byte popOpcode = popInstruction.opcode;
+
+ int popCount = popInstruction.stackPopCount(classFile);
+ if (popCount > 0) // &&
+ //popOpcode != InstructionConstants.OP_DUP &&
+ //popOpcode != InstructionConstants.OP_DUP_X1 &&
+ //popOpcode != InstructionConstants.OP_DUP_X2 &&
+ //popOpcode != InstructionConstants.OP_DUP2 &&
+ //popOpcode != InstructionConstants.OP_DUP2_X1 &&
+ //popOpcode != InstructionConstants.OP_DUP2_X2 &&
+ //popOpcode != InstructionConstants.OP_SWAP)
+ {
+ // Check the instructions on which it depends.
+ InstructionOffsetValue traceOffsetValue = stackTraceValues[index];
+ int traceOffsetCount = traceOffsetValue.instructionOffsetCount();
+
+ if (popCount <= 4 &&
+ isAllNecessary(traceOffsetValue))
+ {
+ if (popOpcode == InstructionConstants.OP_POP ||
+ popOpcode == InstructionConstants.OP_POP2)
+ {
+ if (DEBUG_ANALYSIS) System.out.println(" Popping value again at "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)");
+
+ // Simply mark pop and pop2 instructions.
+ isNecessary[index] = true;
+ }
+ else
+ {
+ if (DEBUG_ANALYSIS) System.out.println(" Popping value instead of "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)");
+
+ // Make sure the pushed value is popped again,
+ // right before this instruction.
+ decreaseStackSize(index, popCount, true, true);
+ }
+ }
+ //else if (popCount == (popInstruction.isCategory2() ? 4 : 2) &&
+ // traceOffsetCount == 2 &&
+ // isAnyNecessary(traceOffsetValue))
+ //{
+ // if (DEBUG_ANALYSIS) System.out.println(" Popping single value instead of "+popInstruction.toString(index)+" (pushed at some of "+traceOffsetValue.instructionOffsetCount()+" offsets)");
+ //
+ // // Make sure the single pushed value is popped again,
+ // // right before this instruction.
+ // decreaseStackSize(index, popCount / 2, true, true);
+ //}
+ else if (isAnyNecessary(traceOffsetValue))
+ {
+ if (DEBUG_ANALYSIS) System.out.println(" Popping value somewhere before "+index+" (pushed at some of "+traceOffsetValue.instructionOffsetCount()+" offsets):");
+
+ // Go over all stack pushing instructions.
+ for (int traceOffsetIndex = 0; traceOffsetIndex < traceOffsetCount; traceOffsetIndex++)
+ {
+ // Has the push instruction been marked?
+ int pushInstructionOffset = traceOffsetValue.instructionOffset(traceOffsetIndex);
+ if (isNecessary[pushInstructionOffset])
+ {
+ Instruction pushInstruction = InstructionFactory.create(codeAttrInfo.code,
+ pushInstructionOffset);
+
+ int lastOffset = lastPopInstructionOffset(pushInstructionOffset,
+ index,
+ pushInstructionOffset);
+
+ if (DEBUG_ANALYSIS) System.out.println(" Popping value right after "+lastOffset+", due to push at "+pushInstructionOffset);
+
+ // Make sure the pushed value is popped again,
+ // right after the instruction that pushes it
+ // (or after the dup instruction that still uses it).
+ decreaseStackSize(lastOffset,
+ pushInstruction.stackPushCount(classFile),
+ false, false);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Returns the last offset of the necessary instruction that depends on the
+ * stack result of the instruction at the given index.
+ * @param startOffset the start offset in the search.
+ * @param endOffset the end offset in the search.
+ * @param pushInstructionOffset the offset of the instruction that pushes
+ * a result onto the stack.
+ * @return the last offset of the necessary instruction that uses the
+ * above result.
+ */
+ private int lastPopInstructionOffset(int startOffset,
+ int endOffset,
+ int pushInstructionOffset)
+ {
+ int lastOffset = startOffset;
+
+ for (int index = startOffset; index < endOffset; index++)
+ {
+ if (isNecessary[index] &&
+ stackTraceValues[index].contains(pushInstructionOffset))
+ {
+ lastOffset = index;
+ }
+ }
+
+ return lastOffset;
+ }
+
+
+ /**
+ * Puts the required push instruction before the given index. The
+ * instruction is marked as necessary.
+ * @param index the offset of the instruction.
+ * @param computationalType the computational type on the stack, for
+ * push instructions.
+ * @param delete specifies whether the instruction should be
+ * deleted.
+ */
+ private void increaseStackSize(int index,
+ int computationalType,
+ boolean delete)
+ {
+ // Mark this instruction.
+ isNecessary[index] = true;
+
+ // Create a simple push instrucion.
+ byte replacementOpcode =
+ computationalType == Value.TYPE_INTEGER ? InstructionConstants.OP_ICONST_0 :
+ computationalType == Value.TYPE_LONG ? InstructionConstants.OP_LCONST_0 :
+ computationalType == Value.TYPE_FLOAT ? InstructionConstants.OP_FCONST_0 :
+ computationalType == Value.TYPE_DOUBLE ? InstructionConstants.OP_DCONST_0 :
+ computationalType == Value.TYPE_REFERENCE ? InstructionConstants.OP_ACONST_NULL :
+ InstructionConstants.OP_NOP;
+
+ Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
+
+ // Insert the pop or push instruction.
+ codeAttrInfoEditor.insertBeforeInstruction(index,
+ replacementInstruction);
+
+ // Delete the original instruction if necessary.
+ if (delete)
+ {
+ codeAttrInfoEditor.deleteInstruction(index);
+ }
+ }
+
+
+ /**
+ * Puts the required pop instruction at the given index. The
+ * instruction is marked as necessary.
+ * @param offset the offset of the instruction.
+ * @param popCount the required reduction of the stack size.
+ * @param before specifies whether the pop instruction should be inserted
+ * before or after the present instruction.
+ * @param delete specifies whether the instruction should be deleted.
+ */
+ private void decreaseStackSize(int offset,
+ int popCount,
+ boolean before,
+ boolean delete)
+ {
+ boolean after = !before;
+
+ // Special case: we may replace the instruction by two pop instructions.
+ if (delete && popCount > 2)
+ {
+ before = true;
+ after = true;
+ }
+
+ if (popCount < 1 ||
+ popCount > 4)
+ {
+ throw new IllegalArgumentException("Unsupported stack size reduction ["+popCount+"]");
+ }
+
+ // Mark this instruction.
+ isNecessary[offset] = true;
+
+ if (before)
+ {
+ // Create a simple pop instrucion.
+ byte replacementOpcode = popCount == 1 || popCount == 3 ?
+ InstructionConstants.OP_POP :
+ InstructionConstants.OP_POP2;
+
+ Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
+
+ // Insert the pop instruction.
+ codeAttrInfoEditor.insertBeforeInstruction(offset,
+ replacementInstruction);
+ }
+
+ if (after)
+ {
+ // Create a simple pop instrucion.
+ byte replacementOpcode = popCount == 1 ?
+ InstructionConstants.OP_POP :
+ InstructionConstants.OP_POP2;
+
+ Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
+
+ if (DEBUG_ANALYSIS) System.out.println(" Pop instruction after ["+offset+"]: "+replacementInstruction);
+
+ // Insert the pop instruction.
+ codeAttrInfoEditor.insertAfterInstruction(offset,
+ replacementInstruction);
+ }
+
+ // Delete the original instruction if necessary.
+ if (delete)
+ {
+ codeAttrInfoEditor.deleteInstruction(offset);
+ }
+ }
+
+
+ /**
+ * Replaces the specified instruction by the proper dup/swap variant,
+ * if necessary, depending on the state of the stack.
+ * @param codeAttrInfo the code that is being checked.
+ * @param offset the offset of the instruction.
+ */
+ private void fixDupInstruction(CodeAttrInfo codeAttrInfo,
+ int offset)
+ {
+ byte replacementOpcode = 0;
+
+ // Simplify the popping instruction if possible.
+ switch (codeAttrInfo.code[offset])
+ {
+ case InstructionConstants.OP_DUP_X1:
+ if (!isStackEntryPresent(offset, 1))
+ {
+ replacementOpcode = InstructionConstants.OP_DUP;
+ }
+ break;
+
+ case InstructionConstants.OP_DUP_X2:
+ if (!isStackEntryPresent(offset, 1) ||
+ !isStackEntryPresent(offset, 2))
+ {
+ if (isStackEntryPresent(offset, 1) ||
+ isStackEntryPresent(offset, 2))
+ {
+ replacementOpcode = InstructionConstants.OP_DUP_X1;
+ }
+ else
+ {
+ replacementOpcode = InstructionConstants.OP_DUP;
+ }
+ }
+ break;
+
+ case InstructionConstants.OP_DUP2_X1:
+ if (!isStackEntryPresent(offset, 2))
+ {
+ replacementOpcode = InstructionConstants.OP_DUP2;
+ }
+ break;
+
+ case InstructionConstants.OP_DUP2_X2:
+ if (!isStackEntryPresent(offset, 2) ||
+ !isStackEntryPresent(offset, 3))
+ {
+ if (isStackEntryPresent(offset, 2) ||
+ isStackEntryPresent(offset, 3))
+ {
+ replacementOpcode = InstructionConstants.OP_DUP2_X1;
+ }
+ else
+ {
+ replacementOpcode = InstructionConstants.OP_DUP2;
+ }
+ }
+ break;
+
+ case InstructionConstants.OP_SWAP:
+ if (!isStackEntryPresent(offset, 0))
+ {
+ isNecessary[offset] = false;
+ }
+ break;
+ }
+
+ // Actually replace the instruction with the new opcde, if any.
+ if (replacementOpcode != 0)
+ {
+ Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
+ codeAttrInfoEditor.replaceInstruction(offset,
+ replacementInstruction);
+
+ if (DEBUG_ANALYSIS) System.out.println(" Replacing instruction at ["+offset+"] by "+replacementInstruction.toString());
+ }
+ }
+
+
+ /**
+ * Returns whether the given stack entry is present after execution of the
+ * instruction at the given offset.
+ */
+ private boolean isStackEntryPresent(int instructionOffset, int stackIndex)
+ {
+ return isAnyNecessary(stacks[instructionOffset].getTopTraceValue(stackIndex).instructionOffsetValue());
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, ExceptionInfo exceptionInfo)
+ {
+ if (isTraced(exceptionInfo.u2startpc, exceptionInfo.u2endpc))
+ {
+ if (DEBUG) System.out.println("Partial evaluation of exception ["+exceptionInfo.u2startpc+","+exceptionInfo.u2endpc+"] -> ["+exceptionInfo.u2handlerpc+"]:");
+
+ // Generalize the variables of the try block.
+ variables.reset(codeAttrInfo.u2maxLocals);
+ generalizeVariables(exceptionInfo.u2startpc,
+ exceptionInfo.u2endpc,
+ variables);
+
+ // Remember the entry variables of the exception.
+ TracedVariables exceptionVariables = (TracedVariables)exceptionInfo.getVisitorInfo();
+ if (exceptionVariables == null)
+ {
+ exceptionVariables = new TracedVariables(codeAttrInfo.u2maxLocals);
+
+ exceptionInfo.setVisitorInfo(exceptionVariables);
+ }
+ else
+ {
+ // Bail out if the entry variables are the same as last time.
+ if (exceptionVariables.equals(variables))
+ {
+ if (DEBUG) System.out.println(" Repeated initial variables");
+
+ return;
+ }
+ }
+
+ exceptionVariables.initialize(variables);
+
+ // Reuse the existing variables and stack objects, ensuring the right size.
+ variables.reset(codeAttrInfo.u2maxLocals);
+ stack.reset(codeAttrInfo.u2maxStack);
+
+ // The initial stack doesn't have associated instruction offsets.
+ Value storeValue = InstructionOffsetValueFactory.create();
+ variables.setStoreValue(storeValue);
+ stack.setStoreValue(storeValue);
+
+ // Initialize the local variables and the stack.
+ variables.initialize(exceptionVariables);
+ //stack.push(ReferenceValueFactory.create((ClassCpInfo)((ProgramClassFile)classFile).getCpEntry(exceptionInfo.u2catchType), false));
+ stack.push(ReferenceValueFactory.create(false));
+
+ // Evaluate the instructions, starting at the entry point.
+ evaluateInstructionBlock(classFile,
+ methodInfo,
+ codeAttrInfo,
+ variables,
+ stack,
+ branchUnit,
+ exceptionInfo.u2handlerpc);
+
+ // Remember to check this exception and other exceptions once more.
+ evaluateExceptions = true;
+ }
+ }
+
+
+ /**
+ * Returns whether a block of instructions is ever used.
+ */
+ private boolean isTraced(int startOffset, int endOffset)
+ {
+ for (int index = startOffset; index < endOffset; index++)
+ {
+ if (isTraced(index))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Generalize the local variable frames of a block of instructions.
+ */
+ private void generalizeVariables(int startOffset, int endOffset, TracedVariables generalizedVariables)
+ {
+ for (int index = startOffset; index < endOffset; index++)
+ {
+ if (isTraced(index))
+ {
+ // We can't use the return value, because local generalization
+ // can be different a couple of times, with the global
+ // generalization being the same.
+ generalizedVariables.generalize(vars[index]);
+ }
+ }
+ }
+
+
+ // Utility methods to evaluate instruction blocks.
+
+ /**
+ * Evaluates a block of instructions, starting at the given offset and ending
+ * at a branch instruction, a return instruction, or a throw instruction.
+ */
+ private void evaluateInstructionBlock(ClassFile classFile,
+ MethodInfo methodInfo,
+ CodeAttrInfo codeAttrInfo,
+ TracedVariables variables,
+ TracedStack stack,
+ TracedBranchUnit branchUnit,
+ int instructionOffset)
+ {
+ byte[] code = codeAttrInfo.code;
+
+ if (DEBUG)
+ {
+ System.out.println("Instruction block starting at ["+instructionOffset+"] in "+
+ ClassUtil.externalFullMethodDescription(classFile.getName(),
+ 0,
+ methodInfo.getName(classFile),
+ methodInfo.getDescriptor(classFile)));
+ System.out.println("Init vars: "+variables);
+ System.out.println("Init stack: "+stack);
+ }
+
+ Processor processor = new Processor(variables, stack, branchUnit);
+
+ // Evaluate the subsequent instructions.
+ while (true)
+ {
+ // Maintain a generalized trace instruction offset.
+ int evaluationCount = evaluationCounts[instructionOffset]++;
+ if (evaluationCount == 0)
+ {
+ varTraceValues[instructionOffset] = InstructionOffsetValueFactory.create();
+ stackTraceValues[instructionOffset] = InstructionOffsetValueFactory.create();
+ }
+
+ // Remember this instruction's offset with any stored value.
+ Value storeValue = InstructionOffsetValueFactory.create(instructionOffset);
+ variables.setStoreValue(storeValue);
+ stack.setStoreValue(storeValue);
+
+ // Reset the trace value.
+ InstructionOffsetValue traceValue = InstructionOffsetValueFactory.create();
+ variables.setTraceValue(traceValue);
+ stack.setTraceValue(traceValue);
+
+ // Reset the initialization flag.
+ variables.resetInitialization();
+
+ // Note that the instruction is only volatile.
+ Instruction instruction = InstructionFactory.create(code, instructionOffset);
+
+ // By default, the next instruction will be the one after this
+ // instruction.
+ int nextInstructionOffset = instructionOffset +
+ instruction.length(instructionOffset);
+ InstructionOffsetValue nextInstructionOffsetValue = InstructionOffsetValueFactory.create(nextInstructionOffset);
+ branchUnit.resetCalled();
+ branchUnit.setTraceBranchTargets(nextInstructionOffsetValue);
+
+
+ if (DEBUG)
+ {
+ System.out.println(instruction.toString(instructionOffset));
+ }
+
+ try
+ {
+ // Process the instruction. The processor may call
+ // the Variables methods of 'variables',
+ // the Stack methods of 'stack', and
+ // the BranchUnit methods of this evaluator.
+ instruction.accept(classFile, methodInfo, codeAttrInfo, instructionOffset, processor);
+ }
+ catch (RuntimeException ex)
+ {
+ System.err.println("Unexpected error while performing partial evaluation:");
+ System.err.println(" ClassFile = ["+classFile.getName()+"]");
+ System.err.println(" Method = ["+methodInfo.getName(classFile)+methodInfo.getDescriptor(classFile)+"]");
+ System.err.println(" Instruction = "+instruction.toString(instructionOffset));
+
+ throw ex;
+ }
+
+ // Collect the offsets of the instructions whose results were used.
+ InstructionOffsetValue variablesTraceValue = variables.getTraceValue().instructionOffsetValue();
+ InstructionOffsetValue stackTraceValue = stack.getTraceValue().instructionOffsetValue();
+ varTraceValues[instructionOffset] =
+ varTraceValues[instructionOffset].generalize(variablesTraceValue).instructionOffsetValue();
+ stackTraceValues[instructionOffset] =
+ stackTraceValues[instructionOffset].generalize(stackTraceValue).instructionOffsetValue();
+ initialization[instructionOffset] =
+ initialization[instructionOffset] || variables.wasInitialization();
+
+ // Collect the branch targets from the branch unit.
+ InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets();
+ int branchTargetCount = branchTargets.instructionOffsetCount();
+
+ // Stop tracing.
+ variables.setTraceValue(traceValue);
+ stack.setTraceValue(traceValue);
+ branchUnit.setTraceBranchTargets(traceValue);
+
+ if (DEBUG)
+ {
+ if (variablesTraceValue.instructionOffsetCount() > 0)
+ {
+ System.out.println(" has used information from instructions setting vars: "+variablesTraceValue);
+ }
+ if (stackTraceValue.instructionOffsetCount() > 0)
+ {
+ System.out.println(" has used information from instructions setting stack: "+stackTraceValue);
+ }
+ if (branchUnit.wasCalled())
+ {
+ System.out.println(" is branching to "+branchTargets);
+ }
+
+ if (varTraceValues[instructionOffset].instructionOffsetCount() > 0)
+ {
+ System.out.println(" has up til now been using information from instructions setting vars: "+varTraceValues[instructionOffset]);
+ }
+ if (stackTraceValues[instructionOffset].instructionOffsetCount() > 0)
+ {
+ System.out.println(" has up till now been using information from instructions setting stack: "+stackTraceValues[instructionOffset]);
+ }
+ if (branchTargetValues[instructionOffset] != null)
+ {
+ System.out.println(" has up till now been branching to "+branchTargetValues[instructionOffset]);
+ }
+
+ System.out.println(" Vars: "+variables);
+ System.out.println(" Stack: "+stack);
+ }
+
+ // Maintain a generalized local variable frame and stack at this
+ // branch instruction offset.
+ if (vars[instructionOffset] == null)
+ {
+ // First time we're passing by this instruction.
+ // There's not even a context at this index yet.
+ vars[instructionOffset] = new TracedVariables(variables);
+ stacks[instructionOffset] = new TracedStack(stack);
+ }
+ else if (evaluationCount == 0)
+ {
+ // First time we're passing by this instruction.
+ // Reuse the context objects at this index.
+ vars[instructionOffset].initialize(variables);
+ stacks[instructionOffset].copy(stack);
+ }
+ else
+ {
+ // If there are multiple alternative branches, or if this
+ // instruction has been evaluated an excessive number of
+ // times, then generalize the current context.
+ // TODO: See if we can avoid generalizing the current context.
+ //if (branchTargetCount > 1 ||
+ // evaluationCount > MAXIMUM_EVALUATION_COUNT)
+ //{
+ // variables.generalize(vars[instructionOffset]);
+ // stack.generalize(stacks[instructionOffset]);
+ //}
+
+ boolean vars_changed = vars[instructionOffset].generalize(variables);
+ boolean stack_changed = stacks[instructionOffset].generalize(stack);
+
+ // Bail out if the current context is the same as last time.
+ if (!vars_changed &&
+ !stack_changed &&
+ branchTargets.equals(branchTargetValues[instructionOffset]))
+ {
+ if (DEBUG) System.out.println("Repeated variables, stack, and branch targets");
+
+ break;
+ }
+
+ // Generalize the current context. Note that the most recent
+ // variable values have to remain last in the generalizations,
+ // for the sake of the ret instruction.
+ variables.initialize(vars[instructionOffset]);
+ stack.copy(stacks[instructionOffset]);
+ }
+
+ // Did the branch unit get called?
+ if (branchUnit.wasCalled())
+ {
+ // Accumulate the branch targets at this offset.
+ branchTargetValues[instructionOffset] = branchTargetValues[instructionOffset] == null ?
+ branchTargets :
+ branchTargetValues[instructionOffset].generalize(branchTargets).instructionOffsetValue();
+
+ // Are there no branch targets at all?
+ if (branchTargetCount == 0)
+ {
+ // Exit from this code block.
+ break;
+ }
+
+ // Accumulate the branch origins at the branch target offsets.
+ InstructionOffsetValue instructionOffsetValue = InstructionOffsetValueFactory.create(instructionOffset);
+ for (int index = 0; index < branchTargetCount; index++)
+ {
+ int branchTarget = branchTargets.instructionOffset(index);
+ branchOriginValues[branchTarget] = branchOriginValues[branchTarget] == null ?
+ instructionOffsetValue:
+ branchOriginValues[branchTarget].generalize(instructionOffsetValue).instructionOffsetValue();
+ }
+
+ // Are there multiple branch targets?
+ if (branchTargetCount > 1)
+ {
+ // Handle them recursively and exit from this code block.
+ for (int index = 0; index < branchTargetCount; index++)
+ {
+ if (DEBUG) System.out.println("Alternative branch #"+index+" out of "+branchTargetCount+", from ["+instructionOffset+"] to ["+branchTargets.instructionOffset(index)+"]");
+
+ evaluateInstructionBlock(classFile,
+ methodInfo,
+ codeAttrInfo,
+ new TracedVariables(variables),
+ new TracedStack(stack),
+ branchUnit,
+ branchTargets.instructionOffset(index));
+ }
+
+ break;
+ }
+
+ if (DEBUG) System.out.println("Definite branch from ["+instructionOffset+"] to ["+branchTargets.instructionOffset(0)+"]");
+ }
+
+ // Just continue with the next instruction.
+ instructionOffset = branchTargets.instructionOffset(0);
+ }
+
+ if (DEBUG) System.out.println("Ending processing of instruction block");
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
+ {
+ if (isTraced(offset))
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_IALOAD:
+ case InstructionConstants.OP_BALOAD:
+ case InstructionConstants.OP_CALOAD:
+ case InstructionConstants.OP_SALOAD:
+ case InstructionConstants.OP_IADD:
+ case InstructionConstants.OP_ISUB:
+ case InstructionConstants.OP_IMUL:
+ case InstructionConstants.OP_IDIV:
+ case InstructionConstants.OP_IREM:
+ case InstructionConstants.OP_INEG:
+ case InstructionConstants.OP_ISHL:
+ case InstructionConstants.OP_ISHR:
+ case InstructionConstants.OP_IUSHR:
+ case InstructionConstants.OP_IAND:
+ case InstructionConstants.OP_IOR:
+ case InstructionConstants.OP_IXOR:
+ case InstructionConstants.OP_L2I:
+ case InstructionConstants.OP_F2I:
+ case InstructionConstants.OP_D2I:
+ case InstructionConstants.OP_I2B:
+ case InstructionConstants.OP_I2C:
+ case InstructionConstants.OP_I2S:
+ replaceIntegerPushInstruction(offset, simpleInstruction);
+ break;
+
+ case InstructionConstants.OP_LALOAD:
+ case InstructionConstants.OP_LADD:
+ case InstructionConstants.OP_LSUB:
+ case InstructionConstants.OP_LMUL:
+ case InstructionConstants.OP_LDIV:
+ case InstructionConstants.OP_LREM:
+ case InstructionConstants.OP_LNEG:
+ case InstructionConstants.OP_LSHL:
+ case InstructionConstants.OP_LSHR:
+ case InstructionConstants.OP_LUSHR:
+ case InstructionConstants.OP_LAND:
+ case InstructionConstants.OP_LOR:
+ case InstructionConstants.OP_LXOR:
+ case InstructionConstants.OP_I2L:
+ case InstructionConstants.OP_F2L:
+ case InstructionConstants.OP_D2L:
+ replaceLongPushInstruction(offset, simpleInstruction);
+ break;
+
+ case InstructionConstants.OP_FALOAD:
+ case InstructionConstants.OP_FADD:
+ case InstructionConstants.OP_FSUB:
+ case InstructionConstants.OP_FMUL:
+ case InstructionConstants.OP_FDIV:
+ case InstructionConstants.OP_FREM:
+ case InstructionConstants.OP_FNEG:
+ case InstructionConstants.OP_I2F:
+ case InstructionConstants.OP_L2F:
+ case InstructionConstants.OP_D2F:
+ replaceFloatPushInstruction(offset, simpleInstruction);
+ break;
+
+ case InstructionConstants.OP_DALOAD:
+ case InstructionConstants.OP_DADD:
+ case InstructionConstants.OP_DSUB:
+ case InstructionConstants.OP_DMUL:
+ case InstructionConstants.OP_DDIV:
+ case InstructionConstants.OP_DREM:
+ case InstructionConstants.OP_DNEG:
+ case InstructionConstants.OP_I2D:
+ case InstructionConstants.OP_L2D:
+ case InstructionConstants.OP_F2D:
+ replaceDoublePushInstruction(offset, simpleInstruction);
+ break;
+
+ case InstructionConstants.OP_AALOAD:
+ replaceReferencePushInstruction(offset, simpleInstruction);
+ break;
+ }
+ }
+ }
+
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ if (isTraced(offset))
+ {
+ switch (variableInstruction.opcode)
+ {
+ case InstructionConstants.OP_ILOAD:
+ case InstructionConstants.OP_ILOAD_0:
+ case InstructionConstants.OP_ILOAD_1:
+ case InstructionConstants.OP_ILOAD_2:
+ case InstructionConstants.OP_ILOAD_3:
+ replaceIntegerPushInstruction(offset, variableInstruction);
+ break;
+
+ case InstructionConstants.OP_LLOAD:
+ case InstructionConstants.OP_LLOAD_0:
+ case InstructionConstants.OP_LLOAD_1:
+ case InstructionConstants.OP_LLOAD_2:
+ case InstructionConstants.OP_LLOAD_3:
+ replaceLongPushInstruction(offset, variableInstruction);
+ break;
+
+ case InstructionConstants.OP_FLOAD:
+ case InstructionConstants.OP_FLOAD_0:
+ case InstructionConstants.OP_FLOAD_1:
+ case InstructionConstants.OP_FLOAD_2:
+ case InstructionConstants.OP_FLOAD_3:
+ replaceFloatPushInstruction(offset, variableInstruction);
+ break;
+
+ case InstructionConstants.OP_DLOAD:
+ case InstructionConstants.OP_DLOAD_0:
+ case InstructionConstants.OP_DLOAD_1:
+ case InstructionConstants.OP_DLOAD_2:
+ case InstructionConstants.OP_DLOAD_3:
+ replaceDoublePushInstruction(offset, variableInstruction);
+ break;
+
+ case InstructionConstants.OP_ALOAD:
+ case InstructionConstants.OP_ALOAD_0:
+ case InstructionConstants.OP_ALOAD_1:
+ case InstructionConstants.OP_ALOAD_2:
+ case InstructionConstants.OP_ALOAD_3:
+ replaceReferencePushInstruction(offset, variableInstruction);
+ break;
+
+ }
+ }
+ }
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ // Make sure 'new' instructions (or subsequent 'dup' instructions)
+ // depend on the subsequent initializer calls, in case these calls
+ // are marked as not having any side effects.
+ if (isTraced(offset) &&
+ cpInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL)
+ {
+ // Check if the invoked method is an initalizer.
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+
+ if (isInitializer)
+ {
+ // Find the previous instruction (assuming there was no branch).
+ int previousOffset = offset - 1;
+ while (!isTraced(previousOffset))
+ {
+ previousOffset--;
+ }
+
+ // Compute the stack index of the uninitialized object.
+ int stackIndex = stacks[offset].size();
+
+ // Get the (first and presumably only) offset of the instruction
+ // that put it there. This is typically a dup instruction.
+ int newOffset = stacks[previousOffset].getBottomTraceValue(stackIndex).instructionOffsetValue().instructionOffset(0);
+
+ // Add a reverse dependency. The source instruction depends on
+ // the initializer instruction, thus making sure that the latter
+ // is preserved whenever the former is used.
+ stackTraceValues[newOffset] = stackTraceValues[newOffset].generalize(InstructionOffsetValueFactory.create(offset)).instructionOffsetValue();
+ }
+ }
+ }
+
+
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
+ {
+ replaceBranchInstruction(offset, branchInstruction);
+ }
+
+
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ replaceBranchInstruction(offset, tableSwitchInstruction);
+ }
+
+
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ replaceBranchInstruction(offset, lookUpSwitchInstruction);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Replaces the given integer instruction by a simpler push instruction,
+ * if possible.
+ */
+ private void replaceIntegerPushInstruction(int offset, Instruction instruction)
+ {
+ Stack stack = stacks[offset];
+ Value pushedValue = stack.getTop(0);
+ if (pushedValue.isSpecific())
+ {
+ int value = pushedValue.integerValue().value();
+ if (value << 16 >> 16 == value)
+ {
+ replacePushInstruction(offset,
+ InstructionConstants.OP_SIPUSH,
+ value);
+ }
+ }
+ }
+
+
+ /**
+ * Replaces the given long instruction by a simpler push instruction,
+ * if possible.
+ */
+ private void replaceLongPushInstruction(int offset, Instruction instruction)
+ {
+ Stack stack = stacks[offset];
+ Value pushedValue = stack.getTop(0);
+ if (pushedValue.isSpecific())
+ {
+ long value = pushedValue.longValue().value();
+ if (value == 0L ||
+ value == 1L)
+ {
+ replacePushInstruction(offset,
+ (byte)(InstructionConstants.OP_LCONST_0 + value),
+ 0);
+ }
+ }
+ }
+
+
+ /**
+ * Replaces the given float instruction by a simpler push instruction,
+ * if possible.
+ */
+ private void replaceFloatPushInstruction(int offset, Instruction instruction)
+ {
+ Stack stack = stacks[offset];
+ Value pushedValue = stack.getTop(0);
+ if (pushedValue.isSpecific())
+ {
+ float value = pushedValue.floatValue().value();
+ if (value == 0f ||
+ value == 1f ||
+ value == 2f)
+ {
+ replacePushInstruction(offset,
+ (byte)(InstructionConstants.OP_FCONST_0 + value),
+ 0);
+ }
+ }
+ }
+
+
+ /**
+ * Replaces the given double instruction by a simpler push instruction,
+ * if possible.
+ */
+ private void replaceDoublePushInstruction(int offset, Instruction instruction)
+ {
+ Stack stack = stacks[offset];
+ Value pushedValue = stack.getTop(0);
+ if (pushedValue.isSpecific())
+ {
+ double value = pushedValue.doubleValue().value();
+ if (value == 0.0 ||
+ value == 1.0)
+ {
+ replacePushInstruction(offset,
+ (byte)(InstructionConstants.OP_DCONST_0 + value),
+ 0);
+ }
+ }
+ }
+
+
+ /**
+ * Replaces the given reference instruction by a simpler push instruction,
+ * if possible.
+ */
+ private void replaceReferencePushInstruction(int offset, Instruction instruction)
+ {
+ Stack stack = stacks[offset];
+ Value pushedValue = stack.getTop(0);
+ if (pushedValue.isSpecific())
+ {
+ ReferenceValue value = pushedValue.referenceValue();
+ if (value.isNull() == Value.ALWAYS)
+ {
+ replacePushInstruction(offset,
+ InstructionConstants.OP_ACONST_NULL,
+ 0);
+ }
+ }
+ }
+
+
+ /**
+ * Replaces the instruction at a given offset by a given push instruction.
+ */
+ private void replacePushInstruction(int offset, byte opcode, int value)
+ {
+ // Remember the replacement instruction.
+ Instruction replacementInstruction =
+ new SimpleInstruction(opcode, value).shrink();
+
+ if (DEBUG_ANALYSIS) System.out.println(" Replacing instruction at ["+offset+"] by "+replacementInstruction.toString());
+
+ codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
+ }
+
+
+ /**
+ * Deletes the given branch instruction, or replaces it by a simpler branch
+ * instruction, if possible.
+ */
+ private void replaceBranchInstruction(int offset, Instruction instruction)
+ {
+ if (isTraced(offset))
+ {
+ InstructionOffsetValue branchTargetValue = branchTargetValues[offset];
+
+ // Is there exactly one branch target (not from a goto or jsr)?
+ if (branchTargetValue != null &&
+ branchTargetValue.instructionOffsetCount() == 1 &&
+ instruction.opcode != InstructionConstants.OP_GOTO &&
+ instruction.opcode != InstructionConstants.OP_GOTO_W &&
+ instruction.opcode != InstructionConstants.OP_JSR &&
+ instruction.opcode != InstructionConstants.OP_JSR_W)
+ {
+ // Is it branching to the next instruction?
+ int branchOffset = branchTargetValue.instructionOffset(0) - offset;
+ if (branchOffset == instruction.length(offset))
+ {
+ if (DEBUG_ANALYSIS) System.out.println(" Deleting zero branch instruction at ["+offset+"]");
+
+ // Delete the branch instruction.
+ codeAttrInfoEditor.deleteInstruction(offset);
+ }
+ else
+ {
+ // Replace the branch instruction by a simple branch instrucion.
+ Instruction replacementInstruction =
+ new BranchInstruction(InstructionConstants.OP_GOTO_W,
+ branchOffset).shrink();
+
+ if (DEBUG_ANALYSIS) System.out.println(" Replacing branch instruction at ["+offset+"] by "+replacementInstruction.toString());
+
+ codeAttrInfoEditor.replaceInstruction2(offset,
+ replacementInstruction);
+ }
+ }
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ isInitializer = methodrefCpInfo.getName(classFile).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns whether any of the instructions at the given offsets are marked as
+ * necessary.
+ */
+ private boolean isAnyNecessary(InstructionOffsetValue traceValue)
+ {
+ int traceCount = traceValue.instructionOffsetCount();
+ if (traceCount == 0)
+ {
+ return true;
+ }
+
+ for (int traceIndex = 0; traceIndex < traceCount; traceIndex++)
+ {
+ if (isNecessary[traceValue.instructionOffset(traceIndex)])
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether all of the instructions at the given offsets are marked as
+ * necessary.
+ */
+ private boolean isAllNecessary(InstructionOffsetValue traceValue)
+ {
+ int traceCount = traceValue.instructionOffsetCount();
+ for (int traceIndex = 0; traceIndex < traceCount; traceIndex++)
+ {
+ if (!isNecessary[traceValue.instructionOffset(traceIndex)])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset has ever been
+ * executed during the partial evaluation.
+ */
+ private boolean isTraced(int instructionOffset)
+ {
+ return evaluationCounts[instructionOffset] > 0;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/Processor.java b/src/proguard/optimize/evaluation/Processor.java
new file mode 100644
index 0000000..409bea4
--- /dev/null
+++ b/src/proguard/optimize/evaluation/Processor.java
@@ -0,0 +1,997 @@
+/* $Id: Processor.java,v 1.12 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.util.ClassUtil;
+import proguard.classfile.visitor.*;
+import proguard.optimize.evaluation.value.*;
+
+/**
+ * This InstructionVisitor executes the instructions that it visits on a given
+ * local variable frame and stack.
+ *
+ * @author Eric Lafortune
+ */
+public class Processor
+implements InstructionVisitor,
+ CpInfoVisitor
+{
+ private Variables variables;
+ private Stack stack;
+ private BranchUnit branchUnit;
+
+ // Fields acting as return parameters for the CpInfoVisitor methods.
+ private int parameterCount;
+ private Value cpValue;
+ private ClassFile referencedClassFile;
+ private int referencedTypeDimensionCount;
+
+
+ /**
+ * Creates a new processor that operates on the given environment.
+ * @param variables the local variable frame.
+ * @param stack the local stack.
+ * @param branchUnit the class that can affect the program counter.
+ */
+ public Processor(Variables variables,
+ Stack stack,
+ BranchUnit branchUnit)
+ {
+ this.variables = variables;
+ this.stack = stack;
+ this.branchUnit = branchUnit;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_NOP:
+ break;
+
+ case InstructionConstants.OP_ACONST_NULL:
+ stack.push(ReferenceValueFactory.createNull());
+ break;
+
+ case InstructionConstants.OP_ICONST_M1:
+ case InstructionConstants.OP_ICONST_0:
+ case InstructionConstants.OP_ICONST_1:
+ case InstructionConstants.OP_ICONST_2:
+ case InstructionConstants.OP_ICONST_3:
+ case InstructionConstants.OP_ICONST_4:
+ case InstructionConstants.OP_ICONST_5:
+ case InstructionConstants.OP_BIPUSH:
+ case InstructionConstants.OP_SIPUSH:
+ stack.push(IntegerValueFactory.create(simpleInstruction.constant));
+ break;
+
+ case InstructionConstants.OP_LCONST_0:
+ case InstructionConstants.OP_LCONST_1:
+ stack.push(LongValueFactory.create(simpleInstruction.constant));
+ break;
+
+ case InstructionConstants.OP_FCONST_0:
+ case InstructionConstants.OP_FCONST_1:
+ case InstructionConstants.OP_FCONST_2:
+ stack.push(FloatValueFactory.create((float)simpleInstruction.constant));
+ break;
+
+ case InstructionConstants.OP_DCONST_0:
+ case InstructionConstants.OP_DCONST_1:
+ stack.push(DoubleValueFactory.create((double)simpleInstruction.constant));
+ break;
+
+ case InstructionConstants.OP_IALOAD:
+ case InstructionConstants.OP_BALOAD:
+ case InstructionConstants.OP_CALOAD:
+ case InstructionConstants.OP_SALOAD:
+ stack.ipop();
+ stack.apop();
+ stack.push(IntegerValueFactory.create());
+ break;
+
+ case InstructionConstants.OP_LALOAD:
+ stack.ipop();
+ stack.apop();
+ stack.push(LongValueFactory.create());
+ break;
+
+ case InstructionConstants.OP_FALOAD:
+ stack.ipop();
+ stack.apop();
+ stack.push(FloatValueFactory.create());
+ break;
+
+ case InstructionConstants.OP_DALOAD:
+ stack.ipop();
+ stack.apop();
+ stack.push(DoubleValueFactory.create());
+ break;
+
+ case InstructionConstants.OP_AALOAD:
+ stack.ipop();
+ stack.apop();
+ stack.push(ReferenceValueFactory.create(true));
+ break;
+
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ stack.ipop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_LASTORE:
+ stack.lpop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_FASTORE:
+ stack.fpop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_DASTORE:
+ stack.dpop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_AASTORE:
+ stack.apop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_POP:
+ stack.pop1();
+ break;
+
+ case InstructionConstants.OP_POP2:
+ stack.pop2();
+ break;
+
+ case InstructionConstants.OP_DUP:
+ stack.dup();
+ break;
+
+ case InstructionConstants.OP_DUP_X1:
+ stack.dup_x1();
+ break;
+
+ case InstructionConstants.OP_DUP_X2:
+ stack.dup_x2();
+ break;
+
+ case InstructionConstants.OP_DUP2:
+ stack.dup2();
+ break;
+
+ case InstructionConstants.OP_DUP2_X1:
+ stack.dup2_x1();
+ break;
+
+ case InstructionConstants.OP_DUP2_X2:
+ stack.dup2_x2();
+ break;
+
+ case InstructionConstants.OP_SWAP:
+ stack.swap();
+ break;
+
+ case InstructionConstants.OP_IADD:
+ stack.push(stack.ipop().add(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LADD:
+ stack.push(stack.lpop().add(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_FADD:
+ stack.push(stack.fpop().add(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DADD:
+ stack.push(stack.dpop().add(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_ISUB:
+ stack.push(stack.ipop().subtractFrom(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LSUB:
+ stack.push(stack.lpop().subtractFrom(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_FSUB:
+ stack.push(stack.fpop().subtractFrom(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DSUB:
+ stack.push(stack.dpop().subtractFrom(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_IMUL:
+ stack.push(stack.ipop().multiply(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LMUL:
+ stack.push(stack.lpop().multiply(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_FMUL:
+ stack.push(stack.fpop().multiply(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DMUL:
+ stack.push(stack.dpop().multiply(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_IDIV:
+ try
+ {
+ stack.push(stack.ipop().divideOf(stack.ipop()));
+ }
+ catch (ArithmeticException ex)
+ {
+ stack.push(IntegerValueFactory.create());
+ // TODO: Forward ArithmeticExceptions.
+ //stack.clear();
+ //stack.push(ReferenceValueFactory.create(false));
+ //branchUnit.throwException();
+ }
+ break;
+
+ case InstructionConstants.OP_LDIV:
+ stack.push(stack.lpop().divideOf(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_FDIV:
+ stack.push(stack.fpop().divideOf(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DDIV:
+ stack.push(stack.dpop().divideOf(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_IREM:
+ try
+ {
+ stack.push(stack.ipop().remainderOf(stack.ipop()));
+ }
+ catch (ArithmeticException ex)
+ {
+ stack.push(IntegerValueFactory.create());
+ // TODO: Forward ArithmeticExceptions.
+ //stack.clear();
+ //stack.push(ReferenceValueFactory.create(false));
+ //branchUnit.throwException();
+ }
+ break;
+
+ case InstructionConstants.OP_LREM:
+ stack.push(stack.lpop().remainderOf(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_FREM:
+ stack.push(stack.fpop().remainderOf(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DREM:
+ stack.push(stack.dpop().remainderOf(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_INEG:
+ stack.push(stack.ipop().negate());
+ break;
+
+ case InstructionConstants.OP_LNEG:
+ stack.push(stack.lpop().negate());
+ break;
+
+ case InstructionConstants.OP_FNEG:
+ stack.push(stack.fpop().negate());
+ break;
+
+ case InstructionConstants.OP_DNEG:
+ stack.push(stack.dpop().negate());
+ break;
+
+ case InstructionConstants.OP_ISHL:
+ stack.push(stack.ipop().shiftLeftOf(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LSHL:
+ stack.push(stack.ipop().shiftLeftOf(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_ISHR:
+ stack.push(stack.ipop().shiftRightOf(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LSHR:
+ stack.push(stack.ipop().shiftRightOf(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_IUSHR:
+ stack.push(stack.ipop().unsignedShiftRightOf(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LUSHR:
+ stack.push(stack.ipop().unsignedShiftRightOf(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_IAND:
+ stack.push(stack.ipop().and(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LAND:
+ stack.push(stack.lpop().and(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_IOR:
+ stack.push(stack.ipop().or(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LOR:
+ stack.push(stack.lpop().or(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_IXOR:
+ stack.push(stack.ipop().xor(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LXOR:
+ stack.push(stack.lpop().xor(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_I2L:
+ stack.push(stack.ipop().convertToLong());
+ break;
+
+ case InstructionConstants.OP_I2F:
+ stack.push(stack.ipop().convertToFloat());
+ break;
+
+ case InstructionConstants.OP_I2D:
+ stack.push(stack.ipop().convertToDouble());
+ break;
+
+ case InstructionConstants.OP_L2I:
+ stack.push(stack.lpop().convertToInteger());
+ break;
+
+ case InstructionConstants.OP_L2F:
+ stack.push(stack.lpop().convertToFloat());
+ break;
+
+ case InstructionConstants.OP_L2D:
+ stack.push(stack.lpop().convertToDouble());
+ break;
+
+ case InstructionConstants.OP_F2I:
+ stack.push(stack.fpop().convertToInteger());
+ break;
+
+ case InstructionConstants.OP_F2L:
+ stack.push(stack.fpop().convertToLong());
+ break;
+
+ case InstructionConstants.OP_F2D:
+ stack.push(stack.fpop().convertToDouble());
+ break;
+
+ case InstructionConstants.OP_D2I:
+ stack.push(stack.dpop().convertToInteger());
+ break;
+
+ case InstructionConstants.OP_D2L:
+ stack.push(stack.dpop().convertToLong());
+ break;
+
+ case InstructionConstants.OP_D2F:
+ stack.push(stack.dpop().convertToFloat());
+ break;
+
+ case InstructionConstants.OP_I2B:
+ stack.push(stack.ipop().convertToByte());
+ break;
+
+ case InstructionConstants.OP_I2C:
+ stack.push(stack.ipop().convertToCharacter());
+ break;
+
+ case InstructionConstants.OP_I2S:
+ stack.push(stack.ipop().convertToShort());
+ break;
+
+ case InstructionConstants.OP_LCMP:
+ stack.push(stack.lpop().compareReverse(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_FCMPL:
+ FloatValue floatValue1 = stack.fpop();
+ FloatValue floatValue2 = stack.fpop();
+ stack.push(floatValue2.compare(floatValue1));
+ break;
+
+ case InstructionConstants.OP_FCMPG:
+ stack.push(stack.fpop().compareReverse(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DCMPL:
+ DoubleValue doubleValue1 = stack.dpop();
+ DoubleValue doubleValue2 = stack.dpop();
+ stack.push(doubleValue2.compare(doubleValue1));
+ break;
+
+ case InstructionConstants.OP_DCMPG:
+ stack.push(stack.dpop().compareReverse(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_IRETURN:
+ branchUnit.returnFromMethod(stack.ipop());
+ break;
+
+ case InstructionConstants.OP_LRETURN:
+ branchUnit.returnFromMethod(stack.lpop());
+ break;
+
+ case InstructionConstants.OP_FRETURN:
+ branchUnit.returnFromMethod(stack.fpop());
+ break;
+
+ case InstructionConstants.OP_DRETURN:
+ branchUnit.returnFromMethod(stack.dpop());
+ break;
+
+ case InstructionConstants.OP_ARETURN:
+ branchUnit.returnFromMethod(stack.apop());
+ break;
+
+ case InstructionConstants.OP_RETURN:
+ branchUnit.returnFromMethod(null);
+ break;
+
+ case InstructionConstants.OP_NEWARRAY:
+ stack.ipop();
+ stack.push(ReferenceValueFactory.create(false));
+ break;
+
+ case InstructionConstants.OP_ARRAYLENGTH:
+ stack.apop();
+ stack.push(IntegerValueFactory.create());
+ break;
+
+ case InstructionConstants.OP_ATHROW:
+ ReferenceValue exceptionReferenceValue = stack.apop();
+ stack.clear();
+ stack.push(exceptionReferenceValue);
+ branchUnit.throwException();
+ break;
+
+ case InstructionConstants.OP_MONITORENTER:
+ case InstructionConstants.OP_MONITOREXIT:
+ stack.apop();
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown simple instruction ["+simpleInstruction.opcode+"]");
+ }
+ }
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ int cpIndex = cpInstruction.cpIndex;
+
+ switch (cpInstruction.opcode)
+ {
+ case InstructionConstants.OP_LDC:
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_LDC2_W:
+ case InstructionConstants.OP_GETSTATIC:
+ stack.push(cpValue(classFile, cpIndex));
+ break;
+
+ case InstructionConstants.OP_PUTSTATIC:
+ stack.pop();
+ break;
+
+ case InstructionConstants.OP_GETFIELD:
+ stack.apop();
+ stack.push(cpValue(classFile, cpIndex));
+ break;
+
+ case InstructionConstants.OP_PUTFIELD:
+ stack.pop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ Value cpValue = cpValue(classFile, cpIndex);
+ int parameterCount = parameterCount(classFile, cpIndex);
+
+ for (int counter = 0; counter < parameterCount; counter++)
+ {
+ stack.pop();
+ }
+ if (cpInstruction.opcode != InstructionConstants.OP_INVOKESTATIC)
+ {
+ stack.apop();
+ }
+ if (cpValue != null)
+ {
+ stack.push(cpValue);
+ }
+ break;
+
+ case InstructionConstants.OP_NEW:
+ stack.push(cpValue(classFile, cpIndex));
+ break;
+
+ case InstructionConstants.OP_ANEWARRAY:
+ stack.ipop();
+ stack.push(ReferenceValueFactory.create(referencedClassFile(classFile, cpIndex),
+ 1,
+ false));
+ break;
+
+ case InstructionConstants.OP_CHECKCAST:
+ // TODO: Check cast.
+ stack.push(stack.apop());
+ break;
+
+ case InstructionConstants.OP_INSTANCEOF:
+ int instanceOf = stack.apop().instanceOf(referencedClassFile(classFile, cpIndex),
+ referencedTypeDimensionCount(classFile, cpIndex));
+
+ stack.push(instanceOf == Value.NEVER ? IntegerValueFactory.create(0) :
+ instanceOf == Value.ALWAYS ? IntegerValueFactory.create(1) :
+ IntegerValueFactory.create());
+ break;
+
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ int dimensionCount = cpInstruction.constant;
+ for (int dimension = 0; dimension < dimensionCount; dimension++)
+ {
+ stack.ipop();
+ }
+ stack.push(cpValue(classFile, cpIndex));
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown constant pool instruction ["+cpInstruction.opcode+"]");
+ }
+ }
+
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ int variableIndex = variableInstruction.variableIndex;
+
+ switch (variableInstruction.opcode)
+ {
+ case InstructionConstants.OP_ILOAD:
+ case InstructionConstants.OP_ILOAD_0:
+ case InstructionConstants.OP_ILOAD_1:
+ case InstructionConstants.OP_ILOAD_2:
+ case InstructionConstants.OP_ILOAD_3:
+ stack.push(variables.iload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_LLOAD:
+ case InstructionConstants.OP_LLOAD_0:
+ case InstructionConstants.OP_LLOAD_1:
+ case InstructionConstants.OP_LLOAD_2:
+ case InstructionConstants.OP_LLOAD_3:
+ stack.push(variables.lload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_FLOAD:
+ case InstructionConstants.OP_FLOAD_0:
+ case InstructionConstants.OP_FLOAD_1:
+ case InstructionConstants.OP_FLOAD_2:
+ case InstructionConstants.OP_FLOAD_3:
+ stack.push(variables.fload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_DLOAD:
+ case InstructionConstants.OP_DLOAD_0:
+ case InstructionConstants.OP_DLOAD_1:
+ case InstructionConstants.OP_DLOAD_2:
+ case InstructionConstants.OP_DLOAD_3:
+ stack.push(variables.dload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_ALOAD:
+ case InstructionConstants.OP_ALOAD_0:
+ case InstructionConstants.OP_ALOAD_1:
+ case InstructionConstants.OP_ALOAD_2:
+ case InstructionConstants.OP_ALOAD_3:
+ stack.push(variables.aload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_ISTORE:
+ case InstructionConstants.OP_ISTORE_0:
+ case InstructionConstants.OP_ISTORE_1:
+ case InstructionConstants.OP_ISTORE_2:
+ case InstructionConstants.OP_ISTORE_3:
+ variables.store(variableIndex, stack.ipop());
+ break;
+
+ case InstructionConstants.OP_LSTORE:
+ case InstructionConstants.OP_LSTORE_0:
+ case InstructionConstants.OP_LSTORE_1:
+ case InstructionConstants.OP_LSTORE_2:
+ case InstructionConstants.OP_LSTORE_3:
+ variables.store(variableIndex, stack.lpop());
+ break;
+
+ case InstructionConstants.OP_FSTORE:
+ case InstructionConstants.OP_FSTORE_0:
+ case InstructionConstants.OP_FSTORE_1:
+ case InstructionConstants.OP_FSTORE_2:
+ case InstructionConstants.OP_FSTORE_3:
+ variables.store(variableIndex, stack.fpop());
+ break;
+
+ case InstructionConstants.OP_DSTORE:
+ case InstructionConstants.OP_DSTORE_0:
+ case InstructionConstants.OP_DSTORE_1:
+ case InstructionConstants.OP_DSTORE_2:
+ case InstructionConstants.OP_DSTORE_3:
+ variables.store(variableIndex, stack.dpop());
+ break;
+
+ case InstructionConstants.OP_ASTORE:
+ case InstructionConstants.OP_ASTORE_0:
+ case InstructionConstants.OP_ASTORE_1:
+ case InstructionConstants.OP_ASTORE_2:
+ case InstructionConstants.OP_ASTORE_3:
+ // The operand on the stack can be a reference or a return
+ // address, so we'll relax the pop operation.
+ //variables.store(variableIndex, stack.apop());
+ variables.store(variableIndex, stack.pop());
+ break;
+
+ case InstructionConstants.OP_IINC:
+ variables.store(variableIndex,
+ variables.iload(variableIndex).add(
+ IntegerValueFactory.create(variableInstruction.constant)));
+ break;
+
+ case InstructionConstants.OP_RET:
+ // The return address should be in the last offset of the
+ // given instruction offset variable (even though there may
+ // be other offsets).
+ InstructionOffsetValue instructionOffsetValue = variables.oload(variableIndex);
+ branchUnit.branch(classFile,
+ codeAttrInfo,
+ offset,
+ instructionOffsetValue.instructionOffset(instructionOffsetValue.instructionOffsetCount()-1));
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown variable instruction ["+variableInstruction.opcode+"]");
+ }
+ }
+
+
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
+ {
+ int branchTarget = offset + branchInstruction.branchOffset;
+
+ switch (branchInstruction.opcode)
+ {
+ case InstructionConstants.OP_IFEQ:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.ipop().equal(IntegerValueFactory.create(0)));
+ break;
+
+ case InstructionConstants.OP_IFNE:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.ipop().notEqual(IntegerValueFactory.create(0)));
+ break;
+
+ case InstructionConstants.OP_IFLT:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.ipop().lessThan(IntegerValueFactory.create(0)));
+ break;
+
+ case InstructionConstants.OP_IFGE:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.ipop().greaterThanOrEqual(IntegerValueFactory.create(0)));
+ break;
+
+ case InstructionConstants.OP_IFGT:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.ipop().greaterThan(IntegerValueFactory.create(0)));
+ break;
+
+ case InstructionConstants.OP_IFLE:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.ipop().lessThanOrEqual(IntegerValueFactory.create(0)));
+ break;
+
+
+ case InstructionConstants.OP_IFICMPEQ:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.ipop().equal(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFICMPNE:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.ipop().notEqual(stack.ipop()));
+ break;
+
+
+ case InstructionConstants.OP_IFICMPLT:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ -stack.ipop().lessThan(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFICMPGE:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ -stack.ipop().greaterThanOrEqual(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFICMPGT:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ -stack.ipop().greaterThan(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFICMPLE:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ -stack.ipop().lessThanOrEqual(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFACMPEQ:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.apop().equal(stack.apop()));
+ break;
+
+ case InstructionConstants.OP_IFACMPNE:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.apop().notEqual(stack.apop()));
+ break;
+
+ case InstructionConstants.OP_GOTO:
+ case InstructionConstants.OP_GOTO_W:
+ branchUnit.branch(classFile, codeAttrInfo, offset, branchTarget);
+ break;
+
+
+ case InstructionConstants.OP_JSR:
+ case InstructionConstants.OP_JSR_W:
+ stack.push(InstructionOffsetValueFactory.create(offset +
+ branchInstruction.length(offset)));
+ branchUnit.branch(classFile, codeAttrInfo, offset, branchTarget);
+ break;
+
+ case InstructionConstants.OP_IFNULL:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.apop().isNull());
+ break;
+
+ case InstructionConstants.OP_IFNONNULL:
+ branchUnit.branchConditionally(classFile, codeAttrInfo, offset, branchTarget,
+ stack.apop().isNotNull());
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown branch instruction ["+branchInstruction.opcode+"]");
+ }
+ }
+
+
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ IntegerValue indexValue = stack.ipop();
+
+ // If there is no definite branch in any of the cases below,
+ // branch to the default offset.
+ branchUnit.branch(classFile, codeAttrInfo,
+ offset,
+ offset + tableSwitchInstruction.defaultOffset);
+
+ for (int index = 0; index < tableSwitchInstruction.jumpOffsetCount; index++)
+ {
+ int conditional = indexValue.equal(IntegerValueFactory.create(
+ tableSwitchInstruction.lowCase + index));
+ branchUnit.branchConditionally(classFile, codeAttrInfo,
+ offset,
+ offset + tableSwitchInstruction.jumpOffsets[index],
+ conditional);
+
+ // If this branch is always taken, we can skip the rest.
+ if (conditional == Value.ALWAYS)
+ {
+ break;
+ }
+ }
+ }
+
+
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ IntegerValue indexValue = stack.ipop();
+
+ // If there is no definite branch in any of the cases below,
+ // branch to the default offset.
+ branchUnit.branch(classFile, codeAttrInfo,
+ offset,
+ offset + lookUpSwitchInstruction.defaultOffset);
+
+ for (int index = 0; index < lookUpSwitchInstruction.jumpOffsetCount; index++)
+ {
+ int conditional = indexValue.equal(IntegerValueFactory.create(
+ lookUpSwitchInstruction.cases[index]));
+ branchUnit.branchConditionally(classFile, codeAttrInfo,
+ offset,
+ offset + lookUpSwitchInstruction.jumpOffsets[index],
+ conditional);
+
+ // If this branch is always taken, we can skip the rest.
+ if (conditional == Value.ALWAYS)
+ {
+ break;
+ }
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo)
+ {
+ cpValue = IntegerValueFactory.create(integerCpInfo.getValue());
+ }
+
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo)
+ {
+ cpValue = LongValueFactory.create(longCpInfo.getValue());
+ }
+
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo)
+ {
+ cpValue = FloatValueFactory.create(floatCpInfo.getValue());
+ }
+
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo)
+ {
+ cpValue = DoubleValueFactory.create(doubleCpInfo.getValue());
+ }
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ cpValue = ReferenceValueFactory.create(false);
+ }
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ cpValue = ValueFactory.create(fieldrefCpInfo.getType(classFile));
+ }
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, interfaceMethodrefCpInfo);
+ }
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, methodrefCpInfo);
+ }
+
+ private void visitRefCpInfo(ClassFile classFile, RefCpInfo methodrefCpInfo)
+ {
+ String type = methodrefCpInfo.getType(classFile);
+
+ parameterCount = ClassUtil.internalMethodParameterCount(type);
+ cpValue = ValueFactory.create(ClassUtil.internalMethodReturnType(type));
+ }
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ String className = classCpInfo.getName(classFile);
+
+ referencedClassFile = classCpInfo.referencedClassFile;
+ referencedTypeDimensionCount = ClassUtil.internalArrayTypeDimensionCount(className);
+
+ cpValue = ReferenceValueFactory.create(referencedClassFile,
+ referencedTypeDimensionCount,
+ false);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the Value of the constant pool element at the given index.
+ * The element can be a constant, a field, a method,...
+ */
+ private Value cpValue(ClassFile classFile, int cpIndex)
+ {
+ // Visit the constant pool entry to get its return value.
+ classFile.constantPoolEntryAccept(cpIndex, this);
+
+ return cpValue;
+ }
+
+
+ /**
+ * Returns the class file referenced by the class constant pool entry at the
+ * given index.
+ */
+ private ClassFile referencedClassFile(ClassFile classFile, int cpIndex)
+ {
+ // Visit the constant pool entry to get its referenced class file.
+ classFile.constantPoolEntryAccept(cpIndex, this);
+
+ return referencedClassFile;
+ }
+
+
+ /**
+ * Returns the dimensionality of the class constant pool entry at the given
+ * index.
+ */
+ private int referencedTypeDimensionCount(ClassFile classFile, int cpIndex)
+ {
+ // Visit the constant pool entry to get its referenced class file.
+ //classFile.constantPoolEntryAccept(this, cpIndex);
+
+ // We'll return the value that was just computed.
+ return referencedTypeDimensionCount;
+ }
+
+
+ /**
+ * Returns the number of parameters of the method reference at the given
+ * constant pool index. This method must be invoked right after the
+ * cpValue(ClassFile,int) method.
+ */
+ private int parameterCount(ClassFile classFile, int methodRefCpIndex)
+ {
+ // Visit the method ref constant pool entry to get its parameter count.
+ //classFile.constantPoolEntryAccept(this, methodRefCpIndex);
+
+ // We'll return the value that was just computed.
+ return parameterCount;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/Stack.java b/src/proguard/optimize/evaluation/Stack.java
new file mode 100644
index 0000000..22b477e
--- /dev/null
+++ b/src/proguard/optimize/evaluation/Stack.java
@@ -0,0 +1,515 @@
+/* $Id: Stack.java,v 1.6 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation;
+
+import proguard.optimize.evaluation.value.*;
+
+/**
+ * This class represents an operand stack that contains <code>Value</code>
+ * objects.
+ *
+ * @author Eric Lafortune
+ */
+class Stack
+{
+ protected Value[] values;
+ protected int currentSize;
+ protected int actualMaxSize;
+
+
+ /**
+ * Creates a new Stack with a given maximum size, accounting for the double
+ * space required by Category 2 values.
+ */
+ public Stack(int maxSize)
+ {
+ values = new Value[maxSize];
+ }
+
+
+ /**
+ * Creates a Stack that is a copy of the given Stack.
+ */
+ public Stack(Stack stack)
+ {
+ // Create the values array.
+ this(stack.values.length);
+
+ // Copy the stack contents.
+ copy(stack);
+ }
+
+
+ /**
+ * Returns the actual maximum stack size that was required for all stack
+ * operations, accounting for the double space required by Category 2 values.
+ */
+ public int getActualMaxSize()
+ {
+ return actualMaxSize;
+ }
+
+
+ /**
+ * Resets this Stack, so that it can be reused.
+ */
+ public void reset(int maxSize)
+ {
+ // Is the values array large enough?
+ if (maxSize > values.length)
+ {
+ // Create a new one.
+ values = new Value[maxSize];
+ }
+
+ // Clear the sizes.
+ clear();
+
+ actualMaxSize = 0;
+ }
+
+
+ /**
+ * Copies the values of the given Stack into this Stack.
+ */
+ public void copy(Stack other)
+ {
+ // Is the values array large enough?
+ if (other.values.length > values.length)
+ {
+ // Create a new one.
+ values = new Value[other.values.length];
+ }
+
+ // Copy the stack contents.
+ System.arraycopy(other.values, 0, this.values, 0, other.currentSize);
+
+ // Copy the sizes.
+ currentSize = other.currentSize;
+ actualMaxSize = other.actualMaxSize;
+ }
+
+
+ /**
+ * Generalizes the values of this Stack with the values of the given Stack.
+ * The stacks must have the same current sizes.
+ * @return whether the generalization has made any difference.
+ */
+ public boolean generalize(Stack other)
+ {
+ if (this.currentSize != other.currentSize)
+ {
+ throw new IllegalArgumentException("Stacks have different current sizes ["+this.currentSize+"] and ["+other.currentSize+"]");
+ }
+
+ boolean changed = false;
+
+ // Generalize the stack values.
+ for (int index = 0; index < currentSize; index++)
+ {
+ Value otherValue = other.values[index];
+
+ if (otherValue != null)
+ {
+ Value thisValue = this.values[index];
+
+ if (thisValue != null)
+ {
+ otherValue = thisValue.generalize(otherValue);
+
+ changed = changed || !otherValue.equals(thisValue);
+ }
+
+ values[index] = otherValue;
+ }
+ }
+
+ // Check if the other stack extends beyond this one.
+ if (this.actualMaxSize < other.actualMaxSize)
+ {
+ this.actualMaxSize = other.actualMaxSize;
+ }
+
+ return changed;
+ }
+
+
+ /**
+ * Clears the stack.
+ */
+ public void clear()
+ {
+ // Clear the stack contents.
+ for (int index = 0; index < currentSize; index++)
+ {
+ values[index] = null;
+ }
+
+ currentSize = 0;
+ }
+
+
+ /**
+ * Returns the number of elements currently on the stack, accounting for the
+ * double space required by Category 2 values..
+ */
+ public int size()
+ {
+ return currentSize;
+ }
+
+
+ /**
+ * Gets the specified Value from the stack, without disturbing it.
+ * @param index the index of the stack element, counting from the bottom
+ * of the stack.
+ */
+ public Value getBottom(int index)
+ {
+ return values[index];
+ }
+
+
+ /**
+ * Gets the specified Value from the stack, without disturbing it.
+ * @param index the index of the stack element, counting from the top
+ * of the stack.
+ */
+ public Value getTop(int index)
+ {
+ return values[currentSize - index - 1];
+ }
+
+
+ /**
+ * Pushes the given Value onto the stack.
+ */
+ public void push(Value value)
+ {
+ // Account for the extra space required by Category 2 values.
+ if (value.isCategory2())
+ {
+ currentSize++;
+ }
+
+ // Push the value.
+ values[currentSize++] = value;
+
+ // Update the maximum actual size;
+ if (actualMaxSize < currentSize)
+ {
+ actualMaxSize = currentSize;
+ }
+ }
+
+
+ /**
+ * Pops the top Value from the stack.
+ */
+ public Value pop()
+ {
+ Value value = values[--currentSize];
+
+ values[currentSize] = null;
+
+ // Account for the extra space required by Category 2 values.
+ if (value.isCategory2())
+ {
+ values[--currentSize] = null;
+ }
+
+ return value;
+ }
+
+
+ // Pop methods that provide convenient casts to the expected value types.
+
+ /**
+ * Pops the top IntegerValue from the stack.
+ */
+ public IntegerValue ipop()
+ {
+ return pop().integerValue();
+ }
+
+
+ /**
+ * Pops the top LongValue from the stack.
+ */
+ public LongValue lpop()
+ {
+ return pop().longValue();
+ }
+
+
+ /**
+ * Pops the top FloatValue from the stack.
+ */
+ public FloatValue fpop()
+ {
+ return pop().floatValue();
+ }
+
+
+ /**
+ * Pops the top DoubleValue from the stack.
+ */
+ public DoubleValue dpop()
+ {
+ return pop().doubleValue();
+ }
+
+
+ /**
+ * Pops the top ReferenceValue from the stack.
+ */
+ public ReferenceValue apop()
+ {
+ return pop().referenceValue();
+ }
+
+
+ /**
+ * Pops the top InstructionOffsetValue from the stack.
+ */
+ public InstructionOffsetValue opop()
+ {
+ return pop().instructionOffsetValue();
+ }
+
+
+ /**
+ * Pops the top category 1 value from the stack.
+ */
+ public void pop1()
+ {
+ values[--currentSize] = null;
+ }
+
+
+ /**
+ * Pops the top category 2 value from the stack (or alternatively, two
+ * Category 1 stack elements).
+ */
+ public void pop2()
+ {
+ values[--currentSize] = null;
+ values[--currentSize] = null;
+ }
+
+
+ /**
+ * Duplicates the top Category 1 value.
+ */
+ public void dup()
+ {
+ values[currentSize] = values[currentSize - 1].category1Value();
+
+ currentSize++;
+
+ // Update the maximum actual size;
+ if (actualMaxSize < currentSize)
+ {
+ actualMaxSize = currentSize;
+ }
+ }
+
+
+ /**
+ * Duplicates the top Category 1 value, one Category 1 element down the
+ * stack.
+ */
+ public void dup_x1()
+ {
+ values[currentSize] = values[currentSize - 1].category1Value();
+ values[currentSize - 1] = values[currentSize - 2].category1Value();
+ values[currentSize - 2] = values[currentSize ];
+
+ currentSize++;
+
+ // Update the maximum actual size;
+ if (actualMaxSize < currentSize)
+ {
+ actualMaxSize = currentSize;
+ }
+ }
+
+
+ /**
+ * Duplicates the top Category 1 value, two Category 1 elements (or one
+ * Category 2 element) down the stack.
+ */
+ public void dup_x2()
+ {
+ values[currentSize] = values[currentSize - 1].category1Value();
+ values[currentSize - 1] = values[currentSize - 2];
+ values[currentSize - 2] = values[currentSize - 3];
+ values[currentSize - 3] = values[currentSize ];
+
+ currentSize++;
+
+ // Update the maximum actual size;
+ if (actualMaxSize < currentSize)
+ {
+ actualMaxSize = currentSize;
+ }
+ }
+
+ /**
+ * Duplicates the top Category 2 value (or alternatively, the equivalent
+ * Category 1 stack elements).
+ */
+ public void dup2()
+ {
+ values[currentSize ] = values[currentSize - 2];
+ values[currentSize + 1] = values[currentSize - 1];
+
+ currentSize += 2;
+
+ // Update the maximum actual size;
+ if (actualMaxSize < currentSize)
+ {
+ actualMaxSize = currentSize;
+ }
+ }
+
+
+ /**
+ * Duplicates the top Category 2 value, one Category 1 element down the
+ * stack (or alternatively, the equivalent Category 1 stack values).
+ */
+ public void dup2_x1()
+ {
+ values[currentSize + 1] = values[currentSize - 1];
+ values[currentSize ] = values[currentSize - 2];
+ values[currentSize - 1] = values[currentSize - 3];
+ values[currentSize - 2] = values[currentSize + 1];
+ values[currentSize - 3] = values[currentSize ];
+
+ currentSize += 2;
+
+ // Update the maximum actual size;
+ if (actualMaxSize < currentSize)
+ {
+ actualMaxSize = currentSize;
+ }
+ }
+
+
+ /**
+ * Duplicates the top Category 2 value, one Category 2 stack element down
+ * the stack (or alternatively, the equivalent Category 1 stack values).
+ */
+ public void dup2_x2()
+ {
+ values[currentSize + 1] = values[currentSize - 1];
+ values[currentSize ] = values[currentSize - 2];
+ values[currentSize - 1] = values[currentSize - 3];
+ values[currentSize - 2] = values[currentSize - 4];
+ values[currentSize - 3] = values[currentSize + 1];
+ values[currentSize - 4] = values[currentSize ];
+
+ currentSize += 2;
+
+ // Update the maximum actual size;
+ if (actualMaxSize < currentSize)
+ {
+ actualMaxSize = currentSize;
+ }
+ }
+
+
+ /**
+ * Swaps the top two Category 1 values.
+ */
+ public void swap()
+ {
+ Value value1 = values[currentSize - 1].category1Value();
+ Value value2 = values[currentSize - 2].category1Value();
+
+ values[currentSize - 1] = value2;
+ values[currentSize - 2] = value1;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ Stack other = (Stack)object;
+
+ if (this.currentSize != other.currentSize)
+ {
+ return false;
+ }
+
+ for (int index = 0; index < currentSize; index++)
+ {
+ Value thisValue = this.values[index];
+ Value otherValue = other.values[index];
+ if (thisValue == null ? otherValue != null :
+ !thisValue.equals(otherValue))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ public int hashCode()
+ {
+ int hashCode = currentSize;
+
+ for (int index = 0; index < currentSize; index++)
+ {
+ Value value = values[index];
+ if (value != null)
+ {
+ hashCode ^= value.hashCode();
+ }
+ }
+
+ return hashCode;
+ }
+
+
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ for (int index = 0; index < currentSize; index++)
+ {
+ Value value = values[index];
+ buffer = buffer.append('[')
+ .append(value == null ? "empty" : value.toString())
+ .append(']');
+ }
+
+ return buffer.toString();
+ }
+}
diff --git a/src/proguard/optimize/evaluation/TracedBranchUnit.java b/src/proguard/optimize/evaluation/TracedBranchUnit.java
new file mode 100644
index 0000000..54c922c
--- /dev/null
+++ b/src/proguard/optimize/evaluation/TracedBranchUnit.java
@@ -0,0 +1,146 @@
+/* $Id: TracedBranchUnit.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.optimize.evaluation.value.*;
+
+/**
+ * This BranchUnit remembers the branch unit commands that are invoked on it.
+ *
+ * @author Eric Lafortune
+ */
+class TracedBranchUnit implements BranchUnit
+{
+ private static final boolean DEBUG = true;
+
+ private boolean wasCalled;
+ private InstructionOffsetValue traceBranchTargets;
+ private Value traceReturnValue;
+
+
+ /**
+ * Resets the flag that tells whether any of the branch unit commands was
+ * called.
+ */
+ public void resetCalled()
+ {
+ wasCalled = false;
+ }
+
+ /**
+ * Returns whether any of the branch unit commands was called.
+ */
+ public boolean wasCalled()
+ {
+ return wasCalled;
+ }
+
+
+ /**
+ * Sets the initial branch targets, which will be updated as the branch
+ * methods of the branch unit are called.
+ */
+ public void setTraceBranchTargets(InstructionOffsetValue branchTargets)
+ {
+ this.traceBranchTargets = branchTargets;
+ }
+
+ public InstructionOffsetValue getTraceBranchTargets()
+ {
+ return traceBranchTargets;
+ }
+
+
+ /**
+ * Sets the initial return Value, which will be generalized as the
+ * return method of the branch unit is called. The initial value may be
+ * null.
+ */
+ public void setTraceReturnValue(Value traceReturnValue)
+ {
+ this.traceReturnValue = traceReturnValue;
+ }
+
+ public Value getTraceReturnValue()
+ {
+ return traceReturnValue;
+ }
+
+
+ // Implementations for BranchUnit.
+
+ public void branch(ClassFile classFile,
+ CodeAttrInfo codeAttrInfo,
+ int offset,
+ int branchTarget)
+ {
+ branchConditionally(classFile,
+ codeAttrInfo,
+ offset,
+ branchTarget,
+ Value.ALWAYS);
+ }
+
+
+ public void branchConditionally(ClassFile classFile,
+ CodeAttrInfo codeAttrInfo,
+ int offset,
+ int branchTarget,
+ int conditional)
+ {
+ // Mark possible branches at the offset and at the branch target.
+ if (conditional != Value.NEVER)
+ {
+ InstructionOffsetValue branchTargetValue = InstructionOffsetValueFactory.create(branchTarget);
+
+ // Accumulate the branch targets for the evaluator.
+ traceBranchTargets = conditional == Value.ALWAYS ?
+ branchTargetValue :
+ traceBranchTargets.generalize(branchTargetValue).instructionOffsetValue();
+ }
+
+ wasCalled = true;
+ }
+
+
+ public void returnFromMethod(Value returnValue)
+ {
+ traceReturnValue = traceReturnValue == null ?
+ returnValue :
+ traceReturnValue.generalize(returnValue);
+
+ // Stop processing this block.
+ traceBranchTargets = InstructionOffsetValueFactory.create();
+
+ wasCalled = true;
+ }
+
+
+ public void throwException()
+ {
+ // Stop processing this block.
+ traceBranchTargets = InstructionOffsetValueFactory.create();
+
+ wasCalled = true;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/TracedStack.java b/src/proguard/optimize/evaluation/TracedStack.java
new file mode 100644
index 0000000..964a95b
--- /dev/null
+++ b/src/proguard/optimize/evaluation/TracedStack.java
@@ -0,0 +1,336 @@
+/* $Id: TracedStack.java,v 1.7 2004/11/20 15:06:55 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation;
+
+import proguard.optimize.evaluation.value.*;
+
+/**
+ * This Stack saves a given store Value along with each Value it stores, and
+ * at the same time generalizes a given trace Value with the store Value of
+ * each Value it loads. The store Value and the trace Value can be set; the
+ * generalized trace Value can be retrieved. The object is to store additional
+ * information along with the actual stack values, for instance to keep track
+ * of their origins.
+ *
+ * @author Eric Lafortune
+ */
+class TracedStack extends Stack
+{
+ private Stack traceStack;
+ private Value storeValue;
+ private Value traceValue;
+
+
+ public TracedStack(int maxSize)
+ {
+ super(maxSize);
+
+ traceStack = new Stack(maxSize);
+ }
+
+
+ public TracedStack(TracedStack tracedStack)
+ {
+ super(tracedStack);
+
+ traceStack = new Stack(tracedStack.traceStack);
+ }
+
+
+ /**
+ * Sets the Value that will be stored along with all store instructions.
+ */
+ public void setStoreValue(Value storeValue)
+ {
+ this.storeValue = storeValue;
+ }
+
+
+ /**
+ * Sets the initial Value with which all values stored along with load
+ * instructions will be generalized.
+ */
+ public void setTraceValue(Value traceValue)
+ {
+ this.traceValue = traceValue;
+ }
+
+ public Value getTraceValue()
+ {
+ return traceValue;
+ }
+
+
+ /**
+ * Gets the specified trace Value from the stack, without disturbing it.
+ * @param index the index of the stack element, counting from the bottom
+ * of the stack.
+ */
+ public Value getBottomTraceValue(int index)
+ {
+ return traceStack.getBottom(index);
+ }
+
+
+ /**
+ * Gets the specified trace Value from the stack, without disturbing it.
+ * @param index the index of the stack element, counting from the top
+ * of the stack.
+ */
+ public Value getTopTraceValue(int index)
+ {
+ return traceStack.getTop(index);
+ }
+
+
+ // Implementations for Stack.
+
+ public void reset(int size)
+ {
+ super.reset(size);
+
+ traceStack.reset(size);
+ }
+
+ public void copy(TracedStack other)
+ {
+ super.copy(other);
+
+ traceStack.copy(other.traceStack);
+ }
+
+ public boolean generalize(TracedStack other)
+ {
+ return
+ super.generalize(other) |
+ traceStack.generalize(other.traceStack);
+ }
+
+ public void clear()
+ {
+ super.clear();
+
+ traceStack.clear();
+ }
+
+ public void push(Value value)
+ {
+ super.push(value);
+
+ tracePush();
+
+ // Account for the extra space required by Category 2 values.
+ if (value.isCategory2())
+ {
+ tracePush();
+ }
+ }
+
+ public Value pop()
+ {
+ Value value = super.pop();
+
+ tracePop();
+
+ // Account for the extra space required by Category 2 values.
+ if (value.isCategory2())
+ {
+ tracePop();
+ }
+
+ return value;
+ }
+
+ public void pop1()
+ {
+ super.pop1();
+
+ tracePop();
+ }
+
+ public void pop2()
+ {
+ super.pop2();
+
+ tracePop();
+ tracePop();
+ }
+
+ public void dup()
+ {
+ super.dup();
+
+ // For now, we're letting all stack values that are somehow involved
+ // depend on this instruction.
+ Value tracePopValue = tracePop();
+
+ tracePush();
+ traceStack.push(tracePopValue);
+ }
+
+ public void dup_x1()
+ {
+ super.dup_x1();
+
+ // Let the duplicated value depend on this instruction.
+ Value tracePopValue = tracePop();
+ Value traceSkipValue = traceStack.pop();
+
+ tracePush();
+ traceStack.push(traceSkipValue);
+ traceStack.push(tracePopValue);
+ }
+
+ public void dup_x2()
+ {
+ super.dup_x2();
+
+ // Let the duplicated value depend on this instruction.
+ Value tracePopValue = tracePop();
+ Value traceSkipValue1 = traceStack.pop();
+ Value traceSkipValue2 = traceStack.pop();
+
+ tracePush();
+ traceStack.push(traceSkipValue2);
+ traceStack.push(traceSkipValue1);
+ traceStack.push(tracePopValue);
+ }
+
+ public void dup2()
+ {
+ super.dup2();
+
+ // Let the duplicated value depend on this instruction.
+ Value tracePopValue1 = tracePop();
+ Value tracePopValue2 = tracePop();
+
+ tracePush();
+ tracePush();
+ traceStack.push(tracePopValue2);
+ traceStack.push(tracePopValue1);
+ }
+
+ public void dup2_x1()
+ {
+ super.dup2_x1();
+
+ // Let the duplicated value depend on this instruction.
+ Value tracePopValue1 = tracePop();
+ Value tracePopValue2 = tracePop();
+ Value traceSkipValue = traceStack.pop();
+
+ tracePush();
+ tracePush();
+ traceStack.push(traceSkipValue);
+ traceStack.push(tracePopValue2);
+ traceStack.push(tracePopValue1);
+ }
+
+ public void dup2_x2()
+ {
+ super.dup2_x2();
+
+ // Let the duplicated value depend on this instruction.
+ Value tracePopValue1 = tracePop();
+ Value tracePopValue2 = tracePop();
+ Value traceSkipValue1 = traceStack.pop();
+ Value traceSkipValue2 = traceStack.pop();
+
+ tracePush();
+ tracePush();
+ traceStack.push(traceSkipValue2);
+ traceStack.push(traceSkipValue1);
+ traceStack.push(tracePopValue2);
+ traceStack.push(tracePopValue1);
+ }
+
+ public void swap()
+ {
+ super.swap();
+
+ // Let one of the swapped values depend on this instruction.
+ tracePop();
+ Value traceSwapValue = traceStack.pop();
+
+ tracePush();
+ traceStack.push(traceSwapValue);
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ TracedStack other = (TracedStack)object;
+
+ return super.equals(object) && this.traceStack.equals(other.traceStack);
+ }
+
+
+ public int hashCode()
+ {
+ return super.hashCode() ^ traceStack.hashCode();
+ }
+
+
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ for (int index = 0; index < this.size(); index++)
+ {
+ Value value = this.values[index];
+ Value tracedValue = traceStack.values[index];
+ buffer = buffer.append('[')
+ .append(tracedValue == null ? "empty" : tracedValue.toString())
+ .append('>')
+ .append(value == null ? "empty" : value.toString())
+ .append(']');
+ }
+
+ return buffer.toString();
+ }
+
+
+ // Small utility methods.
+
+ private void tracePush()
+ {
+ traceStack.push(storeValue);
+ }
+
+
+ private Value tracePop()
+ {
+ Value popTraceValue = traceStack.pop();
+ if (traceValue != null)
+ {
+ traceValue = traceValue.generalize(popTraceValue);
+ }
+
+ return popTraceValue;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/TracedVariables.java b/src/proguard/optimize/evaluation/TracedVariables.java
new file mode 100644
index 0000000..77a5a33
--- /dev/null
+++ b/src/proguard/optimize/evaluation/TracedVariables.java
@@ -0,0 +1,191 @@
+/* $Id: TracedVariables.java,v 1.7 2004/11/20 15:06:55 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation;
+
+import proguard.optimize.evaluation.value.*;
+
+/**
+ * This Variables class saves a given store Value along with each Value it
+ * stores, and at the same time generalizes a given trace Value with the store
+ * Value of each Value it loads. The store Value and the trace Value can be set;
+ * the generalized trace Value can be retrieved. The object is to store
+ * additional information along with the actual variable values, for instance
+ * to keep track of their origins.
+ * <p>
+ * In addition, a boolean initialization flag can be reset and retrieved,
+ * indicating whether store operations on a variable may have initialized the
+ * variable.
+ *
+ * @author Eric Lafortune
+ */
+class TracedVariables extends Variables
+{
+ private Variables traceVariables;
+ private Value storeValue;
+ private Value traceValue;
+ private boolean initialization;
+
+
+ public TracedVariables(int size)
+ {
+ super(size);
+
+ traceVariables = new Variables(size);
+ }
+
+
+ public TracedVariables(TracedVariables tracedVariables)
+ {
+ super(tracedVariables);
+
+ traceVariables = new Variables(tracedVariables.traceVariables);
+ }
+
+
+ /**
+ * Sets the Value that will be stored along with all store instructions.
+ */
+ public void setStoreValue(Value storeValue)
+ {
+ this.storeValue = storeValue;
+ }
+
+
+ /**
+ * Sets the initial Value with which all values stored along with load
+ * instructions will be generalized.
+ */
+ public void setTraceValue(Value traceValue)
+ {
+ this.traceValue = traceValue;
+ }
+
+ public Value getTraceValue()
+ {
+ return traceValue;
+ }
+
+
+ /**
+ * Resets the initialization flag.
+ */
+ public void resetInitialization()
+ {
+ initialization = false;
+ }
+
+ public boolean wasInitialization()
+ {
+ return initialization;
+ }
+
+
+ // Implementations for Variables.
+
+ public void reset(int size)
+ {
+ super.reset(size);
+
+ traceVariables.reset(size);
+ }
+
+ public void initialize(TracedVariables other)
+ {
+ super.initialize(other);
+
+ traceVariables.initialize(other.traceVariables);
+ }
+
+ public boolean generalize(TracedVariables other)
+ {
+ return
+ super.generalize(other) |
+ traceVariables.generalize(other.traceVariables);
+ }
+
+ public void store(int index, Value value)
+ {
+ // Is this store operation an initialization of the variable?
+ Value previousValue = super.load(index);
+ initialization =
+ initialization ||
+ previousValue == null ||
+ previousValue.computationalType() != value.computationalType();
+
+ // Store the value itself in the variable.
+ super.store(index, value);
+
+ // Store the store value in its trace variable.
+ traceVariables.store(index, storeValue);
+ }
+
+ public Value load(int index)
+ {
+ // Load and accumulate the store value of the variable.
+ if (traceValue != null)
+ {
+ traceValue = traceValue.generalize(traceVariables.load(index));
+ }
+
+ // Return the value itself.
+ return super.load(index);
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ TracedVariables other = (TracedVariables)object;
+
+ return super.equals(object) && this.traceVariables.equals(other.traceVariables);
+ }
+
+
+ public int hashCode()
+ {
+ return super.hashCode() ^ traceVariables.hashCode();
+ }
+
+
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ for (int index = 0; index < this.size(); index++)
+ {
+ Value value = this.values[index];
+ Value tracedValue = traceVariables.values[index];
+ buffer = buffer.append('[')
+ .append(tracedValue == null ? "empty" : tracedValue.toString())
+ .append('>')
+ .append(value == null ? "empty" : value.toString())
+ .append(']');
+ }
+
+ return buffer.toString();
+ }
+}
diff --git a/src/proguard/optimize/evaluation/Variables.java b/src/proguard/optimize/evaluation/Variables.java
new file mode 100644
index 0000000..12070c7
--- /dev/null
+++ b/src/proguard/optimize/evaluation/Variables.java
@@ -0,0 +1,312 @@
+/* $Id: Variables.java,v 1.6 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation;
+
+import proguard.optimize.evaluation.value.*;
+
+/**
+ * This class represents a local variable frame that contains <code>Value</code>
+ * objects. Values are generalizations of all values that have been stored in
+ * the respective variables.
+ *
+ * @author Eric Lafortune
+ */
+class Variables
+{
+ protected Value[] values;
+ protected int size;
+
+
+ /**
+ * Creates a new Variables object with a given maximum number of variables.
+ */
+ public Variables(int size)
+ {
+ this.values = new Value[size];
+ this.size = size;
+ }
+
+
+ /**
+ * Creates a Variables object that is a copy of the given Variables object.
+ */
+ public Variables(Variables variables)
+ {
+ // Create the values array.
+ this(variables.size);
+
+ // Copy the values.
+ initialize(variables);
+ }
+
+
+ /**
+ * Resets this Variables object, so that it can be reused.
+ */
+ public void reset(int size)
+ {
+ // Is the values array large enough?
+ if (size > values.length)
+ {
+ // Create a new one.
+ values = new Value[size];
+ }
+ else
+ {
+ // Clear the variables.
+ for (int index = 0; index < values.length; index++)
+ {
+ values[index] = null;
+ }
+ }
+
+ this.size = size;
+ }
+
+
+ /**
+ * Initializes the values of this Variables object with the values of the
+ * given Variables object. The other object may have fewer values, in which
+ * case the remaining values are left unchanged.
+ */
+ public void initialize(Variables other)
+ {
+ if (this.size < other.size)
+ {
+ throw new IllegalArgumentException("Variable frame is too small ["+this.size+"] compared to other frame ["+other.size+"]");
+ }
+
+ // Copy the values.
+ System.arraycopy(other.values, 0, this.values, 0, other.size);
+ }
+
+
+ /**
+ * Generalizes the values of this Variables object with the values of the
+ * given Variables object. In case of conflicts, the other Variables
+ * object gets precedence.
+ * @return whether the generalization has made any difference.
+ */
+ public boolean generalize(Variables other)
+ {
+ if (this.size != other.size)
+ {
+ throw new IllegalArgumentException("Variable frames have different sizes ["+this.size+"] and ["+other.size+"]");
+ }
+
+ boolean changed = false;
+
+ for (int index = 0; index < size; index++)
+ {
+ Value otherValue = other.values[index];
+
+ if (otherValue != null)
+ {
+ Value thisValue = this.values[index];
+
+ // Occasionally, two values of different types might be
+ // present in the same variable in a variable frame
+ // (corresponding to two local variables that share the
+ // same index), at some point outside of their scopes.
+ // The new value gets precedence.
+ if (thisValue != null &&
+ thisValue.computationalType() == otherValue.computationalType())
+ {
+ otherValue = thisValue.generalize(otherValue);
+
+ changed = changed || !otherValue.equals(thisValue);
+ }
+
+ values[index] = otherValue;
+ }
+ }
+
+ return changed;
+ }
+
+
+ /**
+ * Returns the number of variables.
+ */
+ public int size()
+ {
+ return size;
+ }
+
+
+ /**
+ * Stores the given Value at the given variable index.
+ */
+ public void store(int index, Value value)
+ {
+ if (index < 0 ||
+ index >= size)
+ {
+ throw new IndexOutOfBoundsException("Variable index ["+index+"] out of bounds ["+size+"]");
+ }
+
+ // Store the value.
+ values[index] = value;
+ }
+
+
+ /**
+ * Loads the Value from the variable with the given index.
+ */
+ public Value load(int index)
+ {
+ if (index < 0 ||
+ index >= size)
+ {
+ throw new IndexOutOfBoundsException("Variable index ["+index+"] out of bounds ["+size+"]");
+ }
+
+ return values[index];
+ }
+
+
+ // Load methods that provide convenient casts to the expected value types.
+
+ /**
+ * Loads the IntegerValue from the variable with the given index.
+ */
+ public IntegerValue iload(int index)
+ {
+ return load(index).integerValue();
+ }
+
+
+ /**
+ * Loads the LongValue from the variable with the given index.
+ */
+ public LongValue lload(int index)
+ {
+ return load(index).longValue();
+ }
+
+
+ /**
+ * Loads the FloatValue from the variable with the given index.
+ */
+ public FloatValue fload(int index)
+ {
+ return load(index).floatValue();
+ }
+
+
+ /**
+ * Loads the DoubleValue from the variable with the given index.
+ */
+ public DoubleValue dload(int index)
+ {
+ return load(index).doubleValue();
+ }
+
+
+ /**
+ * Loads the ReferenceValue from the variable with the given index.
+ */
+ public ReferenceValue aload(int index)
+ {
+ return load(index).referenceValue();
+ }
+
+
+ /**
+ * Loads the InstructionOffsetValue from the variable with the given index.
+ */
+ public InstructionOffsetValue oload(int index)
+ {
+ return load(index).instructionOffsetValue();
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ Variables other = (Variables)object;
+
+ if (this.size != other.size)
+ {
+ return false;
+ }
+
+ for (int index = 0; index < size; index++)
+ {
+ Value thisValue = this.values[index];
+ Value otherValue = other.values[index];
+
+ // Occasionally, two values of different types might be
+ // present in the same variable in a variable frame
+ // (corresponding to two local variables that share the
+ // same index), at some point outside of their scopes.
+ // We'll ignore these.
+ if (thisValue != null &&
+ otherValue != null &&
+ thisValue.computationalType() == otherValue.computationalType() &&
+ !thisValue.equals(otherValue))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ public int hashCode()
+ {
+ int hashCode = size;
+
+ for (int index = 0; index < size; index++)
+ {
+ Value value = values[index];
+ if (value != null)
+ {
+ hashCode ^= value.hashCode();
+ }
+ }
+
+ return hashCode;
+ }
+
+
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ for (int index = 0; index < size; index++)
+ {
+ Value value = values[index];
+ buffer = buffer.append('[')
+ .append(value == null ? "empty" : value.toString())
+ .append(']');
+ }
+
+ return buffer.toString();
+ }
+}
diff --git a/src/proguard/optimize/evaluation/package.html b/src/proguard/optimize/evaluation/package.html
new file mode 100644
index 0000000..5341f9f
--- /dev/null
+++ b/src/proguard/optimize/evaluation/package.html
@@ -0,0 +1,4 @@
+<body>
+This package contains visitors that perform partial evaluation and subsequent
+optimizations on byte code.
+</body>
diff --git a/src/proguard/optimize/evaluation/value/Category1Value.java b/src/proguard/optimize/evaluation/value/Category1Value.java
new file mode 100644
index 0000000..da9d845
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/Category1Value.java
@@ -0,0 +1,41 @@
+/* $Id: Category1Value.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This abstract class represents a partially evaluated Category 1 value.
+ *
+ * @author Eric Lafortune
+ */
+abstract class Category1Value extends Value
+{
+ // Implementations for Value.
+
+ public final Category1Value category1Value()
+ {
+ return this;
+ }
+
+ public final boolean isCategory2()
+ {
+ return false;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/Category2Value.java b/src/proguard/optimize/evaluation/value/Category2Value.java
new file mode 100644
index 0000000..eccdef9
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/Category2Value.java
@@ -0,0 +1,41 @@
+/* $Id: Category2Value.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This abstract class represents a partially evaluated Category 2 value.
+ *
+ * @author Eric Lafortune
+ */
+abstract class Category2Value extends Value
+{
+ // Implementations for Value.
+
+ public final Category2Value category2Value()
+ {
+ return this;
+ }
+
+ public final boolean isCategory2()
+ {
+ return true;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/DoubleValue.java b/src/proguard/optimize/evaluation/value/DoubleValue.java
new file mode 100644
index 0000000..ead4ef8
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/DoubleValue.java
@@ -0,0 +1,312 @@
+/* $Id: DoubleValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class represents a partially evaluated double value.
+ *
+ * @author Eric Lafortune
+ */
+public class DoubleValue extends Category2Value
+{
+ /**
+ * Returns the specific double value, if applicable.
+ */
+ public double value()
+ {
+ return 0.0;
+ }
+
+
+ // Basic binary methods.
+
+ /**
+ * Returns the generalization of this DoubleValue and the given other
+ * DoubleValue.
+ */
+ public DoubleValue generalize(DoubleValue other)
+ {
+ return this;
+ }
+
+
+ /**
+ * Returns the sum of this DoubleValue and the given DoubleValue.
+ */
+ public DoubleValue add(DoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of this DoubleValue and the given DoubleValue.
+ */
+ public DoubleValue subtract(DoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of the given DoubleValue and this DoubleValue.
+ */
+ public DoubleValue subtractFrom(DoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the product of this DoubleValue and the given DoubleValue.
+ */
+ public DoubleValue multiply(DoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of this DoubleValue and the given DoubleValue.
+ */
+ public DoubleValue divide(DoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of the given DoubleValue and this DoubleValue.
+ */
+ public DoubleValue divideOf(DoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of this DoubleValue divided by the given DoubleValue.
+ */
+ public DoubleValue remainder(DoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of the given DoubleValue divided by this DoubleValue.
+ */
+ public DoubleValue remainderOf(DoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns an IntegerValue with value -1, 0, or 1, if this DoubleValue is
+ * less than, equal to, or greater than the given DoubleValue, respectively.
+ */
+ public IntegerValue compare(DoubleValue other)
+ {
+ return IntegerValueFactory.create();
+ }
+
+
+ // Derived binary methods.
+
+ /**
+ * Returns an IntegerValue with value 1, 0, or -1, if this DoubleValue is
+ * less than, equal to, or greater than the given DoubleValue, respectively.
+ */
+ public final IntegerValue compareReverse(DoubleValue other)
+ {
+ return compare(other).negate();
+ }
+
+
+ // Basic unary methods.
+
+ /**
+ * Returns the negated value of this DoubleValue.
+ */
+ public DoubleValue negate()
+ {
+ return this;
+ }
+
+ /**
+ * Converts this DoubleValue to an IntegerValue.
+ */
+ public IntegerValue convertToInteger()
+ {
+ return IntegerValueFactory.create();
+ }
+
+ /**
+ * Converts this DoubleValue to a LongValue.
+ */
+ public LongValue convertToLong()
+ {
+ return LongValueFactory.create();
+ }
+
+ /**
+ * Converts this DoubleValue to a FloatValue.
+ */
+ public FloatValue convertToFloat()
+ {
+ return FloatValueFactory.create();
+ }
+
+
+ // Similar binary methods, but this time with more specific arguments.
+
+ /**
+ * Returns the generalization of this DoubleValue and the given other
+ * SpecificDoubleValue.
+ */
+ public DoubleValue generalize(SpecificDoubleValue other)
+ {
+ return this;
+ }
+
+
+ /**
+ * Returns the sum of this DoubleValue and the given SpecificDoubleValue.
+ */
+ public DoubleValue add(SpecificDoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of this DoubleValue and the given SpecificDoubleValue.
+ */
+ public DoubleValue subtract(SpecificDoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of the given SpecificDoubleValue and this DoubleValue.
+ */
+ public DoubleValue subtractFrom(SpecificDoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the product of this DoubleValue and the given SpecificDoubleValue.
+ */
+ public DoubleValue multiply(SpecificDoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of this DoubleValue and the given SpecificDoubleValue.
+ */
+ public DoubleValue divide(SpecificDoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of the given SpecificDoubleValue and this
+ * DoubleValue.
+ */
+ public DoubleValue divideOf(SpecificDoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of this DoubleValue divided by the given
+ * SpecificDoubleValue.
+ */
+ public DoubleValue remainder(SpecificDoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of the given SpecificDoubleValue and this
+ * DoubleValue.
+ */
+ public DoubleValue remainderOf(SpecificDoubleValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns an IntegerValue with value -1, 0, or 1, if this DoubleValue is
+ * less than, equal to, or greater than the given SpecificDoubleValue,
+ * respectively.
+ */
+ public IntegerValue compare(SpecificDoubleValue other)
+ {
+ return IntegerValueFactory.create();
+ }
+
+
+ // Derived binary methods.
+
+ /**
+ * Returns an IntegerValue with value 1, 0, or -1, if this DoubleValue is
+ * less than, equal to, or greater than the given SpecificDoubleValue,
+ * respectively.
+ */
+ public final IntegerValue compareReverse(SpecificDoubleValue other)
+ {
+ return compare(other).negate();
+ }
+
+
+ // Implementations for Value.
+
+ public final DoubleValue doubleValue()
+ {
+ return this;
+ }
+
+ public final Value generalize(Value other)
+ {
+ return this.generalize(other.doubleValue());
+ }
+
+ public final int computationalType()
+ {
+ return TYPE_DOUBLE;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass();
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode();
+ }
+
+
+ public String toString()
+ {
+ return "d";
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/DoubleValueFactory.java b/src/proguard/optimize/evaluation/value/DoubleValueFactory.java
new file mode 100644
index 0000000..0f5862c
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/DoubleValueFactory.java
@@ -0,0 +1,53 @@
+/* $Id: DoubleValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class provides methods to create and reuse DoubleValue objects.
+ *
+ * @author Eric Lafortune
+ */
+public class DoubleValueFactory
+{
+ // Shared copies of DoubleValue objects, to avoid creating a lot of objects.
+ private static DoubleValue DOUBLE_VALUE = new DoubleValue();
+ private static SpecificDoubleValue DOUBLE_VALUE_0 = new SpecificDoubleValue(0.0);
+ private static SpecificDoubleValue DOUBLE_VALUE_1 = new SpecificDoubleValue(1.0);
+
+
+ /**
+ * Creates a new DoubleValue with an undefined value.
+ */
+ public static DoubleValue create()
+ {
+ return DOUBLE_VALUE;
+ }
+
+ /**
+ * Creates a new DoubleValue with a given specific value.
+ */
+ public static SpecificDoubleValue create(double value)
+ {
+ return value == 0.0 ? DOUBLE_VALUE_0 :
+ value == 1.0 ? DOUBLE_VALUE_1 :
+ new SpecificDoubleValue(value);
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/FloatValue.java b/src/proguard/optimize/evaluation/value/FloatValue.java
new file mode 100644
index 0000000..8d5b237
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/FloatValue.java
@@ -0,0 +1,312 @@
+/* $Id: FloatValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class represents a partially evaluated float value.
+ *
+ * @author Eric Lafortune
+ */
+public class FloatValue extends Category1Value
+{
+ /**
+ * Returns the specific float value, if applicable.
+ */
+ public float value()
+ {
+ return 0f;
+ }
+
+
+ // Basic binary methods.
+
+ /**
+ * Returns the generalization of this FloatValue and the given other
+ * FloatValue.
+ */
+ public FloatValue generalize(FloatValue other)
+ {
+ return this;
+ }
+
+
+ /**
+ * Returns the sum of this FloatValue and the given FloatValue.
+ */
+ public FloatValue add(FloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of this FloatValue and the given FloatValue.
+ */
+ public FloatValue subtract(FloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of the given FloatValue and this FloatValue.
+ */
+ public FloatValue subtractFrom(FloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the product of this FloatValue and the given FloatValue.
+ */
+ public FloatValue multiply(FloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of this FloatValue and the given FloatValue.
+ */
+ public FloatValue divide(FloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of the given FloatValue and this FloatValue.
+ */
+ public FloatValue divideOf(FloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of this FloatValue divided by the given FloatValue.
+ */
+ public FloatValue remainder(FloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of the given FloatValue divided by this FloatValue.
+ */
+ public FloatValue remainderOf(FloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns an IntegerValue with value -1, 0, or 1, if this FloatValue is
+ * less than, equal to, or greater than the given FloatValue, respectively.
+ */
+ public IntegerValue compare(FloatValue other)
+ {
+ return IntegerValueFactory.create();
+ }
+
+
+ // Derived binary methods.
+
+ /**
+ * Returns an IntegerValue with value 1, 0, or -1, if this FloatValue is
+ * less than, equal to, or greater than the given FloatValue, respectively.
+ */
+ public final IntegerValue compareReverse(FloatValue other)
+ {
+ return compare(other).negate();
+ }
+
+
+ // Basic unary methods.
+
+ /**
+ * Returns the negated value of this FloatValue.
+ */
+ public FloatValue negate()
+ {
+ return this;
+ }
+
+ /**
+ * Converts this FloatValue to an IntegerValue.
+ */
+ public IntegerValue convertToInteger()
+ {
+ return IntegerValueFactory.create();
+ }
+
+ /**
+ * Converts this FloatValue to a LongValue.
+ */
+ public LongValue convertToLong()
+ {
+ return LongValueFactory.create();
+ }
+
+ /**
+ * Converts this FloatValue to a DoubleValue.
+ */
+ public DoubleValue convertToDouble()
+ {
+ return DoubleValueFactory.create();
+ }
+
+
+ // Similar binary methods, but this time with more specific arguments.
+
+ /**
+ * Returns the generalization of this FloatValue and the given other
+ * SpecificFloatValue.
+ */
+ public FloatValue generalize(SpecificFloatValue other)
+ {
+ return this;
+ }
+
+
+ /**
+ * Returns the sum of this FloatValue and the given SpecificFloatValue.
+ */
+ public FloatValue add(SpecificFloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of this FloatValue and the given SpecificFloatValue.
+ */
+ public FloatValue subtract(SpecificFloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of the given SpecificFloatValue and this FloatValue.
+ */
+ public FloatValue subtractFrom(SpecificFloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the product of this FloatValue and the given SpecificFloatValue.
+ */
+ public FloatValue multiply(SpecificFloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of this FloatValue and the given SpecificFloatValue.
+ */
+ public FloatValue divide(SpecificFloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of the given SpecificFloatValue and this
+ * FloatValue.
+ */
+ public FloatValue divideOf(SpecificFloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of this FloatValue divided by the given
+ * SpecificFloatValue.
+ */
+ public FloatValue remainder(SpecificFloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of the given SpecificFloatValue and this
+ * FloatValue.
+ */
+ public FloatValue remainderOf(SpecificFloatValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns an IntegerValue with value -1, 0, or 1, if this FloatValue is
+ * less than, equal to, or greater than the given SpecificFloatValue,
+ * respectively.
+ */
+ public IntegerValue compare(SpecificFloatValue other)
+ {
+ return IntegerValueFactory.create();
+ }
+
+
+ // Derived binary methods.
+
+ /**
+ * Returns an IntegerValue with value 1, 0, or -1, if this FloatValue is
+ * less than, equal to, or greater than the given SpecificFloatValue,
+ * respectively.
+ */
+ public final IntegerValue compareReverse(SpecificFloatValue other)
+ {
+ return compare(other).negate();
+ }
+
+
+ // Implementations for Value.
+
+ public final FloatValue floatValue()
+ {
+ return this;
+ }
+
+ public final Value generalize(Value other)
+ {
+ return this.generalize(other.floatValue());
+ }
+
+ public final int computationalType()
+ {
+ return TYPE_FLOAT;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass();
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode();
+ }
+
+
+ public String toString()
+ {
+ return "f";
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/FloatValueFactory.java b/src/proguard/optimize/evaluation/value/FloatValueFactory.java
new file mode 100644
index 0000000..009989a
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/FloatValueFactory.java
@@ -0,0 +1,55 @@
+/* $Id: FloatValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class provides methods to create and reuse FloatValue objects.
+ *
+ * @author Eric Lafortune
+ */
+public class FloatValueFactory
+{
+ // Shared copies of FloatValue objects, to avoid creating a lot of objects.
+ private static FloatValue FLOAT_VALUE = new FloatValue();
+ private static SpecificFloatValue FLOAT_VALUE_0 = new SpecificFloatValue(0.0f);
+ private static SpecificFloatValue FLOAT_VALUE_1 = new SpecificFloatValue(1.0f);
+ private static SpecificFloatValue FLOAT_VALUE_2 = new SpecificFloatValue(2.0f);
+
+
+ /**
+ * Creates a new FloatValue with an undefined value.
+ */
+ public static FloatValue create()
+ {
+ return FLOAT_VALUE;
+ }
+
+ /**
+ * Creates a new FloatValue with a given specific value.
+ */
+ public static SpecificFloatValue create(float value)
+ {
+ return value == 0.0f ? FLOAT_VALUE_0 :
+ value == 1.0f ? FLOAT_VALUE_1 :
+ value == 2.0f ? FLOAT_VALUE_2 :
+ new SpecificFloatValue(value);
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/InstructionOffsetValue.java b/src/proguard/optimize/evaluation/value/InstructionOffsetValue.java
new file mode 100644
index 0000000..1f4c20b
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/InstructionOffsetValue.java
@@ -0,0 +1,237 @@
+/* $Id: InstructionOffsetValue.java,v 1.6 2004/12/04 19:34:42 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class represents a partially evaluated instruction offset. It can
+ * contain 0 or more specific instruction offsets.
+ *
+ * @author Eric Lafortune
+ */
+public class InstructionOffsetValue extends Category1Value
+{
+ private int[] values;
+
+
+ public InstructionOffsetValue()
+ {
+ }
+
+
+ public InstructionOffsetValue(int value)
+ {
+ this.values = new int[] { value };
+ }
+
+
+ public InstructionOffsetValue(int[] values)
+ {
+ this.values = values;
+ }
+
+
+ public int instructionOffsetCount()
+ {
+ return values == null ? 0 : values.length;
+ }
+
+
+ public int instructionOffset(int index)
+ {
+ return values[index];
+ }
+
+
+ /**
+ * Returns whether the given value is present in this list of instruction
+ * offsets.
+ */
+ public boolean contains(int value)
+ {
+ if (values != null)
+ {
+ for (int index = 0; index < values.length; index++)
+ {
+ if (values[index] == value)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns the generalization of this InstructionOffsetValue and the given
+ * other InstructionOffsetValue. The values of the other InstructionOffsetValue
+ * are guaranteed to remain at the end of the list, in the same order.
+ */
+ public final Value generalize(InstructionOffsetValue other)
+ {
+ // If the values array of either is null, return the other one.
+ if (this.values == null)
+ {
+ return other;
+ }
+
+ if (other.values == null)
+ {
+ return this;
+ }
+
+ // Compute the length of the union of the arrays.
+ int newLength = this.values.length;
+ for (int index = 0; index < other.values.length; index++)
+ {
+ if (!this.contains(other.values[index]))
+ {
+ newLength++;
+ }
+ }
+
+ // If the length of the union array is equal to the length of the values
+ // array of either, return it.
+ if (newLength == other.values.length)
+ {
+ return other;
+ }
+
+ // The ordering of the this array may not be right, so we can't just
+ // use it.
+ //if (newLength == this.values.length)
+ //{
+ // return this;
+ //}
+
+ // Create the union array.
+ int[] newValues = new int[newLength];
+
+ int newIndex = 0;
+
+ // Copy the values that are different from the other array.
+ for (int index = 0; index < this.values.length; index++)
+ {
+ if (!other.contains(this.values[index]))
+ {
+ newValues[newIndex++] = this.values[index];
+ }
+ }
+
+ // Copy the values from the other array.
+ for (int index = 0; index < other.values.length; index++)
+ {
+ newValues[newIndex++] = other.values[index];
+ }
+
+ return InstructionOffsetValueFactory.create(newValues);
+ }
+
+
+ // Implementations for Value.
+
+ public final InstructionOffsetValue instructionOffsetValue()
+ {
+ return this;
+ }
+
+ public final Value generalize(Value other)
+ {
+ return this.generalize(other.instructionOffsetValue());
+ }
+
+ public final int computationalType()
+ {
+ return TYPE_INSTRUCTION_OFFSET;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (object == null ||
+ this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ InstructionOffsetValue other = (InstructionOffsetValue)object;
+ if (this.values == other.values)
+ {
+ return true;
+ }
+
+ if (this.values == null ||
+ other.values == null ||
+ this.values.length != other.values.length)
+ {
+ return false;
+ }
+
+ for (int index = 0; index < other.values.length; index++)
+ {
+ if (!this.contains(other.values[index]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ public int hashCode()
+ {
+ int hashCode = this.getClass().hashCode();
+
+ if (values != null)
+ {
+ for (int index = 0; index < values.length; index++)
+ {
+ hashCode ^= values[index];
+ }
+ }
+
+ return hashCode;
+ }
+
+
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer("o:");
+
+ if (values != null)
+ {
+ for (int index = 0; index < values.length; index++)
+ {
+ if (index > 0)
+ {
+ buffer.append(',');
+ }
+ buffer.append(values[index]);
+ }
+ }
+
+ return buffer.toString();
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/InstructionOffsetValueFactory.java b/src/proguard/optimize/evaluation/value/InstructionOffsetValueFactory.java
new file mode 100644
index 0000000..2c68cbe
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/InstructionOffsetValueFactory.java
@@ -0,0 +1,59 @@
+/* $Id: InstructionOffsetValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class provides methods to create and reuse InstructionOffsetValue objects.
+ *
+ * @author Eric Lafortune
+ */
+public class InstructionOffsetValueFactory
+{
+ // Shared copies of InstructionOffsetValue objects, to avoid creating a lot of objects.
+ private static InstructionOffsetValue INSTRUCTION_OFFSET_VALUE = new InstructionOffsetValue();
+
+
+ /**
+ * Creates a new InstructionOffsetValue without a value.
+ */
+ public static InstructionOffsetValue create()
+ {
+ return INSTRUCTION_OFFSET_VALUE;
+ }
+
+
+ /**
+ * Creates a new InstructionOffsetValue with a given specific value.
+ */
+ public static InstructionOffsetValue create(int value)
+ {
+ return new InstructionOffsetValue(value);
+ }
+
+
+ /**
+ * Creates a new InstructionOffsetValue with a given list of possible values.
+ */
+ public static InstructionOffsetValue create(int[] values)
+ {
+ return new InstructionOffsetValue(values);
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/IntegerValue.java b/src/proguard/optimize/evaluation/value/IntegerValue.java
new file mode 100644
index 0000000..53d245a
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/IntegerValue.java
@@ -0,0 +1,622 @@
+/* $Id: IntegerValue.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class represents a partially evaluated integer value.
+ *
+ * @author Eric Lafortune
+ */
+public class IntegerValue extends Category1Value
+{
+ /**
+ * Returns the specific integer value, if applicable.
+ */
+ public int value()
+ {
+ return 0;
+ }
+
+
+ // Basic binary methods.
+
+ /**
+ * Returns the generalization of this IntegerValue and the given other
+ * IntegerValue.
+ */
+ public IntegerValue generalize(IntegerValue other)
+ {
+ return this;
+ }
+
+
+ /**
+ * Returns the sum of this IntegerValue and the given IntegerValue.
+ */
+ public IntegerValue add(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of this IntegerValue and the given IntegerValue.
+ */
+ public IntegerValue subtract(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of the given IntegerValue and this IntegerValue.
+ */
+ public IntegerValue subtractFrom(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the product of this IntegerValue and the given IntegerValue.
+ */
+ public IntegerValue multiply(IntegerValue other)
+ throws ArithmeticException
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of this IntegerValue and the given IntegerValue.
+ */
+ public IntegerValue divide(IntegerValue other)
+ throws ArithmeticException
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of the given IntegerValue and this IntegerValue.
+ */
+ public IntegerValue divideOf(IntegerValue other)
+ throws ArithmeticException
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of this IntegerValue divided by the given
+ * IntegerValue.
+ */
+ public IntegerValue remainder(IntegerValue other)
+ throws ArithmeticException
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of the given IntegerValue divided by this
+ * IntegerValue.
+ */
+ public IntegerValue remainderOf(IntegerValue other)
+ throws ArithmeticException
+ {
+ return this;
+ }
+
+ /**
+ * Returns this IntegerValue, shifted left by the given IntegerValue.
+ */
+ public IntegerValue shiftLeft(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the given IntegerValue, shifted left by this IntegerValue.
+ */
+ public IntegerValue shiftLeftOf(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns this IntegerValue, shifted right by the given IntegerValue.
+ */
+ public IntegerValue shiftRight(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the given IntegerValue, shifted right by this IntegerValue.
+ */
+ public IntegerValue shiftRightOf(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns this unsigned IntegerValue, shifted left by the given
+ * IntegerValue.
+ */
+ public IntegerValue unsignedShiftRight(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the given unsigned IntegerValue, shifted left by this
+ * IntegerValue.
+ */
+ public IntegerValue unsignedShiftRightOf(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the given LongValue, shifted left by this IntegerValue.
+ */
+ public LongValue shiftLeftOf(LongValue other)
+ {
+ return LongValueFactory.create();
+ }
+
+ /**
+ * Returns the given LongValue, shifted right by this IntegerValue.
+ */
+ public LongValue shiftRightOf(LongValue other)
+ {
+ return LongValueFactory.create();
+ }
+
+ /**
+ * Returns the given unsigned LongValue, shifted right by this IntegerValue.
+ */
+ public LongValue unsignedShiftRightOf(LongValue other)
+ {
+ return LongValueFactory.create();
+ }
+
+ /**
+ * Returns the logical <i>and</i> of this IntegerValue and the given
+ * IntegerValue.
+ */
+ public IntegerValue and(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>or</i> of this IntegerValue and the given
+ * IntegerValue.
+ */
+ public IntegerValue or(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>xor</i> of this IntegerValue and the given
+ * IntegerValue.
+ */
+ public IntegerValue xor(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns whether this IntegerValue and the given IntegerValue are equal:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public int equal(IntegerValue other)
+ {
+ return MAYBE;
+ }
+
+ /**
+ * Returns whether this IntegerValue is less than the given IntegerValue:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public int lessThan(IntegerValue other)
+ {
+ return MAYBE;
+ }
+
+ /**
+ * Returns whether this IntegerValue is less than or equal to the given
+ * IntegerValue: <code>NEVER</code>, <code>MAYBE</code>, or
+ * <code>ALWAYS</code>.
+ */
+ public int lessThanOrEqual(IntegerValue other)
+ {
+ return MAYBE;
+ }
+
+
+ // Derived binary methods.
+
+ /**
+ * Returns whether this IntegerValue and the given IntegerValue are different:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public final int notEqual(IntegerValue other)
+ {
+ return -equal(other);
+ }
+
+ /**
+ * Returns whether this IntegerValue is greater than the given IntegerValue:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public final int greaterThan(IntegerValue other)
+ {
+ return -lessThanOrEqual(other);
+ }
+
+ /**
+ * Returns whether this IntegerValue is greater than or equal to the given IntegerValue:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public final int greaterThanOrEqual(IntegerValue other)
+ {
+ return -lessThan(other);
+ }
+
+
+ // Basic unary methods.
+
+ /**
+ * Returns the negated value of this IntegerValue.
+ */
+ public IntegerValue negate()
+ {
+ return this;
+ }
+
+ /**
+ * Converts this IntegerValue to a byte IntegerValue.
+ */
+ public IntegerValue convertToByte()
+ {
+ return this;
+ }
+
+ /**
+ * Converts this IntegerValue to a character IntegerValue.
+ */
+ public IntegerValue convertToCharacter()
+ {
+ return this;
+ }
+
+ /**
+ * Converts this IntegerValue to a short IntegerValue.
+ */
+ public IntegerValue convertToShort()
+ {
+ return this;
+ }
+
+ /**
+ * Converts this IntegerValue to a LongValue.
+ */
+ public LongValue convertToLong()
+ {
+ return LongValueFactory.create();
+ }
+
+ /**
+ * Converts this IntegerValue to a FloatValue.
+ */
+ public FloatValue convertToFloat()
+ {
+ return FloatValueFactory.create();
+ }
+
+ /**
+ * Converts this IntegerValue to a DoubleValue.
+ */
+ public DoubleValue convertToDouble()
+ {
+ return DoubleValueFactory.create();
+ }
+
+
+ // Similar binary methods, but this time with more specific arguments.
+
+ /**
+ * Returns the generalization of this IntegerValue and the given other
+ * SpecificIntegerValue.
+ */
+ public IntegerValue generalize(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+
+ /**
+ * Returns the sum of this IntegerValue and the given SpecificIntegerValue.
+ */
+ public IntegerValue add(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of this IntegerValue and the given SpecificIntegerValue.
+ */
+ public IntegerValue subtract(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of the given SpecificIntegerValue and this IntegerValue.
+ */
+ public IntegerValue subtractFrom(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the product of this IntegerValue and the given SpecificIntegerValue.
+ */
+ public IntegerValue multiply(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of this IntegerValue and the given
+ * SpecificIntegerValue.
+ */
+ public IntegerValue divide(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of the given SpecificIntegerValue and this
+ * IntegerValue.
+ */
+ public IntegerValue divideOf(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of this IntegerValue divided by the given
+ * SpecificIntegerValue.
+ */
+ public IntegerValue remainder(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of the given SpecificIntegerValue divided by this
+ * IntegerValue.
+ */
+ public IntegerValue remainderOf(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns this IntegerValue, shifted left by the given SpecificIntegerValue.
+ */
+ public IntegerValue shiftLeft(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the given SpecificIntegerValue, shifted left by this IntegerValue.
+ */
+ public IntegerValue shiftLeftOf(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns this IntegerValue, shifted right by the given SpecificIntegerValue.
+ */
+ public IntegerValue shiftRight(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the given SpecificIntegerValue, shifted right by this IntegerValue.
+ */
+ public IntegerValue shiftRightOf(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns this unsigned IntegerValue, shifted right by the given
+ * SpecificIntegerValue.
+ */
+ public IntegerValue unsignedShiftRight(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the given unsigned SpecificIntegerValue, shifted right by this
+ * IntegerValue.
+ */
+ public IntegerValue unsignedShiftRightOf(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the given SpecificLongValue, shifted left by this IntegerValue.
+ */
+ public LongValue shiftLeftOf(SpecificLongValue other)
+ {
+ return LongValueFactory.create();
+ }
+
+ /**
+ * Returns the given SpecificLongValue, shifted right by this IntegerValue.
+ */
+ public LongValue shiftRightOf(SpecificLongValue other)
+ {
+ return LongValueFactory.create();
+ }
+
+ /**
+ * Returns the given unsigned SpecificLongValue, shifted right by this
+ * IntegerValue.
+ */
+ public LongValue unsignedShiftRightOf(SpecificLongValue other)
+ {
+ return LongValueFactory.create();
+ }
+
+ /**
+ * Returns the logical <i>and</i> of this IntegerValue and the given
+ * SpecificIntegerValue.
+ */
+ public IntegerValue and(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>or</i> of this IntegerValue and the given
+ * SpecificIntegerValue.
+ */
+ public IntegerValue or(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>xor</i> of this IntegerValue and the given
+ * SpecificIntegerValue.
+ */
+ public IntegerValue xor(SpecificIntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns whether this IntegerValue and the given SpecificIntegerValue are
+ * equal: <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public int equal(SpecificIntegerValue other)
+ {
+ return MAYBE;
+ }
+
+ /**
+ * Returns whether this IntegerValue is less than the given
+ * SpecificIntegerValue: <code>NEVER</code>, <code>MAYBE</code>, or
+ * <code>ALWAYS</code>.
+ */
+ public int lessThan(SpecificIntegerValue other)
+ {
+ return MAYBE;
+ }
+
+ /**
+ * Returns whether this IntegerValue is less than or equal to the given
+ * SpecificIntegerValue: <code>NEVER</code>, <code>MAYBE</code>, or
+ * <code>ALWAYS</code>.
+ */
+ public int lessThanOrEqual(SpecificIntegerValue other)
+ {
+ return MAYBE;
+ }
+
+
+ // Derived binary methods.
+
+ /**
+ * Returns whether this IntegerValue and the given SpecificIntegerValue are
+ * different: <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public final int notEqual(SpecificIntegerValue other)
+ {
+ return -equal(other);
+ }
+
+ /**
+ * Returns whether this IntegerValue is greater than the given
+ * SpecificIntegerValue: <code>NEVER</code>, <code>MAYBE</code>, or
+ * <code>ALWAYS</code>.
+ */
+ public final int greaterThan(SpecificIntegerValue other)
+ {
+ return -lessThanOrEqual(other);
+ }
+
+ /**
+ * Returns whether this IntegerValue is greater than or equal to the given
+ * SpecificIntegerValue: <code>NEVER</code>, <code>MAYBE</code>, or
+ * <code>ALWAYS</code>.
+ */
+ public final int greaterThanOrEqual(SpecificIntegerValue other)
+ {
+ return -lessThan(other);
+ }
+
+
+ // Implementations for Value.
+
+ public final IntegerValue integerValue()
+ {
+ return this;
+ }
+
+ public final Value generalize(Value other)
+ {
+ return this.generalize(other.integerValue());
+ }
+
+ public final int computationalType()
+ {
+ return TYPE_INTEGER;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass();
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode();
+ }
+
+
+ public String toString()
+ {
+ return "i";
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/IntegerValueFactory.java b/src/proguard/optimize/evaluation/value/IntegerValueFactory.java
new file mode 100644
index 0000000..19c3e04
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/IntegerValueFactory.java
@@ -0,0 +1,66 @@
+/* $Id: IntegerValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class provides methods to create and reuse IntegerValue objects.
+ *
+ * @author Eric Lafortune
+ */
+public class IntegerValueFactory
+{
+ // Shared copies of IntegerValue objects, to avoid creating a lot of objects.
+ private static IntegerValue INTEGER_VALUE = new IntegerValue();
+ private static SpecificIntegerValue INTEGER_VALUE_M1 = new SpecificIntegerValue(-1);
+ private static SpecificIntegerValue INTEGER_VALUE_0 = new SpecificIntegerValue(0);
+ private static SpecificIntegerValue INTEGER_VALUE_1 = new SpecificIntegerValue(1);
+ private static SpecificIntegerValue INTEGER_VALUE_2 = new SpecificIntegerValue(2);
+ private static SpecificIntegerValue INTEGER_VALUE_3 = new SpecificIntegerValue(3);
+ private static SpecificIntegerValue INTEGER_VALUE_4 = new SpecificIntegerValue(4);
+ private static SpecificIntegerValue INTEGER_VALUE_5 = new SpecificIntegerValue(5);
+
+ /**
+ * Creates a new IntegerValue with an undefined value.
+ */
+ public static IntegerValue create()
+ {
+ return INTEGER_VALUE;
+ }
+
+ /**
+ * Creates a new IntegerValue with a given specific value.
+ */
+ public static SpecificIntegerValue create(int value)
+ {
+ switch (value)
+ {
+ case -1: return INTEGER_VALUE_M1;
+ case 0: return INTEGER_VALUE_0;
+ case 1: return INTEGER_VALUE_1;
+ case 2: return INTEGER_VALUE_2;
+ case 3: return INTEGER_VALUE_3;
+ case 4: return INTEGER_VALUE_4;
+ case 5: return INTEGER_VALUE_5;
+ default: return new SpecificIntegerValue(value);
+ }
+ }
+
+}
diff --git a/src/proguard/optimize/evaluation/value/LongValue.java b/src/proguard/optimize/evaluation/value/LongValue.java
new file mode 100644
index 0000000..e625d38
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/LongValue.java
@@ -0,0 +1,390 @@
+/* $Id: LongValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class represents a partially evaluated long value.
+ *
+ * @author Eric Lafortune
+ */
+public class LongValue extends Category2Value
+{
+ /**
+ * Returns the specific long value, if applicable.
+ */
+ public long value()
+ {
+ return 0L;
+ }
+
+
+ // Basic binary methods.
+
+ /**
+ * Returns the generalization of this LongValue and the given other
+ * LongValue.
+ */
+ public LongValue generalize(LongValue other)
+ {
+ return this;
+ }
+
+
+ /**
+ * Returns the sum of this LongValue and the given LongValue.
+ */
+ public LongValue add(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of this LongValue and the given LongValue.
+ */
+ public LongValue subtract(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of the given LongValue and this LongValue.
+ */
+ public LongValue subtractFrom(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the product of this LongValue and the given LongValue.
+ */
+ public LongValue multiply(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of this LongValue and the given LongValue.
+ */
+ public LongValue divide(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of the given LongValue and this LongValue.
+ */
+ public LongValue divideOf(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of this LongValue divided by the given LongValue.
+ */
+ public LongValue remainder(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of the given LongValue divided by this LongValue.
+ */
+ public LongValue remainderOf(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns this LongValue, shifted left by the given IntegerValue.
+ */
+ public LongValue shiftLeft(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns this LongValue, shifted right by the given IntegerValue.
+ */
+ public LongValue shiftRight(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns this unsigned LongValue, shifted left by the given
+ * IntegerValue.
+ */
+ public LongValue unsignedShiftRight(IntegerValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>and</i> of this LongValue and the given
+ * LongValue.
+ */
+ public LongValue and(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>or</i> of this LongValue and the given
+ * LongValue.
+ */
+ public LongValue or(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>xor</i> of this LongValue and the given
+ * LongValue.
+ */
+ public LongValue xor(LongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns an IntegerValue with value -1, 0, or 1, if this LongValue is
+ * less than, equal to, or greater than the given LongValue, respectively.
+ */
+ public IntegerValue compare(LongValue other)
+ {
+ return IntegerValueFactory.create();
+ }
+
+
+ // Derived binary methods.
+
+ /**
+ * Returns an IntegerValue with value 1, 0, or -1, if this LongValue is
+ * less than, equal to, or greater than the given LongValue, respectively.
+ */
+ public final IntegerValue compareReverse(LongValue other)
+ {
+ return compare(other).negate();
+ }
+
+
+ // Basic unary methods.
+
+ /**
+ * Returns the negated value of this LongValue.
+ */
+ public LongValue negate()
+ {
+ return this;
+ }
+
+ /**
+ * Converts this LongValue to an IntegerValue.
+ */
+ public IntegerValue convertToInteger()
+ {
+ return IntegerValueFactory.create();
+ }
+
+ /**
+ * Converts this LongValue to a FloatValue.
+ */
+ public FloatValue convertToFloat()
+ {
+ return FloatValueFactory.create();
+ }
+
+ /**
+ * Converts this LongValue to a DoubleValue.
+ */
+ public DoubleValue convertToDouble()
+ {
+ return DoubleValueFactory.create();
+ }
+
+
+ // Similar binary methods, but this time with more specific arguments.
+
+ /**
+ * Returns the generalization of this LongValue and the given other
+ * SpecificLongValue.
+ */
+ public LongValue generalize(SpecificLongValue other)
+ {
+ return this;
+ }
+
+
+ /**
+ * Returns the sum of this LongValue and the given SpecificLongValue.
+ */
+ public LongValue add(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of this LongValue and the given SpecificLongValue.
+ */
+ public LongValue subtract(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the difference of the given SpecificLongValue and this LongValue.
+ */
+ public LongValue subtractFrom(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the product of this LongValue and the given SpecificLongValue.
+ */
+ public LongValue multiply(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of this LongValue and the given SpecificLongValue.
+ */
+ public LongValue divide(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the quotient of the given SpecificLongValue and this LongValue.
+ */
+ public LongValue divideOf(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of this LongValue divided by the given
+ * SpecificLongValue.
+ */
+ public LongValue remainder(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the remainder of the given SpecificLongValue and this
+ * LongValue.
+ */
+ public LongValue remainderOf(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>and</i> of this LongValue and the given
+ * SpecificLongValue.
+ */
+ public LongValue and(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>or</i> of this LongValue and the given
+ * SpecificLongValue.
+ */
+ public LongValue or(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns the logical <i>xor</i> of this LongValue and the given
+ * SpecificLongValue.
+ */
+ public LongValue xor(SpecificLongValue other)
+ {
+ return this;
+ }
+
+ /**
+ * Returns an IntegerValue with value -1, 0, or 1, if this LongValue is
+ * less than, equal to, or greater than the given SpecificLongValue,
+ * respectively.
+ */
+ public IntegerValue compare(SpecificLongValue other)
+ {
+ return IntegerValueFactory.create();
+ }
+
+
+ // Derived binary methods.
+
+ /**
+ * Returns an IntegerValue with value 1, 0, or -1, if this LongValue is
+ * less than, equal to, or greater than the given SpecificLongValue,
+ * respectively.
+ */
+ public final IntegerValue compareReverse(SpecificLongValue other)
+ {
+ return compare(other).negate();
+ }
+
+
+ // Implementations for Value.
+
+ public final LongValue longValue()
+ {
+ return this;
+ }
+
+ public final Value generalize(Value other)
+ {
+ return this.generalize(other.longValue());
+ }
+
+ public final int computationalType()
+ {
+ return TYPE_LONG;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass();
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode();
+ }
+
+
+ public String toString()
+ {
+ return "l";
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/LongValueFactory.java b/src/proguard/optimize/evaluation/value/LongValueFactory.java
new file mode 100644
index 0000000..38475da
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/LongValueFactory.java
@@ -0,0 +1,53 @@
+/* $Id: LongValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This class provides methods to create and reuse LongValue objects.
+ *
+ * @author Eric Lafortune
+ */
+public class LongValueFactory
+{
+ // Shared copies of LongValue objects, to avoid creating a lot of objects.
+ private static LongValue LONG_VALUE = new LongValue();
+ private static SpecificLongValue LONG_VALUE_0 = new SpecificLongValue(0);
+ private static SpecificLongValue LONG_VALUE_1 = new SpecificLongValue(1);
+
+
+ /**
+ * Creates a new LongValue with an undefined value.
+ */
+ public static LongValue create()
+ {
+ return LONG_VALUE;
+ }
+
+ /**
+ * Creates a new LongValue with a given specific value.
+ */
+ public static SpecificLongValue create(long value)
+ {
+ return value == 0 ? LONG_VALUE_0 :
+ value == 1 ? LONG_VALUE_1 :
+ new SpecificLongValue(value);
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/ReferenceValue.java b/src/proguard/optimize/evaluation/value/ReferenceValue.java
new file mode 100644
index 0000000..2d15729
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/ReferenceValue.java
@@ -0,0 +1,190 @@
+/* $Id: ReferenceValue.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+import proguard.classfile.*;
+import proguard.classfile.ClassCpInfo;
+
+/**
+ * This class represents a partially evaluated reference value.
+ *
+ * @author Eric Lafortune
+ */
+public class ReferenceValue extends Category1Value
+{
+ protected boolean mayBeNull;
+
+
+ /**
+ * Creates a new reference value that may or may not be null.
+ */
+ public ReferenceValue(boolean mayBeNull)
+ {
+ this.mayBeNull = mayBeNull;
+ }
+
+
+ /**
+ * Returns the specific reference value, if applicable.
+ */
+ public ClassFile value()
+ {
+ return null;
+ }
+
+
+ /**
+ * Returns the array dimension, if applicable.
+ */
+ public int dimension()
+ {
+ return 0;
+ }
+
+
+ // Basic binary methods.
+
+ /**
+ * Returns the generalization of this ReferenceValue and the given other
+ * ReferenceValue.
+ */
+ public ReferenceValue generalize(ReferenceValue other)
+ {
+ return ReferenceValueFactory.create(this.mayBeNull || other.mayBeNull);
+ }
+
+
+ /**
+ * Returns whether this ReferenceValue and the given ReferenceValue are equal:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public int equal(ReferenceValue other)
+ {
+ return MAYBE;
+ }
+
+
+ // Basic unary methods.
+
+ /**
+ * Returns whether this ReferenceValue is <code>null</code>:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public int isNull()
+ {
+ return mayBeNull ? MAYBE : NEVER;
+ }
+
+
+ /**
+ * Returns whether this ReferenceValue is an instance of the given class
+ * with the given dimensionality:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public int instanceOf(ClassFile typeClassFile, int typeDimension)
+ {
+ return MAYBE;
+ }
+
+
+ // Derived binary methods.
+
+ /**
+ * Returns whether this ReferenceValue and the given ReferenceValue are different:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public final int notEqual(ReferenceValue other)
+ {
+ return -equal(other);
+ }
+
+
+ /**
+ * Returns whether this ReferenceValue is not <code>null</code>:
+ * <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public final int isNotNull()
+ {
+ return -isNull();
+ }
+
+
+ // Similar binary methods, but this time with more specific arguments.
+
+ /**
+ * Returns the generalization of this ReferenceValue and the given other
+ * SpecificReferenceValue.
+ */
+ public ReferenceValue generalize(SpecificReferenceValue other)
+ {
+ return ReferenceValueFactory.create(this.mayBeNull || other.mayBeNull);
+ }
+
+
+ /**
+ * Returns whether this ReferenceValue and the given SpecificReferenceValue are
+ * equal: <code>NEVER</code>, <code>MAYBE</code>, or <code>ALWAYS</code>.
+ */
+ public int equal(SpecificReferenceValue other)
+ {
+ return MAYBE;
+ }
+
+
+ // Implementations for Value.
+
+ public final ReferenceValue referenceValue()
+ {
+ return this;
+ }
+
+ public final Value generalize(Value other)
+ {
+ return this.generalize(other.referenceValue());
+ }
+
+ public final int computationalType()
+ {
+ return TYPE_REFERENCE;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass() &&
+ this.mayBeNull == ((ReferenceValue)object).mayBeNull;
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode() ^ (mayBeNull ? 0 : 1);
+ }
+
+
+ public String toString()
+ {
+ return mayBeNull ? "a" : "a:!null";
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/ReferenceValueFactory.java b/src/proguard/optimize/evaluation/value/ReferenceValueFactory.java
new file mode 100644
index 0000000..30d8da7
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/ReferenceValueFactory.java
@@ -0,0 +1,80 @@
+/* $Id: ReferenceValueFactory.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+import proguard.classfile.*;
+import proguard.classfile.ClassCpInfo;
+
+/**
+ * This class provides methods to create and reuse ReferenceValue objects.
+ *
+ * @author Eric Lafortune
+ */
+public class ReferenceValueFactory
+{
+ // Shared copies of ReferenceValue objects, to avoid creating a lot of objects.
+ private static ReferenceValue REFERENCE_VALUE_MAYBE_NULL = new ReferenceValue(true);
+ private static ReferenceValue REFERENCE_VALUE_NOT_NULL = new ReferenceValue(false);
+
+
+ /**
+ * Creates a new ReferenceValue with an undefined value.
+ */
+ public static ReferenceValue create(boolean mayBeNull)
+ {
+ return mayBeNull ? REFERENCE_VALUE_MAYBE_NULL :
+ REFERENCE_VALUE_NOT_NULL;
+ }
+
+
+ /**
+ * Creates a new ReferenceValue that represents <code>null</code>.
+ */
+ public static ReferenceValue createNull()
+ {
+ return new SpecificReferenceValue(null, true);
+ }
+
+
+ /**
+ * Creates a new ReferenceValue of a specific type. If the value is
+ * <code>null</code>, a ReferenceValue of an undefined type is returned.
+ */
+ public static ReferenceValue create(ClassFile value, boolean mayBeNull)
+ {
+ return value == null ? ReferenceValueFactory.create(mayBeNull) :
+ new SpecificReferenceValue(value, mayBeNull);
+ }
+
+
+ /**
+ * Creates a new array ReferenceValue of a specific type and dimensionality.
+ * If the value is <code>null</code>, a ReferenceValue of an undefined
+ * type is returned. If the dimension is 0, a ReferenceValue of the given
+ * type is returned.
+ */
+ public static ReferenceValue create(ClassFile value, int dimension, boolean mayBeNull)
+ {
+ return value == null ? ReferenceValueFactory.create(mayBeNull) :
+ dimension == 0 ? ReferenceValueFactory.create(value, mayBeNull) :
+ new SpecificArrayReferenceValue(value, dimension, mayBeNull);
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/SpecificArrayReferenceValue.java b/src/proguard/optimize/evaluation/value/SpecificArrayReferenceValue.java
new file mode 100644
index 0000000..0a4ec34
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/SpecificArrayReferenceValue.java
@@ -0,0 +1,160 @@
+/* $Id: SpecificArrayReferenceValue.java,v 1.4 2004/08/21 21:37:28 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+import proguard.classfile.*;
+import proguard.classfile.ClassCpInfo;
+import proguard.classfile.util.ClassUtil;
+
+/**
+ * This ReferenceValue represents an array reference value of a specific type
+ * and dimensionality.
+ *
+ * @author Eric Lafortune
+ */
+class SpecificArrayReferenceValue extends SpecificReferenceValue
+{
+ protected int dimension;
+
+
+ /**
+ * Creates a new specific array reference value. The dimensionality of the
+ * value argument alone is ignored.
+ */
+ public SpecificArrayReferenceValue(ClassFile value, int dimension, boolean mayBeNull)
+ {
+ super(value, mayBeNull);
+
+ this.dimension = dimension;
+ }
+
+
+ // Implementations for ReferenceValue.
+
+ public int dimension()
+ {
+ return dimension;
+ }
+
+
+ // Implementations of binary methods of ReferenceValue.
+
+ // Perhaps the other value arguments are more specific than apparent
+ // in these methods, so delegate to them.
+
+ public ReferenceValue generalize(ReferenceValue other)
+ {
+ return other.generalize(this);
+ }
+
+ public int equal(ReferenceValue other)
+ {
+ return other.equal(this);
+ }
+
+
+ // Implementations of unary methods of ReferenceValue.
+
+ public int instanceOf(ClassFile typeClassFile, int typeDimension)
+ {
+ // If this value is null, it is never an instance of any class.
+ if (value == null)
+ {
+ return NEVER;
+ }
+
+ // If the type class is unknown or the type has a higher dimension, we
+ // can't tell for sure.
+ if (typeClassFile == null ||
+ typeDimension > dimension)
+ {
+ return MAYBE;
+ }
+
+ // If the type dimension is less than the value's dimension, the type
+ // must be Object, Cloneable, or Serializable.
+ if (typeDimension < dimension)
+ {
+ String typeClassName = typeClassFile.getName();
+ return typeClassName.equals(ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT) ||
+ typeClassName.equals(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLONEABLE) ||
+ typeClassName.equals(ClassConstants.INTERNAL_NAME_JAVA_IO_SERIALIZABLE) ?
+ ALWAYS :
+ NEVER;
+ }
+
+ // If the value extends the type, we're sure.
+ return value.extends_(typeClassFile) ||
+ value.implements_(typeClassFile) ?
+ ALWAYS :
+ MAYBE;
+ }
+
+
+ // Implementations of binary ReferenceValue methods with
+ // SpecificArrayReferenceValue arguments.
+
+ public ReferenceValue generalize(SpecificArrayReferenceValue other)
+ {
+ return this.value == other.value &&
+ this.dimension == other.dimension ?
+ this.mayBeNull ? this : other :
+ ReferenceValueFactory.create(this.mayBeNull || other.mayBeNull);
+ }
+
+ public int equal(SpecificArrayReferenceValue other)
+ {
+ return this.value == null &&
+ other.value == null ? ALWAYS : MAYBE;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (object == null ||
+ this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ SpecificArrayReferenceValue other = (SpecificArrayReferenceValue)object;
+ return this.mayBeNull == other.mayBeNull &&
+ (this.value == null ? other.value == null :
+ this.value.equals(other.value)) &&
+ this.dimension == other.dimension;
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode() ^
+ (value == null ? 0 : value.hashCode()) ^
+ dimension;
+ }
+
+
+ public String toString()
+ {
+ return "a:" + (value == null ? "null" : value.getName()+"["+dimension+"]");
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/SpecificDoubleValue.java b/src/proguard/optimize/evaluation/value/SpecificDoubleValue.java
new file mode 100644
index 0000000..f957ca6
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/SpecificDoubleValue.java
@@ -0,0 +1,213 @@
+/* $Id: SpecificDoubleValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License adouble
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This DoubleValue represents a specific double value.
+ *
+ * @author Eric Lafortune
+ */
+class SpecificDoubleValue extends DoubleValue
+{
+ private double value;
+
+
+ /**
+ * Creates a new specific double value.
+ */
+ public SpecificDoubleValue(double value)
+ {
+ this.value = value;
+ }
+
+
+ // Implementations for DoubleValue.
+
+ public double value()
+ {
+ return value;
+ }
+
+
+ // Implementations of binary methods of DoubleValue.
+
+ // Perhaps the other value arguments are more specific than apparent
+ // in these methods, so delegate to them.
+
+ public DoubleValue generalize(DoubleValue other)
+ {
+ return other.generalize(this);
+ }
+
+ public DoubleValue add(DoubleValue other)
+ {
+ return other.add(this);
+ }
+
+ public DoubleValue subtract(DoubleValue other)
+ {
+ return other.subtractFrom(this);
+ }
+
+ public DoubleValue subtractFrom(DoubleValue other)
+ {
+ return other.subtract(this);
+ }
+
+ public DoubleValue multiply(DoubleValue other)
+ {
+ return other.multiply(this);
+ }
+
+ public DoubleValue divide(DoubleValue other)
+ {
+ return other.divideOf(this);
+ }
+
+ public DoubleValue divideOf(DoubleValue other)
+ {
+ return other.divide(this);
+ }
+
+ public DoubleValue remainder(DoubleValue other)
+ {
+ return other.remainderOf(this);
+ }
+
+ public DoubleValue remainderOf(DoubleValue other)
+ {
+ return other.remainder(this);
+ }
+
+ public IntegerValue compare(DoubleValue other)
+ {
+ return other.compareReverse(this);
+ }
+
+
+ // Implementations of unary methods of DoubleValue.
+
+ public DoubleValue negate()
+ {
+ return DoubleValueFactory.create(-value);
+ }
+
+ public IntegerValue convertToInteger()
+ {
+ return IntegerValueFactory.create((int)value);
+ }
+
+ public LongValue convertToLong()
+ {
+ return LongValueFactory.create((long)value);
+ }
+
+ public FloatValue convertToFloat()
+ {
+ return FloatValueFactory.create((float)value);
+ }
+
+
+ // Implementations of binary DoubleValue methods with SpecificDoubleValue
+ // arguments.
+
+ public DoubleValue generalize(SpecificDoubleValue other)
+ {
+ return this.value == other.value ? this : DoubleValueFactory.create();
+ }
+
+ public DoubleValue add(SpecificDoubleValue other)
+ {
+ return DoubleValueFactory.create(this.value + other.value);
+ }
+
+ public DoubleValue subtract(SpecificDoubleValue other)
+ {
+ return DoubleValueFactory.create(this.value - other.value);
+ }
+
+ public DoubleValue subtractFrom(SpecificDoubleValue other)
+ {
+ return DoubleValueFactory.create(other.value - this.value);
+ }
+
+ public DoubleValue multiply(SpecificDoubleValue other)
+ {
+ return DoubleValueFactory.create(this.value * other.value);
+ }
+
+ public DoubleValue divide(SpecificDoubleValue other)
+ {
+ return DoubleValueFactory.create(this.value / other.value);
+ }
+
+ public DoubleValue divideOf(SpecificDoubleValue other)
+ {
+ return DoubleValueFactory.create(other.value / this.value);
+ }
+
+ public DoubleValue remainder(SpecificDoubleValue other)
+ {
+ return DoubleValueFactory.create(this.value % other.value);
+ }
+
+ public DoubleValue remainderOf(SpecificDoubleValue other)
+ {
+ return DoubleValueFactory.create(other.value % this.value);
+ }
+
+ public IntegerValue compare(SpecificDoubleValue other)
+ {
+ return this.value < other.value ? IntegerValueFactory.create(-1) :
+ this.value == other.value ? IntegerValueFactory.create(0) :
+ IntegerValueFactory.create(1);
+ }
+
+
+ // Implementations for Value.
+
+ public boolean isSpecific()
+ {
+ return true;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass() &&
+ this.value == ((SpecificDoubleValue)object).value;
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode() ^ (int)Double.doubleToLongBits(value);
+ }
+
+
+ public String toString()
+ {
+ return "d:"+value;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/SpecificFloatValue.java b/src/proguard/optimize/evaluation/value/SpecificFloatValue.java
new file mode 100644
index 0000000..b8332a4
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/SpecificFloatValue.java
@@ -0,0 +1,213 @@
+/* $Id: SpecificFloatValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License afloat
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This FloatValue represents a specific float value.
+ *
+ * @author Eric Lafortune
+ */
+class SpecificFloatValue extends FloatValue
+{
+ private float value;
+
+
+ /**
+ * Creates a new specific float value.
+ */
+ public SpecificFloatValue(float value)
+ {
+ this.value = value;
+ }
+
+
+ // Implementations for FloatValue.
+
+ public float value()
+ {
+ return value;
+ }
+
+
+ // Implementations of binary methods of FloatValue.
+
+ // Perhaps the other value arguments are more specific than apparent
+ // in these methods, so delegate to them.
+
+ public FloatValue generalize(FloatValue other)
+ {
+ return other.generalize(this);
+ }
+
+ public FloatValue add(FloatValue other)
+ {
+ return other.add(this);
+ }
+
+ public FloatValue subtract(FloatValue other)
+ {
+ return other.subtractFrom(this);
+ }
+
+ public FloatValue subtractFrom(FloatValue other)
+ {
+ return other.subtract(this);
+ }
+
+ public FloatValue multiply(FloatValue other)
+ {
+ return other.multiply(this);
+ }
+
+ public FloatValue divide(FloatValue other)
+ {
+ return other.divideOf(this);
+ }
+
+ public FloatValue divideOf(FloatValue other)
+ {
+ return other.divide(this);
+ }
+
+ public FloatValue remainder(FloatValue other)
+ {
+ return other.remainderOf(this);
+ }
+
+ public FloatValue remainderOf(FloatValue other)
+ {
+ return other.remainder(this);
+ }
+
+ public IntegerValue compare(FloatValue other)
+ {
+ return other.compareReverse(this);
+ }
+
+
+ // Implementations of unary methods of FloatValue.
+
+ public FloatValue negate()
+ {
+ return FloatValueFactory.create(-value);
+ }
+
+ public IntegerValue convertToInteger()
+ {
+ return IntegerValueFactory.create((int)value);
+ }
+
+ public LongValue convertToLong()
+ {
+ return LongValueFactory.create((long)value);
+ }
+
+ public DoubleValue convertToDouble()
+ {
+ return DoubleValueFactory.create((double)value);
+ }
+
+
+ // Implementations of binary FloatValue methods with SpecificFloatValue
+ // arguments.
+
+ public FloatValue generalize(SpecificFloatValue other)
+ {
+ return this.value == other.value ? this : FloatValueFactory.create();
+ }
+
+ public FloatValue add(SpecificFloatValue other)
+ {
+ return FloatValueFactory.create(this.value + other.value);
+ }
+
+ public FloatValue subtract(SpecificFloatValue other)
+ {
+ return FloatValueFactory.create(this.value - other.value);
+ }
+
+ public FloatValue subtractFrom(SpecificFloatValue other)
+ {
+ return FloatValueFactory.create(other.value - this.value);
+ }
+
+ public FloatValue multiply(SpecificFloatValue other)
+ {
+ return FloatValueFactory.create(this.value * other.value);
+ }
+
+ public FloatValue divide(SpecificFloatValue other)
+ {
+ return FloatValueFactory.create(this.value / other.value);
+ }
+
+ public FloatValue divideOf(SpecificFloatValue other)
+ {
+ return FloatValueFactory.create(other.value / this.value);
+ }
+
+ public FloatValue remainder(SpecificFloatValue other)
+ {
+ return FloatValueFactory.create(this.value % other.value);
+ }
+
+ public FloatValue remainderOf(SpecificFloatValue other)
+ {
+ return FloatValueFactory.create(other.value % this.value);
+ }
+
+ public IntegerValue compare(SpecificFloatValue other)
+ {
+ return this.value < other.value ? IntegerValueFactory.create(-1) :
+ this.value == other.value ? IntegerValueFactory.create(0) :
+ IntegerValueFactory.create(1);
+ }
+
+
+ // Implementations for Value.
+
+ public boolean isSpecific()
+ {
+ return true;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass() &&
+ this.value == ((SpecificFloatValue)object).value;
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode() ^ Float.floatToIntBits(value);
+ }
+
+
+ public String toString()
+ {
+ return "f:"+value;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/SpecificIntegerValue.java b/src/proguard/optimize/evaluation/value/SpecificIntegerValue.java
new file mode 100644
index 0000000..0f21bdf
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/SpecificIntegerValue.java
@@ -0,0 +1,388 @@
+/* $Id: SpecificIntegerValue.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This IntegerValue represents a specific integer value.
+ *
+ * @author Eric Lafortune
+ */
+class SpecificIntegerValue extends IntegerValue
+{
+ private int value;
+
+
+ public SpecificIntegerValue(int value)
+ {
+ this.value = value;
+ }
+
+
+ // Implementations for IntegerValue.
+
+ public int value()
+ {
+ return value;
+ }
+
+
+ // Implementations of binary methods of IntegerValue.
+
+ // Perhaps the other value arguments are more specific than apparent
+ // in these methods, so delegate to them.
+
+ public IntegerValue generalize(IntegerValue other)
+ {
+ return other.generalize(this);
+ }
+
+ public IntegerValue add(IntegerValue other)
+ {
+ return other.add(this);
+ }
+
+ public IntegerValue subtract(IntegerValue other)
+ {
+ return other.subtractFrom(this);
+ }
+
+ public IntegerValue subtractFrom(IntegerValue other)
+ {
+ return other.subtract(this);
+ }
+
+ public IntegerValue multiply(IntegerValue other)
+ {
+ return other.multiply(this);
+ }
+
+ public IntegerValue divide(IntegerValue other)
+ throws ArithmeticException
+ {
+ return other.divideOf(this);
+ }
+
+ public IntegerValue divideOf(IntegerValue other)
+ throws ArithmeticException
+ {
+ return other.divide(this);
+ }
+
+ public IntegerValue remainder(IntegerValue other)
+ throws ArithmeticException
+ {
+ return other.remainderOf(this);
+ }
+
+ public IntegerValue remainderOf(IntegerValue other)
+ throws ArithmeticException
+ {
+ return other.remainder(this);
+ }
+
+ public IntegerValue shiftLeft(IntegerValue other)
+ {
+ return other.shiftLeftOf(this);
+ }
+
+ public IntegerValue shiftLeftOf(IntegerValue other)
+ {
+ return other.shiftLeft(this);
+ }
+
+ public IntegerValue shiftRight(IntegerValue other)
+ {
+ return other.shiftRightOf(this);
+ }
+
+ public IntegerValue shiftRightOf(IntegerValue other)
+ {
+ return other.shiftRight(this);
+ }
+
+ public IntegerValue unsignedShiftRight(IntegerValue other)
+ {
+ return other.unsignedShiftRightOf(this);
+ }
+
+ public IntegerValue unsignedShiftRightOf(IntegerValue other)
+ {
+ return other.unsignedShiftRight(this);
+ }
+
+ public LongValue shiftLeftOf(LongValue other)
+ {
+ return other.shiftLeft(this);
+ }
+
+ public LongValue shiftRightOf(LongValue other)
+ {
+ return other.shiftRight(this);
+ }
+
+ public LongValue unsignedShiftRightOf(LongValue other)
+ {
+ return other.unsignedShiftRight(this);
+ }
+
+ public IntegerValue and(IntegerValue other)
+ {
+ return other.and(this);
+ }
+
+ public IntegerValue or(IntegerValue other)
+ {
+ return other.or(this);
+ }
+
+ public IntegerValue xor(IntegerValue other)
+ {
+ return other.xor(this);
+ }
+
+ public int equal(IntegerValue other)
+ {
+ return other.equal(this);
+ }
+
+ public int lessThan(IntegerValue other)
+ {
+ return other.greaterThanOrEqual(this);
+ }
+
+ public int lessThanOrEqual(IntegerValue other)
+ {
+ return other.greaterThan(this);
+ }
+
+
+ // Implementations of unary methods of IntegerValue.
+
+ public IntegerValue negate()
+ {
+ return IntegerValueFactory.create(-value);
+ }
+
+ public IntegerValue convertToByte()
+ {
+ int byteValue = (byte)value;
+
+ return byteValue == value ?
+ this :
+ IntegerValueFactory.create(byteValue);
+ }
+
+ public IntegerValue convertToCharacter()
+ {
+ int charValue = (char)value;
+
+ return charValue == value ?
+ this :
+ IntegerValueFactory.create(charValue);
+ }
+
+ public IntegerValue convertToShort()
+ {
+ int shortValue = (short)value;
+
+ return shortValue == value ?
+ this :
+ IntegerValueFactory.create(shortValue);
+ }
+
+ public IntegerValue convertToInteger()
+ {
+ return this;
+ }
+
+ public LongValue convertToLong()
+ {
+ return LongValueFactory.create((long)value);
+ }
+
+ public FloatValue convertToFloat()
+ {
+ return FloatValueFactory.create((float)value);
+ }
+
+ public DoubleValue convertToDouble()
+ {
+ return DoubleValueFactory.create((double)value);
+ }
+
+
+ // Implementations of binary IntegerValue methods with SpecificIntegerValue
+ // arguments.
+
+ public IntegerValue generalize(SpecificIntegerValue other)
+ {
+ return this.value == other.value ? this : IntegerValueFactory.create();
+ }
+
+ public IntegerValue add(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(this.value + other.value);
+ }
+
+ public IntegerValue subtract(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(this.value - other.value);
+ }
+
+ public IntegerValue subtractFrom(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(other.value - this.value);
+ }
+
+ public IntegerValue multiply(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(this.value * other.value);
+ }
+
+ public IntegerValue divide(SpecificIntegerValue other)
+ throws ArithmeticException
+ {
+ return IntegerValueFactory.create(this.value / other.value);
+ }
+
+ public IntegerValue divideOf(SpecificIntegerValue other)
+ throws ArithmeticException
+ {
+ return IntegerValueFactory.create(other.value / this.value);
+ }
+
+ public IntegerValue remainder(SpecificIntegerValue other)
+ throws ArithmeticException
+ {
+ return IntegerValueFactory.create(this.value % other.value);
+ }
+
+ public IntegerValue remainderOf(SpecificIntegerValue other)
+ throws ArithmeticException
+ {
+ return IntegerValueFactory.create(other.value % this.value);
+ }
+
+ public IntegerValue shiftLeft(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(this.value << other.value);
+ }
+
+ public IntegerValue shiftLeftOf(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(other.value << this.value);
+ }
+
+ public IntegerValue shiftRight(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(this.value >> other.value);
+ }
+
+ public IntegerValue shiftRightOf(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(other.value >> this.value);
+ }
+
+ public IntegerValue unsignedShiftRight(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(this.value >>> other.value);
+ }
+
+ public IntegerValue unsignedShiftRightOf(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(other.value >>> this.value);
+ }
+
+ public LongValue shiftLeftOf(SpecificLongValue other)
+ {
+ return LongValueFactory.create(other.value() << this.value);
+ }
+
+ public LongValue shiftRightOf(SpecificLongValue other)
+ {
+ return LongValueFactory.create(other.value() >> this.value);
+ }
+
+ public LongValue unsignedShiftRightOf(SpecificLongValue other)
+ {
+ return LongValueFactory.create(other.value() >>> this.value);
+ }
+
+ public IntegerValue and(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(this.value & other.value);
+ }
+
+ public IntegerValue or(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(this.value | other.value);
+ }
+
+ public IntegerValue xor(SpecificIntegerValue other)
+ {
+ return IntegerValueFactory.create(this.value ^ other.value);
+ }
+
+ public int equal(SpecificIntegerValue other)
+ {
+ return this.value == other.value ? ALWAYS : NEVER;
+ }
+
+ public int lessThan(SpecificIntegerValue other)
+ {
+ return this.value < other.value ? ALWAYS : NEVER;
+ }
+
+ public int lessThanOrEqual(SpecificIntegerValue other)
+ {
+ return this.value <= other.value ? ALWAYS : NEVER;
+ }
+
+
+ // Implementations for Value.
+
+ public boolean isSpecific()
+ {
+ return true;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass() &&
+ this.value == ((SpecificIntegerValue)object).value;
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode() ^ value;
+ }
+
+
+ public String toString()
+ {
+ return "i:"+value;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/SpecificLongValue.java b/src/proguard/optimize/evaluation/value/SpecificLongValue.java
new file mode 100644
index 0000000..05cc591
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/SpecificLongValue.java
@@ -0,0 +1,258 @@
+/* $Id: SpecificLongValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This LongValue represents a specific long value.
+ *
+ * @author Eric Lafortune
+ */
+class SpecificLongValue extends LongValue
+{
+ private long value;
+
+
+ /**
+ * Creates a new specific long value.
+ */
+ public SpecificLongValue(long value)
+ {
+ this.value = value;
+ }
+
+
+ // Implementations for LongValue.
+
+ public long value()
+ {
+ return value;
+ }
+
+
+ // Implementations of binary methods of LongValue.
+
+ // Perhaps the other value arguments are more specific than apparent
+ // in these methods, so delegate to them.
+
+ public LongValue generalize(LongValue other)
+ {
+ return other.generalize(this);
+ }
+
+ public LongValue add(LongValue other)
+ {
+ return other.add(this);
+ }
+
+ public LongValue subtract(LongValue other)
+ {
+ return other.subtractFrom(this);
+ }
+
+ public LongValue subtractFrom(LongValue other)
+ {
+ return other.subtract(this);
+ }
+
+ public LongValue multiply(LongValue other)
+ {
+ return other.multiply(this);
+ }
+
+ public LongValue divide(LongValue other)
+ {
+ return other.divideOf(this);
+ }
+
+ public LongValue divideOf(LongValue other)
+ {
+ return other.divide(this);
+ }
+
+ public LongValue remainder(LongValue other)
+ {
+ return other.remainderOf(this);
+ }
+
+ public LongValue remainderOf(LongValue other)
+ {
+ return other.remainder(this);
+ }
+
+ public LongValue shiftLeft(IntegerValue other)
+ {
+ return other.shiftLeftOf(this);
+ }
+
+ public LongValue shiftRight(IntegerValue other)
+ {
+ return other.shiftRightOf(this);
+ }
+
+ public LongValue unsignedShiftRight(IntegerValue other)
+ {
+ return other.unsignedShiftRightOf(this);
+ }
+
+ public LongValue and(LongValue other)
+ {
+ return other.and(this);
+ }
+
+ public LongValue or(LongValue other)
+ {
+ return other.or(this);
+ }
+
+ public LongValue xor(LongValue other)
+ {
+ return other.xor(this);
+ }
+
+ public IntegerValue compare(LongValue other)
+ {
+ return other.compareReverse(this);
+ }
+
+
+ // Implementations of unary methods of LongValue.
+
+ public LongValue negate()
+ {
+ return LongValueFactory.create(-value);
+ }
+
+ public IntegerValue convertToInteger()
+ {
+ return IntegerValueFactory.create((int)value);
+ }
+
+ public FloatValue convertToFloat()
+ {
+ return FloatValueFactory.create((float)value);
+ }
+
+ public DoubleValue convertToDouble()
+ {
+ return DoubleValueFactory.create((double)value);
+ }
+
+
+ // Implementations of binary LongValue methods with SpecificLongValue
+ // arguments.
+
+ public LongValue generalize(SpecificLongValue other)
+ {
+ return this.value == other.value ? this : LongValueFactory.create();
+ }
+
+ public LongValue add(SpecificLongValue other)
+ {
+ return LongValueFactory.create(this.value + other.value);
+ }
+
+ public LongValue subtract(SpecificLongValue other)
+ {
+ return LongValueFactory.create(this.value - other.value);
+ }
+
+ public LongValue subtractFrom(SpecificLongValue other)
+ {
+ return LongValueFactory.create(other.value - this.value);
+ }
+
+ public LongValue multiply(SpecificLongValue other)
+ {
+ return LongValueFactory.create(this.value * other.value);
+ }
+
+ public LongValue divide(SpecificLongValue other)
+ {
+ return LongValueFactory.create(this.value / other.value);
+ }
+
+ public LongValue divideOf(SpecificLongValue other)
+ {
+ return LongValueFactory.create(other.value / this.value);
+ }
+
+ public LongValue remainder(SpecificLongValue other)
+ {
+ return LongValueFactory.create(this.value % other.value);
+ }
+
+ public LongValue remainderOf(SpecificLongValue other)
+ {
+ return LongValueFactory.create(other.value % this.value);
+ }
+
+ public LongValue and(SpecificLongValue other)
+ {
+ return LongValueFactory.create(this.value & other.value);
+ }
+
+ public LongValue or(SpecificLongValue other)
+ {
+ return LongValueFactory.create(this.value | other.value);
+ }
+
+ public LongValue xor(SpecificLongValue other)
+ {
+ return LongValueFactory.create(this.value ^ other.value);
+ }
+
+ public IntegerValue compare(SpecificLongValue other)
+ {
+ return this.value < other.value ? IntegerValueFactory.create(-1) :
+ this.value == other.value ? IntegerValueFactory.create(0) :
+ IntegerValueFactory.create(1);
+ }
+
+
+ // Implementations for Value.
+
+ public boolean isSpecific()
+ {
+ return true;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ return object != null &&
+ this.getClass() == object.getClass() &&
+ this.value == ((SpecificLongValue)object).value;
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode() ^ (int)value;
+ }
+
+
+ public String toString()
+ {
+ return "l:"+value;
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/SpecificReferenceValue.java b/src/proguard/optimize/evaluation/value/SpecificReferenceValue.java
new file mode 100644
index 0000000..e31c969
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/SpecificReferenceValue.java
@@ -0,0 +1,158 @@
+/* $Id: SpecificReferenceValue.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+import proguard.classfile.*;
+import proguard.classfile.ClassCpInfo;
+
+/**
+ * This ReferenceValue represents a reference value of a specific type.
+ *
+ * @author Eric Lafortune
+ */
+class SpecificReferenceValue extends ReferenceValue
+{
+ protected ClassFile value;
+
+
+ /**
+ * Creates a new specific reference value.
+ */
+ public SpecificReferenceValue(ClassFile value, boolean mayBeNull)
+ {
+ super(mayBeNull);
+
+ this.value = value;
+ }
+
+
+ // Implementations for ReferenceValue.
+
+ public ClassFile value()
+ {
+ return value;
+ }
+
+
+ // Implementations of binary methods of ReferenceValue.
+
+ // Perhaps the other value arguments are more specific than apparent
+ // in these methods, so delegate to them.
+
+ public ReferenceValue generalize(ReferenceValue other)
+ {
+ return other.generalize(this);
+ }
+
+ public int equal(ReferenceValue other)
+ {
+ return other.equal(this);
+ }
+
+
+ // Implementations of unary methods of ReferenceValue.
+
+ public int isNull()
+ {
+ return value == null ? ALWAYS :
+ mayBeNull ? MAYBE :
+ NEVER;
+ }
+
+
+ public int instanceOf(ClassFile typeClassFile, int typeDimension)
+ {
+ // If this value is null, it is never an instance of any class.
+ if (value == null)
+ {
+ return NEVER;
+ }
+
+ // If the type class is unknown or the type is an array type, we can't
+ // tell for sure.
+ if (typeClassFile == null ||
+ typeDimension > 0)
+ {
+ return MAYBE;
+ }
+
+ // If the value extends the type, we're sure.
+ return value.extends_(typeClassFile) ||
+ value.implements_(typeClassFile) ?
+ ALWAYS :
+ MAYBE;
+ }
+
+
+ // Implementations of binary ReferenceValue methods with SpecificReferenceValue
+ // arguments.
+
+ public ReferenceValue generalize(SpecificReferenceValue other)
+ {
+ return this.value == other.value ?
+ this.mayBeNull ? this : other :
+ ReferenceValueFactory.create(this.mayBeNull || other.mayBeNull);
+ }
+
+ public int equal(SpecificReferenceValue other)
+ {
+ return this.value == null &&
+ other.value == null ? ALWAYS : MAYBE;
+ }
+
+
+ // Implementations for Value.
+
+ public boolean isSpecific()
+ {
+ return true;
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (object == null ||
+ this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ SpecificReferenceValue other = (SpecificReferenceValue)object;
+ return this.mayBeNull == other.mayBeNull &&
+ (this.value == null ? other.value == null :
+ this.value.equals(other.value));
+ }
+
+
+ public int hashCode()
+ {
+ return this.getClass().hashCode() ^
+ (value == null ? 0 : value.hashCode());
+ }
+
+
+ public String toString()
+ {
+ return "a:" + (value == null ? "null" : value.getName());
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/Value.java b/src/proguard/optimize/evaluation/value/Value.java
new file mode 100644
index 0000000..12affa1
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/Value.java
@@ -0,0 +1,143 @@
+/* $Id: Value.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+/**
+ * This abstract class represents a partially evaluated value.
+ *
+ * @author Eric Lafortune
+ */
+public abstract class Value
+{
+ public static final int NEVER = -1;
+ public static final int MAYBE = 0;
+ public static final int ALWAYS = 1;
+
+ public static final int TYPE_INTEGER = 1;
+ public static final int TYPE_LONG = 2;
+ public static final int TYPE_FLOAT = 3;
+ public static final int TYPE_DOUBLE = 4;
+ public static final int TYPE_REFERENCE = 5;
+ public static final int TYPE_INSTRUCTION_OFFSET = 6;
+
+
+ /**
+ * Returns this Value as a Category1Value.
+ */
+ public Category1Value category1Value()
+ {
+ throw new IllegalArgumentException("Value is not a Category 1 value [" + this.getClass().getName() + "]");
+ }
+
+ /**
+ * Returns this Value as a Category2Value.
+ */
+ public Category2Value category2Value()
+ {
+ throw new IllegalArgumentException("Value is not a Category 2 value [" + this.getClass().getName() + "]");
+ }
+
+
+ /**
+ * Returns this Value as an IntegerValue.
+ */
+ public IntegerValue integerValue()
+ {
+ throw new IllegalArgumentException("Value is not an integer value [" + this.getClass().getName() + "]");
+ }
+
+ /**
+ * Returns this Value as a LongValue.
+ */
+ public LongValue longValue()
+ {
+ throw new IllegalArgumentException("Value is not a long value [" + this.getClass().getName() + "]");
+ }
+
+ /**
+ * Returns this Value as a FloatValue.
+ */
+ public FloatValue floatValue()
+ {
+ throw new IllegalArgumentException("Value is not a float value [" + this.getClass().getName() + "]");
+ }
+
+ /**
+ * Returns this Value as a DoubleValue.
+ */
+ public DoubleValue doubleValue()
+ {
+ throw new IllegalArgumentException("Value is not a double value [" + this.getClass().getName() + "]");
+ }
+
+ /**
+ * Returns this Value as a ReferenceValue.
+ */
+ public ReferenceValue referenceValue()
+ {
+ throw new IllegalArgumentException("Value is not a reference value [" + this.getClass().getName() + "]");
+ }
+
+ /**
+ * Returns this Value as a InstructionOffsetValue.
+ */
+ public InstructionOffsetValue instructionOffsetValue()
+ {
+ throw new IllegalArgumentException("Value is not an instruction offset value [" + this.getClass().getName() + "]");
+ }
+
+
+ /**
+ * Returns whether this Value represents a single specific value.
+ */
+ public boolean isSpecific()
+ {
+ return false;
+ }
+
+
+ /**
+ * Returns the generalization of this Value and the given other Value.
+ */
+ public abstract Value generalize(Value other);
+
+
+ /**
+ * Returns whether the computational type of this Value is a category 2 type.
+ * This means that it takes up the space of two category 1 types on the
+ * stack, for instance.
+ */
+ public abstract boolean isCategory2();
+
+
+ /**
+ * Returns the computational type of this Value. The type is one of
+ * <ul>
+ * <li><code>TYPE_INTEGER</code>
+ * <li><code>TYPE_LONG</code>
+ * <li><code>TYPE_FLOAT</code>
+ * <li><code>TYPE_DOUBLE</code>
+ * <li><code>TYPE_REFERENCE</code>
+ * <li><code>TYPE_INSTRUCTION_OFFSET</code>
+ * </ul>
+ */
+ public abstract int computationalType();
+}
diff --git a/src/proguard/optimize/evaluation/value/ValueFactory.java b/src/proguard/optimize/evaluation/value/ValueFactory.java
new file mode 100644
index 0000000..c4149e6
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/ValueFactory.java
@@ -0,0 +1,63 @@
+/* $Id: ValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.evaluation.value;
+
+import proguard.classfile.ClassConstants;
+
+/**
+ * This class provides methods to create and reuse Value objects.
+ *
+ * @author Eric Lafortune
+ */
+public class ValueFactory
+{
+ /**
+ * Creates a new Value with an undefined value, corresponding to the given
+ * internal type. The void type returns <code>null</code>.
+ */
+ public static Value create(String internalType)
+ {
+ switch (internalType.charAt(0))
+ {
+ case ClassConstants.INTERNAL_TYPE_VOID:
+ return null;
+
+ case ClassConstants.INTERNAL_TYPE_BOOLEAN:
+ case ClassConstants.INTERNAL_TYPE_BYTE:
+ case ClassConstants.INTERNAL_TYPE_CHAR:
+ case ClassConstants.INTERNAL_TYPE_SHORT:
+ case ClassConstants.INTERNAL_TYPE_INT:
+ return IntegerValueFactory.create();
+
+ case ClassConstants.INTERNAL_TYPE_FLOAT:
+ return FloatValueFactory.create();
+
+ case ClassConstants.INTERNAL_TYPE_LONG:
+ return LongValueFactory.create();
+
+ case ClassConstants.INTERNAL_TYPE_DOUBLE:
+ return DoubleValueFactory.create();
+
+ default:
+ return ReferenceValueFactory.create(true);
+ }
+ }
+}
diff --git a/src/proguard/optimize/evaluation/value/package.html b/src/proguard/optimize/evaluation/value/package.html
new file mode 100644
index 0000000..71e1b13
--- /dev/null
+++ b/src/proguard/optimize/evaluation/value/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains classes that represent partial evaluation values.
+</body>
diff --git a/src/proguard/optimize/package.html b/src/proguard/optimize/package.html
new file mode 100644
index 0000000..3ee1353
--- /dev/null
+++ b/src/proguard/optimize/package.html
@@ -0,0 +1,4 @@
+<body>
+This package contains visitors that assist with various optimizations of byte
+code.
+</body>
diff --git a/src/proguard/optimize/peephole/BranchTargetFinder.java b/src/proguard/optimize/peephole/BranchTargetFinder.java
new file mode 100644
index 0000000..15bb005
--- /dev/null
+++ b/src/proguard/optimize/peephole/BranchTargetFinder.java
@@ -0,0 +1,178 @@
+/* $Id: BranchTargetFinder.java,v 1.5 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This AttrInfoVisitor finds all branch targets in the CodeAttrInfo objects
+ * that it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class BranchTargetFinder
+implements AttrInfoVisitor,
+ InstructionVisitor,
+ ExceptionInfoVisitor
+{
+ private boolean[] isBranchTarget;
+
+
+ /**
+ * Creates a new BranchTargetFinder.
+ * @param codeLength an estimate of the maximum length of all the code that
+ * will be edited.
+ */
+ public BranchTargetFinder(int codeLength)
+ {
+ isBranchTarget = new boolean[codeLength + 1];
+ }
+
+
+ /**
+ * Returns whether the instruction at the given offset is the target of a
+ * branch instruction in the CodeAttrInfo that was visited most recently.
+ */
+ public boolean isBranchTarget(int offset)
+ {
+ return isBranchTarget[offset];
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ // Make sure there is a sufficiently large boolean array.
+ int length = codeAttrInfo.u4codeLength + 1;
+ if (isBranchTarget.length < length)
+ {
+ // Create a new boolean array.
+ isBranchTarget = new boolean[length];
+ }
+ else
+ {
+ // Reset the boolean array.
+ for (int index = 0; index < length; index++)
+ {
+ isBranchTarget[index] = false;
+ }
+ }
+
+ // The first instruction and the end of the code are always branch targets.
+ isBranchTarget[0] = true;
+ isBranchTarget[codeAttrInfo.u4codeLength] = true;
+
+ // Mark branch targets by going over all instructions.
+ codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
+
+ // Mark branch targets in the exception table.
+ codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+
+
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
+ {
+ // Mark the branch target.
+ isBranchTarget[offset + branchInstruction.branchOffset] = true;
+ }
+
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ // Mark the branch targets of the default jump offset.
+ isBranchTarget[offset + tableSwitchInstruction.defaultOffset] = true;
+
+ // Mark the branch targets of the jump offsets.
+ markBranchTargets(offset,
+ tableSwitchInstruction.jumpOffsets,
+ tableSwitchInstruction.highCase -
+ tableSwitchInstruction.lowCase + 1);
+ }
+
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ // Mark the branch targets of the default jump offset.
+ isBranchTarget[offset + lookUpSwitchInstruction.defaultOffset] = true;
+
+ // Mark the branch targets of the jump offsets.
+ markBranchTargets(offset,
+ lookUpSwitchInstruction.jumpOffsets,
+ lookUpSwitchInstruction.jumpOffsetCount);
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, ExceptionInfo exceptionInfo)
+ {
+ // Remap the code offsets. Note that the branch target array also has
+ // an entry for the first offset after the code, for u2endpc.
+ isBranchTarget[exceptionInfo.u2startpc] = true;
+ isBranchTarget[exceptionInfo.u2endpc] = true;
+ isBranchTarget[exceptionInfo.u2handlerpc] = true;
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the branch targets of the given jump offsets for the instruction
+ * at the given offset.
+ */
+ private void markBranchTargets(int offset, int[] jumpOffsets, int length)
+ {
+ for (int index = 0; index < length; index++)
+ {
+ isBranchTarget[offset + jumpOffsets[index]] = true;
+ }
+ }
+}
diff --git a/src/proguard/optimize/peephole/ClassFileFinalizer.java b/src/proguard/optimize/peephole/ClassFileFinalizer.java
new file mode 100644
index 0000000..88c1fb2
--- /dev/null
+++ b/src/proguard/optimize/peephole/ClassFileFinalizer.java
@@ -0,0 +1,96 @@
+/* $Id: ClassFileFinalizer.java,v 1.6 2004/12/19 21:03:13 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.util.MemberFinder;
+import proguard.classfile.visitor.*;
+import proguard.optimize.*;
+
+/**
+ * This <code>ClassFileVisitor</code> and <code>MemberInfoVisitor</code>
+ * makes the class files it visits, and their class members, final, if possible.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileFinalizer
+ implements ClassFileVisitor,
+ MemberInfoVisitor
+{
+ private MemberFinder memberFinder = new MemberFinder();
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // If the class is not final/interface/abstract,
+ // and it is not being kept,
+ // then make it final.
+ if ((programClassFile.u2accessFlags & (ClassConstants.INTERNAL_ACC_FINAL |
+ ClassConstants.INTERNAL_ACC_INTERFACE |
+ ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 &&
+ !KeepMarker.isKept(programClassFile) &&
+ programClassFile.subClasses == null)
+ {
+ programClassFile.u2accessFlags |= ClassConstants.INTERNAL_ACC_FINAL;
+ }
+
+ // Check all methods.
+ programClassFile.methodsAccept(this);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ String name = programMethodInfo.getName(programClassFile);
+
+ // If the method is not final/abstract/private.
+ // and it is not an initialization method,
+ // and its class is final,
+ // or it is not being kept and it is not overridden,
+ // then make it final.
+ if ((programMethodInfo.u2accessFlags & (ClassConstants.INTERNAL_ACC_FINAL |
+ ClassConstants.INTERNAL_ACC_ABSTRACT |
+ ClassConstants.INTERNAL_ACC_PRIVATE)) == 0 &&
+ !name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) &&
+ !name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) &&
+ ((programClassFile.u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0 ||
+ (!KeepMarker.isKept(programMethodInfo) &&
+ (programClassFile.subClasses == null ||
+ !memberFinder.isOverriden(programClassFile, programMethodInfo)))))
+ {
+ programMethodInfo.u2accessFlags |= ClassConstants.INTERNAL_ACC_FINAL;
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+}
diff --git a/src/proguard/optimize/peephole/GetterSetterInliner.java b/src/proguard/optimize/peephole/GetterSetterInliner.java
new file mode 100644
index 0000000..caef29c
--- /dev/null
+++ b/src/proguard/optimize/peephole/GetterSetterInliner.java
@@ -0,0 +1,387 @@
+/* $Id: GetterSetterInliner.java,v 1.14 2004/12/18 20:22:42 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.util.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This InstructionVisitor inlines simple getter and setter methods.
+ *
+ * @author Eric Lafortune
+ */
+public class GetterSetterInliner
+implements InstructionVisitor,
+ CpInfoVisitor
+{
+ private static final String SETTER_RETURN_TYPE = "V";
+
+ private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
+ private MyGetterSetterChecker getterSetterChecker = new MyGetterSetterChecker();
+ private MemberFinder memberFinder = new MemberFinder();
+
+ private CodeAttrInfoEditor codeAttrInfoEditor;
+ private boolean allowAccessModification;
+
+
+ // Return values of the getter/setter checker.
+ private byte getFieldPutFieldOpcode;
+ private int referencedClassIndex;
+ private int referencedFieldIndex;
+ private ClassFile referencedClassFile;
+ private MemberInfo referencedFieldInfo;
+ private ClassFile[] typeReferencedClassFiles;
+
+
+ /**
+ * Creates a new GetterSetterInliner.
+ * @param codeAttrInfoEditor a code editor that can be used for
+ * accumulating changes to the code.
+ * @param allowAccessModification indicates whether the access modifiers of
+ * a field can be changed in order to inline
+ * its getter or setter.
+ */
+ public GetterSetterInliner(CodeAttrInfoEditor codeAttrInfoEditor,
+ boolean allowAccessModification)
+ {
+ this.codeAttrInfoEditor = codeAttrInfoEditor;
+ this.allowAccessModification = allowAccessModification;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ byte opcode = cpInstruction.opcode;
+
+ // Is this instruction a non-static invoke instruction?
+ if (opcode == InstructionConstants.OP_INVOKEVIRTUAL ||
+ opcode == InstructionConstants.OP_INVOKESPECIAL)
+ {
+ // Check if it's a getter or setter that can be inlined.
+ getFieldPutFieldOpcode = 0;
+
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+
+ // Do we have a getfield or putfield instruction to inline?
+ if (getFieldPutFieldOpcode != 0)
+ {
+ // Reuse or create the field reference in this class.
+ int fieldrefCpInfoIndex = classFile.equals(referencedClassFile) ?
+ referencedFieldIndex :
+ constantPoolEditor.addFieldrefCpInfo((ProgramClassFile)classFile,
+ referencedClassIndex,
+ referencedFieldInfo.getName(referencedClassFile),
+ referencedFieldInfo.getDescriptor(referencedClassFile),
+ referencedClassFile,
+ referencedFieldInfo,
+ typeReferencedClassFiles);
+
+ // Inline the getfield or putfield instruction.
+ Instruction replacementInstruction = new CpInstruction(getFieldPutFieldOpcode,
+ fieldrefCpInfoIndex).shrink();
+
+ codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
+ }
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ String descriptor = methodrefCpInfo.getType(classFile);
+
+ // A getter or a setter can't have more than one parameter.
+ int parameterCount = ClassUtil.internalMethodParameterCount(descriptor);
+ if (parameterCount > 1)
+ {
+ return;
+ }
+
+ // A getter must return a value, a setter must return void.
+ String returnType = ClassUtil.internalMethodReturnType(descriptor);
+ if ((parameterCount > 0) ^ returnType.equals(SETTER_RETURN_TYPE))
+ {
+ return;
+ }
+
+ // The referenced method must be present and private or final.
+ MemberInfo referencedMethodInfo = methodrefCpInfo.referencedMemberInfo;
+ if (referencedMethodInfo == null ||
+ (referencedMethodInfo.getAccessFlags() &
+ (ClassConstants.INTERNAL_ACC_PRIVATE |
+ ClassConstants.INTERNAL_ACC_FINAL)) == 0)
+ {
+ return;
+ }
+
+ // Check if the method can be inlined.
+ referencedMethodInfo.accept(methodrefCpInfo.referencedClassFile,
+ getterSetterChecker);
+
+ // Do we have a getfield or putfield instruction to inline?
+ if (getFieldPutFieldOpcode == 0)
+ {
+ return;
+ }
+
+ // Remember the constant pool index of the referenced class.
+ referencedClassIndex = methodrefCpInfo.u2classIndex;
+
+ // Doesn't the field allow at least the same access as the getter or
+ // setter?
+ if (AccessUtil.accessLevel(referencedFieldInfo.getAccessFlags()) <
+ AccessUtil.accessLevel(referencedMethodInfo.getAccessFlags()))
+ {
+ // Are we allowed to fix the access?
+ if (allowAccessModification)
+ {
+ // Is the field access private, and is the field shadowed by
+ // a field in a subclass?
+ if (AccessUtil.accessLevel(referencedFieldInfo.getAccessFlags()) == AccessUtil.PRIVATE &&
+ memberFinder.isShadowed(referencedClassFile, (FieldInfo)referencedFieldInfo))
+ {
+ // Cancel the inlining.
+ getFieldPutFieldOpcode = 0;
+ }
+
+ if (getFieldPutFieldOpcode != 0)
+ {
+ // Fix the access.
+ ((ProgramFieldInfo)referencedFieldInfo).u2accessFlags =
+ AccessUtil.replaceAccessFlags(referencedFieldInfo.getAccessFlags(),
+ referencedMethodInfo.getAccessFlags());
+ }
+ }
+ else
+ {
+ // We can't give the field the access of the getter or setter.
+ // Forget about inlining it after all.
+ getFieldPutFieldOpcode = 0;
+ }
+ }
+ }
+
+
+ /**
+ * This MemberInfoVisitor checks whether the visited member is a simple
+ * getter or setter.
+ */
+ private class MyGetterSetterChecker
+ implements MemberInfoVisitor,
+ AttrInfoVisitor,
+ InstructionVisitor,
+ CpInfoVisitor
+ {
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ programMethodInfo.attributesAccept(programClassFile, this);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ byte[] code = codeAttrInfo.code;
+
+ int offset = 0;
+ Instruction instruction;
+
+ // TODO: Handle static getters and setters.
+
+ // Check the first instruction.
+ instruction = InstructionFactory.create(code, offset);
+ if (instruction.opcode != InstructionConstants.OP_ALOAD_0)
+ {
+ return;
+ }
+
+ offset += instruction.length(offset);
+
+ // Start remembering if this is a getter or a setter.
+ boolean getter = true;
+
+ // TODO: Handle array getters and setters.
+
+ // Check the second instruction.
+ instruction = InstructionFactory.create(code, offset);
+ byte opcode = instruction.opcode;
+ if (opcode == InstructionConstants.OP_ILOAD_1 ||
+ opcode == InstructionConstants.OP_LLOAD_1 ||
+ opcode == InstructionConstants.OP_FLOAD_1 ||
+ opcode == InstructionConstants.OP_DLOAD_1 ||
+ opcode == InstructionConstants.OP_ALOAD_1)
+ {
+ // This instruction is loading the argument. Skip it.
+ offset += instruction.length(offset);
+
+ instruction = InstructionFactory.create(code, offset);
+ opcode = instruction.opcode;
+
+ // So this is a setter.
+ getter = false;
+ }
+
+ // Check the next instruction.
+ if (getter ? opcode != InstructionConstants.OP_GETFIELD :
+ opcode != InstructionConstants.OP_PUTFIELD)
+ {
+ return;
+ }
+
+ // Retrieve the field class, name and type.
+ instruction.accept(classFile, methodInfo, codeAttrInfo, offset, this);
+
+ // Check the class.
+ // TODO: Handle fields that are in super classes.
+ if (!classFile.equals(referencedClassFile))
+ {
+ return;
+ }
+
+ offset += instruction.length(offset);
+
+ // Remember the instruction opcode.
+ getFieldPutFieldOpcode = opcode;
+
+ // Check the last instruction.
+ instruction = InstructionFactory.create(code, offset);
+ opcode = instruction.opcode;
+ if (getter ? opcode != InstructionConstants.OP_IRETURN &&
+ opcode != InstructionConstants.OP_LRETURN &&
+ opcode != InstructionConstants.OP_FRETURN &&
+ opcode != InstructionConstants.OP_DRETURN &&
+ opcode != InstructionConstants.OP_ARETURN :
+ opcode != InstructionConstants.OP_RETURN)
+ {
+ // This isn't a simple getter or setter.
+ // Forget about inlining it.
+ getFieldPutFieldOpcode = 0;
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ // Remember the index of the field reference.
+ referencedFieldIndex = cpInstruction.cpIndex;
+
+ // Retrieve the referenced field and its class file.
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ // Remember the class file and the field.
+ referencedClassFile = fieldrefCpInfo.referencedClassFile;
+ referencedFieldInfo = fieldrefCpInfo.referencedMemberInfo;
+
+ // Retrieve the referenced class files.
+ classFile.constantPoolEntryAccept(fieldrefCpInfo.u2nameAndTypeIndex, this);
+ }
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ // Remember the referenced class files of the field.
+ typeReferencedClassFiles = nameAndTypeCpInfo.referencedClassFiles;
+ }
+ }
+}
diff --git a/src/proguard/optimize/peephole/GotoReturnReplacer.java b/src/proguard/optimize/peephole/GotoReturnReplacer.java
new file mode 100644
index 0000000..c472e2d
--- /dev/null
+++ b/src/proguard/optimize/peephole/GotoReturnReplacer.java
@@ -0,0 +1,92 @@
+/* $Id: GotoReturnReplacer.java,v 1.6 2004/11/20 15:06:55 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+
+/**
+ * This InstructionVisitor replaces unconditional branches to return instructions
+ * by these same return instructions.
+ *
+ * @author Eric Lafortune
+ */
+public class GotoReturnReplacer implements InstructionVisitor
+{
+ private CodeAttrInfoEditor codeAttrInfoEditor;
+
+
+ /**
+ * Creates a new GotoReturnReplacer.
+ * @param codeAttrInfoEditor a code editor that can be used for
+ * accumulating changes to the code.
+ */
+ public GotoReturnReplacer(CodeAttrInfoEditor codeAttrInfoEditor)
+ {
+ this.codeAttrInfoEditor = codeAttrInfoEditor;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
+ {
+ // Check if the instruction is an unconditional goto instruction.
+ byte opcode = branchInstruction.opcode;
+ if (opcode == InstructionConstants.OP_GOTO ||
+ opcode == InstructionConstants.OP_GOTO_W)
+ {
+ // Check if the goto instruction points to a return instruction.
+ int targetOffset = offset + branchInstruction.branchOffset;
+
+ if (!codeAttrInfoEditor.isModified(offset) &&
+ !codeAttrInfoEditor.isModified(targetOffset))
+ {
+ Instruction targetInstruction = InstructionFactory.create(codeAttrInfo.code,
+ targetOffset);
+ switch (targetInstruction.opcode)
+ {
+ case InstructionConstants.OP_IRETURN:
+ case InstructionConstants.OP_LRETURN:
+ case InstructionConstants.OP_FRETURN:
+ case InstructionConstants.OP_DRETURN:
+ case InstructionConstants.OP_ARETURN:
+ case InstructionConstants.OP_RETURN:
+ // Replace the goto instruction by the return instruction.
+ Instruction returnInstruction =
+ new SimpleInstruction(targetInstruction.opcode);
+ codeAttrInfoEditor.replaceInstruction(offset,
+ returnInstruction);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/src/proguard/optimize/peephole/LoadStoreRemover.java b/src/proguard/optimize/peephole/LoadStoreRemover.java
new file mode 100644
index 0000000..a4619f4
--- /dev/null
+++ b/src/proguard/optimize/peephole/LoadStoreRemover.java
@@ -0,0 +1,99 @@
+/* $Id: LoadStoreRemover.java,v 1.6 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This InstructionVisitor deletes load/store instruction pairs.
+ *
+ * @author Eric Lafortune
+ */
+public class LoadStoreRemover implements InstructionVisitor
+{
+ private BranchTargetFinder branchTargetFinder;
+ private CodeAttrInfoEditor codeAttrInfoEditor;
+
+
+ /**
+ * Creates a new LoadStoreRemover.
+ * @param branchTargetFinder a branch target finder that has been
+ * initialized to indicate branch targets
+ * in the visited code.
+ * @param codeAttrInfoEditor a code editor that can be used for
+ * accumulating changes to the code.
+ */
+ public LoadStoreRemover(BranchTargetFinder branchTargetFinder,
+ CodeAttrInfoEditor codeAttrInfoEditor)
+ {
+ this.branchTargetFinder = branchTargetFinder;
+ this.codeAttrInfoEditor = codeAttrInfoEditor;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ // Is this instruction a load instruction?
+ if (variableInstruction.isLoad() &&
+ variableInstruction.opcode != InstructionConstants.OP_RET)
+ {
+ byte opcode = variableInstruction.opcode;
+ int variableIndex = variableInstruction.variableIndex;
+
+ int nextOffset = offset + variableInstruction.length(offset);
+
+ if (!codeAttrInfoEditor.isModified(offset) &&
+ !codeAttrInfoEditor.isModified(nextOffset) &&
+ !branchTargetFinder.isBranchTarget(nextOffset))
+ {
+ // Is the next instruction a corresponding store instruction?
+ Instruction nextInstruction = InstructionFactory.create(codeAttrInfo.code,
+ nextOffset);
+
+ if (nextInstruction instanceof VariableInstruction)
+ {
+ variableInstruction = (VariableInstruction)nextInstruction;
+ if (!variableInstruction.isLoad() &&
+ variableInstruction.opcode != InstructionConstants.OP_IINC &&
+ variableInstruction.variableIndex == variableIndex)
+ {
+ // Delete both instructions.
+ codeAttrInfoEditor.deleteInstruction(offset);
+ codeAttrInfoEditor.deleteInstruction(nextOffset);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/proguard/optimize/peephole/NopRemover.java b/src/proguard/optimize/peephole/NopRemover.java
new file mode 100644
index 0000000..c21bb0f
--- /dev/null
+++ b/src/proguard/optimize/peephole/NopRemover.java
@@ -0,0 +1,68 @@
+/* $Id: NopRemover.java,v 1.5 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This InstructionVisitor removes all nop instructions that it encounters.
+ *
+ * @author Eric Lafortune
+ */
+public class NopRemover implements InstructionVisitor
+{
+ private CodeAttrInfoEditor codeAttrInfoEditor;
+
+
+ /**
+ * Creates a new NopRemover.
+ * @param codeAttrInfoEditor a code editor that can be used for
+ * accumulating changes to the code.
+ */
+ public NopRemover(CodeAttrInfoEditor codeAttrInfoEditor)
+ {
+ this.codeAttrInfoEditor = codeAttrInfoEditor;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
+ {
+ // Check if the instruction is a nop instruction.
+ if (simpleInstruction.opcode == InstructionConstants.OP_NOP &&
+ !codeAttrInfoEditor.isModified(offset))
+ {
+ codeAttrInfoEditor.deleteInstruction(offset);
+ }
+ }
+}
diff --git a/src/proguard/optimize/peephole/PushPopRemover.java b/src/proguard/optimize/peephole/PushPopRemover.java
new file mode 100644
index 0000000..c342f68
--- /dev/null
+++ b/src/proguard/optimize/peephole/PushPopRemover.java
@@ -0,0 +1,139 @@
+/* $Id: PushPopRemover.java,v 1.8 2004/10/10 20:56:58 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+
+/**
+ * This InstructionVisitor deletes all push/pop instruction pairs. In this
+ * context, push instructions are instructions that push values onto the stack,
+ * like dup and load instructions.
+ *
+ * @author Eric Lafortune
+ */
+public class PushPopRemover implements InstructionVisitor
+{
+ private BranchTargetFinder branchTargetFinder;
+ private CodeAttrInfoEditor codeAttrInfoEditor;
+
+
+ /**
+ * Creates a new PushPopRemover.
+ * @param branchTargetFinder a branch target finder that has been
+ * initialized to indicate branch targets
+ * in the visited code.
+ * @param codeAttrInfoEditor a code editor that can be used for
+ * accumulating changes to the code.
+ */
+ public PushPopRemover(BranchTargetFinder branchTargetFinder,
+ CodeAttrInfoEditor codeAttrInfoEditor)
+ {
+ this.branchTargetFinder = branchTargetFinder;
+ this.codeAttrInfoEditor = codeAttrInfoEditor;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_ICONST_M1:
+ case InstructionConstants.OP_ICONST_0:
+ case InstructionConstants.OP_ICONST_1:
+ case InstructionConstants.OP_ICONST_2:
+ case InstructionConstants.OP_ICONST_3:
+ case InstructionConstants.OP_ICONST_4:
+ case InstructionConstants.OP_ICONST_5:
+ case InstructionConstants.OP_LCONST_0:
+ case InstructionConstants.OP_LCONST_1:
+ case InstructionConstants.OP_FCONST_0:
+ case InstructionConstants.OP_FCONST_1:
+ case InstructionConstants.OP_FCONST_2:
+ case InstructionConstants.OP_DCONST_0:
+ case InstructionConstants.OP_DCONST_1:
+
+ case InstructionConstants.OP_DUP:
+ case InstructionConstants.OP_DUP2:
+ case InstructionConstants.OP_BIPUSH:
+ case InstructionConstants.OP_SIPUSH:
+ case InstructionConstants.OP_LDC:
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_LDC2_W:
+ // All these simple instructions are pushing instructions.
+ deleteWithSubsequentPop(codeAttrInfo, offset, simpleInstruction);
+ break;
+ }
+ }
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ if (variableInstruction.isLoad() &&
+ variableInstruction.opcode != InstructionConstants.OP_RET)
+ {
+ // All load instructions are pushing instructions.
+ deleteWithSubsequentPop(codeAttrInfo, offset, variableInstruction);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Deletes the given instruction and its subsequent compatible pop instruction,
+ * if any, and if the latter is not a branch target.
+ */
+ private void deleteWithSubsequentPop(CodeAttrInfo codeAttrInfo,
+ int offset,
+ Instruction instruction)
+ {
+ boolean isCategory2 = instruction.isCategory2();
+
+ int nextOffset = offset + instruction.length(offset);
+
+ if (!codeAttrInfoEditor.isModified(offset) &&
+ !codeAttrInfoEditor.isModified(nextOffset) &&
+ !branchTargetFinder.isBranchTarget(nextOffset))
+ {
+ Instruction nextInstruction = InstructionFactory.create(codeAttrInfo.code,
+ nextOffset);
+ int nextOpcode = nextInstruction.opcode;
+ if ((nextOpcode == InstructionConstants.OP_POP ||
+ nextOpcode == InstructionConstants.OP_POP2) &&
+ nextInstruction.isCategory2() == isCategory2)
+ {
+ // Delete the pushing instruction and the pop instruction.
+ codeAttrInfoEditor.deleteInstruction(offset);
+ codeAttrInfoEditor.deleteInstruction(nextOffset);
+ }
+ }
+ }
+}
diff --git a/src/proguard/optimize/peephole/SingleImplementationInliner.java b/src/proguard/optimize/peephole/SingleImplementationInliner.java
new file mode 100644
index 0000000..c700199
--- /dev/null
+++ b/src/proguard/optimize/peephole/SingleImplementationInliner.java
@@ -0,0 +1,534 @@
+/* $Id: SingleImplementationInliner.java,v 1.7 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This MemberInfoVisitor and AttrInfoVisitor replaces all references to
+ * interfaces that have single implementations by references to those
+ * implementations.
+ *
+ * @author Eric Lafortune
+ */
+public class SingleImplementationInliner
+implements MemberInfoVisitor,
+ AttrInfoVisitor,
+ InstructionVisitor,
+ CpInfoVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor
+{
+ private MemberFinder memberFinder = new MemberFinder();
+
+ private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
+ private CodeAttrInfoEditor codeAttrInfoEditor = new CodeAttrInfoEditor(1024);
+
+
+ // Return values of the single implementation inliner.
+ private int cpIndex;
+ private ClassFile singleImplementationClassFile;
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ // Update the member info if any of its referenced classes
+ // is an interface with a single implementation.
+ ClassFile[] referencedClassFiles =
+ updateReferencedClassFiles(programMemberInfo.referencedClassFiles);
+
+ // Update the descriptor if necessary.
+ if (referencedClassFiles != null)
+ {
+ programMemberInfo.u2descriptorIndex =
+ constantPoolEditor.addUtf8CpInfo(programClassFile,
+ newDescriptor(programMemberInfo.getDescriptor(programClassFile),
+ referencedClassFiles));
+
+ programMemberInfo.referencedClassFiles = referencedClassFiles;
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ // Reset the code changes.
+ codeAttrInfoEditor.reset(codeAttrInfo.u4codeLength);
+
+ // Update the instructions that refer to interfaces with a single
+ // implementation.
+ codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
+
+ // Apply the code changes.
+ codeAttrInfoEditor.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
+
+ //codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+ }
+
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ // Rename the types of the local variables.
+ localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ // Rename the signatures of the local variables.
+ localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ // TODO: Update signature attribute.
+ }
+
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ // TODO: Update runtime visible annotation attribute.
+
+ //runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ // TODO: Update runtime invisible annotation attribute.
+
+ //runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ // TODO: Update runtime visible parameter annotation attribute.
+
+ //runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ // TODO: Update runtime invisible parameter annotation attribute.
+
+ //runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ // TODO: Update annotation default attribute.
+
+ //annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ cpIndex = 0;
+ classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+
+ if (cpIndex != 0)
+ {
+ byte opcode = cpInstruction.opcode;
+
+ // Does this instruction now invoke a single implementation?
+ if (opcode == InstructionConstants.OP_INVOKEINTERFACE &&
+ singleImplementationClassFile != null)
+ {
+ // Replace the interface invocation by an ordinary invocation.
+ opcode = InstructionConstants.OP_INVOKEVIRTUAL;
+ }
+
+ // Replace the instruction by an updated instruction.
+ Instruction replacementInstruction = new CpInstruction(opcode,
+ cpIndex,
+ cpInstruction.constant).shrink();
+
+ codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ // Create a new string entry if its referenced class is an interface with
+ // a single implementation.
+ singleImplementationClassFile =
+ SingleImplementationMarker.singleImplementation(stringCpInfo.referencedClassFile);
+
+ if (singleImplementationClassFile != null)
+ {
+ // Create a new string entry.
+ cpIndex = constantPoolEditor.addStringCpInfo((ProgramClassFile)classFile,
+ singleImplementationClassFile.getName(),
+ singleImplementationClassFile);
+ }
+ }
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ // Create a new field reference entry if its type has changed.
+ cpIndex = 0;
+ classFile.constantPoolEntryAccept(fieldrefCpInfo.getNameAndTypeIndex(), this);
+ int nameAndTypeIndex = cpIndex;
+
+ if (nameAndTypeIndex != 0)
+ {
+ // Create a new field reference entry.
+ cpIndex = constantPoolEditor.addFieldrefCpInfo((ProgramClassFile)classFile,
+ fieldrefCpInfo.getClassIndex(),
+ nameAndTypeIndex,
+ fieldrefCpInfo.referencedClassFile,
+ fieldrefCpInfo.referencedMemberInfo);
+ }
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ // Create a new method reference entry if its type has changed.
+ cpIndex = 0;
+ classFile.constantPoolEntryAccept(methodrefCpInfo.getNameAndTypeIndex(), this);
+ int nameAndTypeIndex = cpIndex;
+
+ if (nameAndTypeIndex != 0)
+ {
+ // Create a new method reference entry.
+ cpIndex = constantPoolEditor.addMethodrefCpInfo((ProgramClassFile)classFile,
+ methodrefCpInfo.getClassIndex(),
+ nameAndTypeIndex,
+ methodrefCpInfo.referencedClassFile,
+ methodrefCpInfo.referencedMemberInfo);
+ }
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ // Create a new ordinary method reference entry, if its referenced class
+ // is an interface with a single implementation, or a a new interface
+ // method reference entry, if its type has changed.
+ cpIndex = 0;
+ classFile.constantPoolEntryAccept(interfaceMethodrefCpInfo.getClassIndex(), this);
+ int classIndex = cpIndex;
+
+ cpIndex = 0;
+ classFile.constantPoolEntryAccept(interfaceMethodrefCpInfo.getNameAndTypeIndex(), this);
+ int nameAndTypeIndex = cpIndex;
+
+ if (classIndex != 0)
+ {
+ if (nameAndTypeIndex == 0)
+ {
+ nameAndTypeIndex = interfaceMethodrefCpInfo.getNameAndTypeIndex();
+ }
+
+ // See if we can find the referenced method.
+ ClassFile referencedClassFile = singleImplementationClassFile;
+
+ String name = interfaceMethodrefCpInfo.getName(classFile);
+ String type = interfaceMethodrefCpInfo.getType(classFile);
+
+ // See if we can find the referenced class membver somewhere in the
+ // hierarchy.
+ MethodInfo referencedMethodInfo = memberFinder.findMethod(referencedClassFile,
+ name,
+ type);
+ referencedClassFile = memberFinder.correspondingClassFile();
+
+ // Create an ordinary method reference entry.
+ cpIndex = constantPoolEditor.addMethodrefCpInfo((ProgramClassFile)classFile,
+ classIndex,
+ nameAndTypeIndex,
+ referencedClassFile,
+ referencedMethodInfo);
+ }
+ else if (nameAndTypeIndex != 0)
+ {
+ classIndex = interfaceMethodrefCpInfo.getClassIndex();
+
+ // Create an interface method reference entry.
+ cpIndex = constantPoolEditor.addInterfaceMethodrefCpInfo((ProgramClassFile)classFile,
+ classIndex,
+ nameAndTypeIndex,
+ interfaceMethodrefCpInfo.referencedClassFile,
+ interfaceMethodrefCpInfo.referencedMemberInfo);
+ }
+ }
+
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ // Create a new class entry if its referenced class is an interface with
+ // a single implementation.
+ singleImplementationClassFile =
+ SingleImplementationMarker.singleImplementation(classCpInfo.referencedClassFile);
+
+ if (singleImplementationClassFile != null)
+ {
+ // Create a new class entry.
+ cpIndex = constantPoolEditor.addClassCpInfo((ProgramClassFile)classFile,
+ newClassName(classCpInfo.getName(classFile),
+ singleImplementationClassFile),
+ singleImplementationClassFile);
+ }
+ }
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ // Create a new name and type entry if any of the referenced classes of
+ // its type is an interface with a single implementation.
+ ClassFile[] referencedClassFiles =
+ updateReferencedClassFiles(nameAndTypeCpInfo.referencedClassFiles);
+
+ if (referencedClassFiles != null)
+ {
+ // Create a new name and type entry.
+ cpIndex = constantPoolEditor.addNameAndTypeCpInfo((ProgramClassFile)classFile,
+ nameAndTypeCpInfo.getName(classFile),
+ newDescriptor(nameAndTypeCpInfo.getType(classFile),
+ referencedClassFiles),
+ referencedClassFiles);
+ }
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+ {
+ // Create a new type entry if its referenced class is an interface with
+ // a single implementation.
+ ClassFile singleImplementationClassFile =
+ SingleImplementationMarker.singleImplementation(localVariableInfo.referencedClassFile);
+
+ // Update the type if necessary.
+ if (singleImplementationClassFile != null)
+ {
+ // Refer to a new Utf8 entry.
+ localVariableInfo.u2descriptorIndex =
+ constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+ newClassName(classFile.getCpString(localVariableInfo.u2descriptorIndex),
+ singleImplementationClassFile));
+ }
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ // Create a new signature entry if any of the referenced classes of
+ // its type is an interface with a single implementation.
+ ClassFile[] referencedClassFiles =
+ updateReferencedClassFiles(localVariableTypeInfo.referencedClassFiles);
+
+ // Update the signature if necessary.
+ if (referencedClassFiles != null)
+ {
+ localVariableTypeInfo.u2signatureIndex =
+ constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+ newDescriptor(classFile.getCpString(localVariableTypeInfo.u2signatureIndex),
+ referencedClassFiles));
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Updates the given array of referenced class files, if the refer to an
+ * interface with a single implementation. Returns a new array if it
+ * needed to be updated, or <code>null</code> otherwise.
+ */
+ private ClassFile[] updateReferencedClassFiles(ClassFile[] referencedClassFiles)
+ {
+ ClassFile[] newReferencedClassFiles = null;
+
+ // Check all referenced classes.
+ if (referencedClassFiles != null &&
+ referencedClassFilesChanged(referencedClassFiles))
+ {
+ // Create a new array to copy the elements.
+ newReferencedClassFiles = new ClassFile[referencedClassFiles.length];
+
+ // Update all referenced classes.
+ for (int index = 0; index < referencedClassFiles.length; index++)
+ {
+ ClassFile referencedClassFile = referencedClassFiles[index];
+
+ // See if we have is an interface with a single implementation.
+ ClassFile singleImplementationClassFile =
+ SingleImplementationMarker.singleImplementation(referencedClassFile);
+
+ // Update or copy the referenced class file.
+ newReferencedClassFiles[index] = singleImplementationClassFile != null ?
+ singleImplementationClassFile :
+ referencedClassFile;
+ }
+ }
+
+ return newReferencedClassFiles;
+ }
+
+
+ private boolean referencedClassFilesChanged(ClassFile[] referencedClassFiles)
+ {
+ // Check all referenced classes.
+ for (int index = 0; index < referencedClassFiles.length; index++)
+ {
+ // See if we have is an interface with a single implementation.
+ if (SingleImplementationMarker.singleImplementation(referencedClassFiles[index]) != null)
+ {
+ // We've found an element that needs to be updated.
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns the new descriptor based on the given descriptor and the new
+ * names of the given referenced class files.
+ */
+ private String newDescriptor(String descriptor,
+ ClassFile[] referencedClassFiles)
+ {
+ // Unravel and reconstruct the class elements of the descriptor.
+ DescriptorClassEnumeration descriptorClassEnumeration =
+ new DescriptorClassEnumeration(descriptor);
+
+ String newDescriptor = descriptorClassEnumeration.nextFluff();
+
+ int index = 0;
+ while (descriptorClassEnumeration.hasMoreClassNames())
+ {
+ String className = descriptorClassEnumeration.nextClassName();
+ String fluff = descriptorClassEnumeration.nextFluff();
+
+ String newClassName = newClassName(className,
+ referencedClassFiles[index++]);
+
+ // Fall back on the original class name if there is no new name.
+ if (newClassName == null)
+ {
+ newClassName = className;
+ }
+
+ newDescriptor = newDescriptor + newClassName + fluff;
+ }
+
+ return newDescriptor;
+ }
+
+
+ /**
+ * Returns the new class name based on the given class name and the new
+ * name of the given referenced class file. Class names of array types
+ * are handled properly.
+ */
+ private String newClassName(String className,
+ ClassFile referencedClassFile)
+ {
+ // If there is no new class name, the descriptor doesn't change.
+ if (referencedClassFile == null)
+ {
+ return className;
+ }
+
+ // Reconstruct the class name.
+ String newClassName = referencedClassFile.getName();
+
+ // Is it an array type?
+ if (className.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY)
+ {
+ // Add the array prefixes and suffix "[L...;".
+ newClassName =
+ className.substring(0, className.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START)+1) +
+ newClassName +
+ ClassConstants.INTERNAL_TYPE_CLASS_END;
+ }
+
+ return newClassName;
+ }
+}
diff --git a/src/proguard/optimize/peephole/SingleImplementationMarker.java b/src/proguard/optimize/peephole/SingleImplementationMarker.java
new file mode 100644
index 0000000..472fe4c
--- /dev/null
+++ b/src/proguard/optimize/peephole/SingleImplementationMarker.java
@@ -0,0 +1,160 @@
+/* $Id: SingleImplementationMarker.java,v 1.3 2004/11/20 15:41:24 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+import proguard.optimize.*;
+
+/**
+ * This ClassFileVisitor investigates all class files that it visits to see
+ * whether they have/are the sole (non-abstract) implementation of an interface.
+ * It may already modify the access of the single implementing class to match
+ * the access of the interface.
+ *
+ * @author Eric Lafortune
+ */
+public class SingleImplementationMarker
+implements ClassFileVisitor
+{
+ // A visitor info flag to indicate that a ClassFile object is the single
+ // implementation of an interface.
+ private static final Object SINGLE_IMPLEMENTATION = new Object();
+
+
+ private boolean allowAccessModification;
+
+
+ /**
+ * Creates a new SingleImplementationMarker.
+ * @param allowAccessModification indicates whether the access modifiers of
+ * a class can be changed in order to inline
+ * it.
+ */
+ public SingleImplementationMarker(boolean allowAccessModification)
+ {
+ this.allowAccessModification = allowAccessModification;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // The program class must be an interface class that cannot be
+ // implemented again.
+ if ((programClassFile.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) == 0 ||
+ KeepMarker.isKept(programClassFile))
+ {
+ return;
+ }
+
+ // The interface class must have a single implementation.
+ ClassFile[] subClasses = programClassFile.subClasses;
+ if (subClasses == null ||
+ subClasses.length != 1)
+ {
+ return;
+ }
+
+ // If the single implementation is an interface, check it recursively.
+ ClassFile singleImplementationClassFile = subClasses[0];
+ int singleImplementationAccessFlags = singleImplementationClassFile.getAccessFlags();
+ if ((singleImplementationAccessFlags & ClassConstants.INTERNAL_ACC_INTERFACE) != 0)
+ {
+ singleImplementationClassFile.accept(this);
+
+ // See if the subinterface has a single implementation.
+ singleImplementationClassFile = singleImplementation(singleImplementationClassFile);
+ if (singleImplementationClassFile == null)
+ {
+ return;
+ }
+
+ singleImplementationAccessFlags = singleImplementationClassFile.getAccessFlags();
+ }
+
+ // The single implementation must not be abstract.
+ else if ((singleImplementationAccessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0)
+ {
+ return;
+ }
+
+ // Doesn't the implementation have at least the same access as the
+ // interface?
+ if (AccessUtil.accessLevel(singleImplementationAccessFlags) <
+ AccessUtil.accessLevel(programClassFile.getAccessFlags()))
+ {
+ // Are we allowed to fix the access?
+ if (allowAccessModification)
+ {
+ // Fix the access.
+ ((ProgramClassFile)singleImplementationClassFile).u2accessFlags =
+ AccessUtil.replaceAccessFlags(singleImplementationAccessFlags,
+ programClassFile.getAccessFlags());
+ }
+ else
+ {
+ // We can't give the implementation the access of the interface.
+ // Forget about inlining it after all.
+ return;
+ }
+ }
+
+ // Mark the interface and its single implementation.
+ markSingleImplementation(programClassFile, singleImplementationClassFile);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+
+
+ // Small utility methods.
+
+ public static void markSingleImplementation(VisitorAccepter visitorAccepter,
+ ClassFile singleImplementation)
+ {
+ //System.out.println("Marking single implementation ["+((ClassFile)visitorAccepter).getName()+"] -> ["+singleImplementation.getName()+"]");
+
+ // The interface has a single implementation.
+ visitorAccepter.setVisitorInfo(singleImplementation);
+
+ // The class is a single implementation.
+ singleImplementation.setVisitorInfo(SINGLE_IMPLEMENTATION);
+ }
+
+
+ public static ClassFile singleImplementation(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter != null &&
+ visitorAccepter.getVisitorInfo() instanceof ClassFile ?
+ (ClassFile)visitorAccepter.getVisitorInfo() :
+ null;
+ }
+
+
+ public static boolean isSingleImplementation(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter != null &&
+ visitorAccepter.getVisitorInfo() == SINGLE_IMPLEMENTATION;
+ }
+}
diff --git a/src/proguard/optimize/peephole/StoreLoadReplacer.java b/src/proguard/optimize/peephole/StoreLoadReplacer.java
new file mode 100644
index 0000000..74e62f9
--- /dev/null
+++ b/src/proguard/optimize/peephole/StoreLoadReplacer.java
@@ -0,0 +1,116 @@
+/* $Id: StoreLoadReplacer.java,v 1.7 2004/11/20 15:06:55 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This InstructionVisitor replaces store/load instruction pairs by equivalent
+ * dup/store instruction pairs.
+ *
+ * @author Eric Lafortune
+ */
+public class StoreLoadReplacer implements InstructionVisitor
+{
+ // Some Instruction objects that can be reused.
+ private Instruction dupInstruction = new SimpleInstruction(InstructionConstants.OP_DUP);
+ private Instruction dup2Instruction = new SimpleInstruction(InstructionConstants.OP_DUP2);
+
+ private BranchTargetFinder branchTargetFinder;
+ private CodeAttrInfoEditor codeAttrInfoEditor;
+
+
+ /**
+ * Creates a new StoreLoadReplacer.
+ * @param branchTargetFinder a branch target finder that has been
+ * initialized to indicate branch targets
+ * in the visited code.
+ * @param codeAttrInfoEditor a code editor that can be used for
+ * accumulating changes to the code.
+ */
+ public StoreLoadReplacer(BranchTargetFinder branchTargetFinder,
+ CodeAttrInfoEditor codeAttrInfoEditor)
+ {
+ this.branchTargetFinder = branchTargetFinder;
+ this.codeAttrInfoEditor = codeAttrInfoEditor;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+ {
+ // Is this instruction a regular store instruction?
+ if (!variableInstruction.isLoad() &&
+ variableInstruction.opcode != InstructionConstants.OP_IINC)
+ {
+ byte opcode = variableInstruction.opcode;
+ int variableIndex = variableInstruction.variableIndex;
+
+ int nextOffset = offset + variableInstruction.length(offset);
+
+ if (!codeAttrInfoEditor.isModified(offset) &&
+ !codeAttrInfoEditor.isModified(nextOffset) &&
+ !branchTargetFinder.isBranchTarget(nextOffset))
+ {
+ // Is the next instruction a corresponding load instruction?
+ Instruction nextInstruction = InstructionFactory.create(codeAttrInfo.code,
+ nextOffset);
+
+ if (nextInstruction instanceof VariableInstruction)
+ {
+ variableInstruction = (VariableInstruction)nextInstruction;
+ if (variableInstruction.isLoad() &&
+ variableInstruction.opcode != InstructionConstants.OP_RET &&
+ variableInstruction.variableIndex == variableIndex)
+ {
+ // Replace the store instruction by a matching dup instruction.
+ Instruction matchingDupInstruction = variableInstruction.isCategory2() ?
+ dup2Instruction :
+ dupInstruction;
+
+ codeAttrInfoEditor.replaceInstruction(offset,
+ matchingDupInstruction);
+
+ // Replace the load instruction by the store instruction.
+ Instruction storeInstruction =
+ new VariableInstruction(opcode,
+ variableInstruction.variableIndex).shrink();
+
+ codeAttrInfoEditor.replaceInstruction(nextOffset,
+ storeInstruction);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/proguard/optimize/peephole/package.html b/src/proguard/optimize/peephole/package.html
new file mode 100644
index 0000000..e0eeb51
--- /dev/null
+++ b/src/proguard/optimize/peephole/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains visitors that perform various peephole optimizations.
+</body>
diff --git a/src/proguard/package.html b/src/proguard/package.html
new file mode 100644
index 0000000..986cad8
--- /dev/null
+++ b/src/proguard/package.html
@@ -0,0 +1,5 @@
+<body>
+This package contains the main ProGuard application.
+ProGuard can read jar files, shrink and obfuscate them, and write out the
+resulting jar file.
+</body>
diff --git a/src/proguard/retrace/ReTrace.java b/src/proguard/retrace/ReTrace.java
new file mode 100644
index 0000000..b981572
--- /dev/null
+++ b/src/proguard/retrace/ReTrace.java
@@ -0,0 +1,155 @@
+/* $Id: ReTrace.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.retrace;
+
+import java.io.IOException;
+
+import proguard.obfuscate.MappingReader;
+
+
+/**
+ * Tool for de-obfuscating stack traces of applications that were obfuscated
+ * with ProGuard.
+ *
+ * @author Eric Lafortune
+ */
+public class ReTrace
+{
+ private static final String VERBOSE_OPTION = "-verbose";
+
+
+ // The class settings.
+ private boolean verbose;
+ private String mappingFileName;
+ private String stackTraceFileName;
+
+
+ /**
+ * Creates a new ReTrace object to process stack traces on the standard
+ * input, based on the given mapping file name.
+ * @param verbose specifies whether the de-obfuscated stack trace
+ * should be verbose.
+ * @param mappingFileName the mapping file that was written out by ProGuard.
+ */
+ public ReTrace(boolean verbose,
+ String mappingFileName)
+ {
+ this(verbose, mappingFileName, null);
+ }
+
+
+ /**
+ * Creates a new ReTrace object to process a stack trace from the given file,
+ * based on the given mapping file name.
+ * @param verbose specifies whether the de-obfuscated stack trace
+ * should be verbose.
+ * @param mappingFileName the mapping file that was written out by
+ * ProGuard.
+ * @param stackTraceFileName the name of the file that contains the stack
+ * trace.
+ */
+ public ReTrace(boolean verbose,
+ String mappingFileName,
+ String stackTraceFileName)
+ {
+ this.verbose = verbose;
+ this.mappingFileName = mappingFileName;
+ this.stackTraceFileName = stackTraceFileName;
+ }
+
+
+ /**
+ * Performs the subsequent ReTrace operations.
+ */
+ public void execute() throws IOException
+ {
+ StackTrace stackTrace = new StackTrace(verbose);
+ MappingReader reader = new MappingReader(mappingFileName);
+
+ // Read the obfuscated stack trace.
+ stackTrace.read(stackTraceFileName);
+
+ // Resolve the obfuscated stack trace by means of the mapping file.
+ reader.pump(stackTrace);
+
+ // Print out the resolved stack trace.
+ stackTrace.print();
+ }
+
+
+ /**
+ * The main program for ReTrace.
+ */
+ public static void main(String[] args)
+ {
+ if (args.length < 1)
+ {
+ System.err.println("Usage: java proguard.ReTrace [-verbose] <mapping_file> [<stacktrace_file>]");
+ System.exit(-1);
+ }
+
+ int argumentIndex = 0;
+
+ boolean verbose = false;
+ if (args[argumentIndex].equals(VERBOSE_OPTION))
+ {
+ verbose = true;
+ argumentIndex++;
+
+ if (args.length < 2)
+ {
+ System.err.println("Usage: java proguard.ReTrace [-verbose] <mapping_file> [<stacktrace_file>]");
+ System.exit(-1);
+ }
+ }
+
+ String mappingFileName = args[argumentIndex++];
+ String stackTraceFileName = argumentIndex < args.length ?
+ args[argumentIndex++] :
+ null;
+
+ ReTrace reTrace = new ReTrace(verbose,
+ mappingFileName,
+ stackTraceFileName);
+ try
+ {
+ // Execute ReTrace with its given settings.
+ reTrace.execute();
+ }
+ catch (IOException ex)
+ {
+ if (verbose)
+ {
+ // Print a verbose stack trace.
+ ex.printStackTrace();
+ }
+ else
+ {
+ // Print just the stack trace message.
+ System.err.println("Error: "+ex.getMessage());
+ }
+
+ System.exit(1);
+ }
+
+ System.exit(0);
+ }
+}
diff --git a/src/proguard/retrace/StackTrace.java b/src/proguard/retrace/StackTrace.java
new file mode 100644
index 0000000..50961c9
--- /dev/null
+++ b/src/proguard/retrace/StackTrace.java
@@ -0,0 +1,177 @@
+/* $Id: StackTrace.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.retrace;
+
+import java.io.*;
+import java.util.*;
+
+import proguard.obfuscate.MappingProcessor;
+
+
+/**
+ * This class represents an obfuscated stack trace. It can read, de-obfuscate,
+ * and then write its contents.
+ *
+ * @author Eric Lafortune
+ */
+class StackTrace implements MappingProcessor
+{
+ // The stack trace settings.
+ private boolean verbose;
+
+ // The stack trace items.
+ private List stackTraceItems = new ArrayList();
+
+
+ /**
+ * Creates a new StackTrace.
+ * @param verbose specifies whether the de-obfuscated stack trace should
+ * be verbose.
+ */
+ public StackTrace(boolean verbose)
+ {
+ this.verbose = verbose;
+ }
+
+
+ /**
+ * Reads the stack trace file.
+ */
+ public void read(String stackTraceFileName) throws IOException
+ {
+ LineNumberReader lineNumberReader = null;
+
+ try
+ {
+ Reader reader = stackTraceFileName == null ?
+ (Reader)new InputStreamReader(System.in) :
+ (Reader)new BufferedReader(new FileReader(stackTraceFileName));
+
+ lineNumberReader = new LineNumberReader(reader);
+
+ // Read the line in the stack trace.
+ while (true)
+ {
+ String line = lineNumberReader.readLine();
+ if (line == null)
+ {
+ break;
+ }
+
+ line = line.trim();
+ if (line.length() == 0)
+ {
+ continue;
+ }
+
+ // Put the line in a stack trace item.
+ StackTraceItem item = new StackTraceItem(verbose);
+
+ item.parse(line);
+
+ stackTraceItems.add(item);
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new IOException("Can't read stack trace (" + ex.getMessage() + ")");
+ }
+ finally
+ {
+ if (stackTraceFileName != null &&
+ lineNumberReader != null)
+ {
+ try
+ {
+ lineNumberReader.close();
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Prints out the de-obfuscated stack trace.
+ */
+ public void print()
+ {
+ // Delegate to each of the stack trace items.
+ for (int index = 0; index < stackTraceItems.size(); index++)
+ {
+ StackTraceItem item = (StackTraceItem)stackTraceItems.get(index);
+
+ item.print();
+ }
+ }
+
+
+ // Implementations for MappingProcessor.
+
+ public boolean processClassFileMapping(String className,
+ String newClassName)
+ {
+ // Delegate to each of the stack trace items.
+ boolean present = false;
+ for (int index = 0; index < stackTraceItems.size(); index++)
+ {
+ StackTraceItem item = (StackTraceItem)stackTraceItems.get(index);
+
+ present |= item.processClassFileMapping(className,
+ newClassName);
+ }
+
+ return present;
+ }
+
+
+ public void processFieldMapping(String className,
+ String fieldType,
+ String fieldName,
+ String newFieldName)
+ {
+ // A stack trace never contains any fields.
+ }
+
+
+ public void processMethodMapping(String className,
+ int firstLineNumber,
+ int lastLineNumber,
+ String methodReturnType,
+ String methodNameAndArguments,
+ String newMethodName)
+ {
+ // Delegate to each of the stack trace items.
+ for (int index = 0; index < stackTraceItems.size(); index++)
+ {
+ StackTraceItem item = (StackTraceItem)stackTraceItems.get(index);
+
+ item.processMethodMapping(className,
+ firstLineNumber,
+ lastLineNumber,
+ methodReturnType,
+ methodNameAndArguments,
+ newMethodName);
+ }
+ }
+}
diff --git a/src/proguard/retrace/StackTraceItem.java b/src/proguard/retrace/StackTraceItem.java
new file mode 100644
index 0000000..f3e30c3
--- /dev/null
+++ b/src/proguard/retrace/StackTraceItem.java
@@ -0,0 +1,294 @@
+/* $Id: StackTraceItem.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.retrace;
+
+import java.io.*;
+import java.util.*;
+
+import proguard.obfuscate.MappingProcessor;
+
+
+/**
+ * This class represents an obfuscated stack trace item. It can read, de-obfuscate,
+ * and then write its contents.
+ *
+ * @author Eric Lafortune
+ */
+class StackTraceItem implements MappingProcessor
+{
+ // The stack trace settings.
+ private boolean verbose;
+
+ public String prefix;
+ public String obfuscatedClassName;
+ public String obfuscatedMethodName;
+ public String sourceFile;
+ public int lineNumber;
+ public String suffix;
+
+ public String originalClassName;
+ public List originalMethodNames;
+
+ /**
+ * Creates a new StackTraceItem.
+ * @param verbose specifies whether the de-obfuscated stack trace should
+ * be verbose.
+ */
+ public StackTraceItem(boolean verbose)
+ {
+ this.verbose = verbose;
+ }
+
+
+ /**
+ * Parses the stack trace
+ */
+ public void parse(String line) throws IOException
+ {
+ if (!parseAtLine(line) &&
+ !parseExceptionInThreadLine(line))
+ {
+ parseAnyLine(line);
+ }
+ }
+
+
+ /**
+ * Tries to parse "at ___.___(___:___)", containing the class name,
+ * the method name, the source file, and the optional line number.
+ */
+ private boolean parseAtLine(String line)
+ {
+ if (!line.startsWith("at "))
+ {
+ return false;
+ }
+
+ int openParenthesisIndex = line.indexOf('(', 3);
+ if (openParenthesisIndex < 0)
+ {
+ return false;
+ }
+
+ int colonIndex = line.indexOf(':', openParenthesisIndex + 1);
+
+ int closeParenthesisIndex = line.indexOf(')', Math.max(openParenthesisIndex, colonIndex) + 1);
+ if (closeParenthesisIndex < 0)
+ {
+ return false;
+ }
+
+ int periodIndex = line.lastIndexOf('.', openParenthesisIndex - 1);
+ if (periodIndex < 0)
+ {
+ return false;
+ }
+
+ prefix = " at ";
+ obfuscatedClassName = line.substring(3, periodIndex).trim();
+ obfuscatedMethodName = line.substring(periodIndex + 1, openParenthesisIndex).trim();
+ sourceFile = line.substring(openParenthesisIndex + 1, colonIndex < 0 ? closeParenthesisIndex : colonIndex).trim();
+ lineNumber = colonIndex < 0 ? 0 : Integer.parseInt(line.substring(colonIndex + 1, closeParenthesisIndex).trim());
+
+ return true;
+ }
+
+
+ /**
+ * Tries to parse "Exception in thread "___" ___:___" or just "___:___",
+ * containing the optional thread name, the exception class name and the
+ * exception message.
+ */
+ private boolean parseExceptionInThreadLine(String line)
+ {
+ // Trim away the thread message part, if any.
+ if (line.startsWith("Exception in thread \""))
+ {
+ int quote_index = line.indexOf('"', 21);
+ if (quote_index < 0)
+ {
+ return false;
+ }
+
+ prefix = line.substring(0, quote_index+1) + " ";
+ line = line.substring(quote_index+1).trim();
+ }
+
+ int colonIndex = line.indexOf(':');
+ if (colonIndex < 0)
+ {
+ return false;
+ }
+
+ int spaceIndex = line.lastIndexOf(' ', colonIndex);
+
+ prefix = line.substring(0, spaceIndex+1);
+ obfuscatedClassName = line.substring(spaceIndex+1, colonIndex).trim();;
+ suffix = line.substring(colonIndex);
+
+ return true;
+ }
+
+
+ /**
+ * Parses any line.
+ */
+ private void parseAnyLine(String line)
+ {
+ prefix = line;
+ }
+
+
+ /**
+ * Prints out the de-obfuscated stack trace.
+ */
+ public void print()
+ {
+ // Get the original class name, if we found it.
+ String className = originalClassName != null ?
+ originalClassName :
+ obfuscatedClassName;
+
+ // Get the first original method name, if we found it.
+ String methodName = originalMethodNames != null ?
+ (String)originalMethodNames.get(0) :
+ obfuscatedMethodName;
+
+ // Compose the source file with the line number, if any.
+ String source = lineNumber != 0 ?
+ sourceFile + ":" + lineNumber :
+ sourceFile;
+
+ // Print out the resolved stack trace
+ if (prefix != null)
+ {
+ System.out.print(prefix);
+ }
+
+ if (className != null)
+ {
+ System.out.print(className);
+ }
+
+ if (methodName != null)
+ {
+ System.out.print("." + methodName + "(" + source + ")");
+
+ // Print out alternatives, if any.
+ if (originalMethodNames != null)
+ {
+ for (int otherMethodNameIndex = 1; otherMethodNameIndex < originalMethodNames.size(); otherMethodNameIndex++) {
+ String otherMethodName = (String)originalMethodNames.get(otherMethodNameIndex);
+ System.out.println();
+ printSpaces(className.length()+12);
+ System.out.print(otherMethodName);
+ }
+ }
+ }
+
+ if (suffix != null)
+ {
+ System.out.print(suffix);
+ }
+
+ System.out.println();
+ }
+
+
+ /**
+ * Prints the given number of spaces.
+ */
+ private void printSpaces(int aCount)
+ {
+ for (int counter = 0; counter < aCount; counter++)
+ System.out.print(' ');
+ }
+
+
+ // Implementations for MappingProcessor.
+
+ public boolean processClassFileMapping(String className,
+ String newClassName)
+ {
+ boolean present = false;
+
+ if (newClassName.equals(obfuscatedClassName))
+ {
+ originalClassName = className;
+ present = true;
+ }
+
+ return present;
+ }
+
+
+ public void processFieldMapping(String className,
+ String fieldType,
+ String fieldName,
+ String newFieldName)
+ {
+ // A stack trace item never contains any fields.
+ }
+
+
+ public void processMethodMapping(String className,
+ int firstLineNumber,
+ int lastLineNumber,
+ String methodReturnType,
+ String methodNameAndArguments,
+ String newMethodName)
+ {
+ if (className.equals(originalClassName) &&
+ newMethodName.equals(obfuscatedMethodName) &&
+ (lineNumber == 0 ||
+ firstLineNumber == 0 ||
+ lastLineNumber == 0 ||
+ (firstLineNumber <= lineNumber &&
+ lastLineNumber >= lineNumber)))
+ {
+ // Create a List for storing solutions for this
+ // method name.
+ if (originalMethodNames == null)
+ {
+ originalMethodNames = new ArrayList();
+ }
+
+ // Does the method have line numbers?
+ if (firstLineNumber != 0 &&
+ lastLineNumber != 0 &&
+ lineNumber != 0)
+ {
+ // Then it will be the one and only solution.
+ obfuscatedMethodName = null;
+ originalMethodNames.clear();
+ }
+
+ // Include return type and arguments in the method name if
+ // we're in verbose mode, otherwise strip the arguments.
+ String originalMethodName = verbose ?
+ (methodReturnType + " " + methodNameAndArguments) :
+ methodNameAndArguments.substring(0, methodNameAndArguments.indexOf('('));
+
+ // Add this method name solution to the list.
+ originalMethodNames.add(originalMethodName);
+ }
+ }
+}
diff --git a/src/proguard/retrace/package.html b/src/proguard/retrace/package.html
new file mode 100644
index 0000000..a35ce21
--- /dev/null
+++ b/src/proguard/retrace/package.html
@@ -0,0 +1,4 @@
+<body>
+This package contains the main ReTrace application.
+ReTrace can de-obfuscate stack traces of obfuscated programs.
+</body>
diff --git a/src/proguard/shrink/ClassFileShrinker.java b/src/proguard/shrink/ClassFileShrinker.java
new file mode 100644
index 0000000..5d5be32
--- /dev/null
+++ b/src/proguard/shrink/ClassFileShrinker.java
@@ -0,0 +1,341 @@
+/* $Id: ClassFileShrinker.java,v 1.25 2004/12/04 23:43:43 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.shrink;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.editor.ConstantPoolRemapper;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor removes constant pool entries and class members that
+ * are not marked as being used.
+ *
+ * @see UsageMarker
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileShrinker
+ implements ClassFileVisitor,
+ MemberInfoVisitor,
+ AttrInfoVisitor
+{
+ private int[] cpIndexMap;
+ private ConstantPoolRemapper constantPoolRemapper;
+
+
+ /**
+ * Creates a new ClassFileShrinker.
+ * @param codeLength an estimate of the maximum length of all the code that
+ * will be edited.
+ */
+ public ClassFileShrinker(int codeLength)
+ {
+ constantPoolRemapper = new ConstantPoolRemapper(codeLength);
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ // Shrink the arrays for constant pool, interfaces, fields, methods,
+ // and class attributes.
+ programClassFile.u2interfacesCount =
+ shrinkCpIndexArray(programClassFile.constantPool,
+ programClassFile.u2interfaces,
+ programClassFile.u2interfacesCount);
+
+ // Shrinking the constant pool also sets up an index map.
+ programClassFile.u2constantPoolCount =
+ shrinkConstantPool(programClassFile.constantPool,
+ programClassFile.u2constantPoolCount);
+
+ programClassFile.u2fieldsCount =
+ shrinkArray(programClassFile.fields,
+ programClassFile.u2fieldsCount);
+
+ programClassFile.u2methodsCount =
+ shrinkArray(programClassFile.methods,
+ programClassFile.u2methodsCount);
+
+ programClassFile.u2attributesCount =
+ shrinkArray(programClassFile.attributes,
+ programClassFile.u2attributesCount);
+
+ // Compact the remaining fields, methods, and attributes,
+ // and remap their references to the constant pool.
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+ programClassFile.attributesAccept(this);
+
+ // Remap all constant pool references.
+ constantPoolRemapper.setCpIndexMap(cpIndexMap);
+ constantPoolRemapper.visitProgramClassFile(programClassFile);
+
+ // Compact the extra field pointing to the subclasses of this class.
+ programClassFile.subClasses =
+ shrinkToNewArray(programClassFile.subClasses);
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ // Library class files are left unchanged.
+
+ // Compact the extra field pointing to the subclasses of this class.
+ libraryClassFile.subClasses =
+ shrinkToNewArray(libraryClassFile.subClasses);
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ visitMemberInfo(programClassFile, programFieldInfo);
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ visitMemberInfo(programClassFile, programMethodInfo);
+ }
+
+
+ private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ // Compact the attributes array.
+ programMemberInfo.u2attributesCount =
+ shrinkArray(programMemberInfo.attributes,
+ programMemberInfo.u2attributesCount);
+
+ // Compact any attributes.
+ programMemberInfo.attributesAccept(programClassFile, this);
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+ {
+ // Library class files are left unchanged.
+ }
+
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ // Library class files are left unchanged.
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ // Compact the array of InnerClassesInfo objects.
+ innerClassesAttrInfo.u2numberOfClasses =
+ shrinkArray(innerClassesAttrInfo.classes,
+ innerClassesAttrInfo.u2numberOfClasses);
+ }
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ // Sometimes, a class is still referenced (apparently as a dummy class),
+ // but its enclosing method is not. Then remove the reference to
+ // the enclosing method.
+ // E.g. the anonymous inner class javax.swing.JList$1 is defined inside
+ // a constructor of javax.swing.JList, but it is also referenced as a
+ // dummy argument in a constructor of javax.swing.JList$ListSelectionHandler.
+ if (enclosingMethodAttrInfo.referencedMethodInfo != null &&
+ !UsageMarker.isUsed(enclosingMethodAttrInfo.referencedMethodInfo))
+ {
+ enclosingMethodAttrInfo.u2nameAndTypeIndex = 0;
+
+ enclosingMethodAttrInfo.referencedMethodInfo = null;
+ }
+ }
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ // Compact the attributes array.
+ codeAttrInfo.u2attributesCount =
+ shrinkArray(codeAttrInfo.attributes,
+ codeAttrInfo.u2attributesCount);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Removes all entries that are not marked as being used from the given
+ * constant pool.
+ * @return the new number of entries.
+ */
+ private int shrinkConstantPool(CpInfo[] constantPool, int length)
+ {
+ if (cpIndexMap == null ||
+ cpIndexMap.length < length)
+ {
+ cpIndexMap = new int[length];
+ }
+
+ int counter = 1;
+ boolean isUsed = false;
+
+ // Shift the used constant pool entries together.
+ for (int index = 1; index < length; index++)
+ {
+ cpIndexMap[index] = counter;
+
+ CpInfo cpInfo = constantPool[index];
+
+ // Don't update the flag if this is the second half of a long entry.
+ if (cpInfo != null)
+ {
+ isUsed = UsageMarker.isUsed(cpInfo);
+ }
+
+ if (isUsed)
+ {
+ constantPool[counter++] = cpInfo;
+ }
+ }
+
+ // Clear the remaining constant pool elements.
+ for (int index = counter; index < length; index++)
+ {
+ constantPool[index] = null;
+ }
+
+ return counter;
+ }
+
+
+ /**
+ * Removes all indices that point to unused constant pool entries
+ * from the given array.
+ * @return the new number of indices.
+ */
+ private static int shrinkCpIndexArray(CpInfo[] constantPool, int[] array, int length)
+ {
+ int counter = 0;
+
+ // Shift the used objects together.
+ for (int index = 0; index < length; index++)
+ {
+ if (UsageMarker.isUsed(constantPool[array[index]]))
+ {
+ array[counter++] = array[index];
+ }
+ }
+
+ // Clear the remaining array elements.
+ for (int index = counter; index < length; index++)
+ {
+ array[index] = 0;
+ }
+
+ return counter;
+ }
+
+
+ /**
+ * Removes all ClassFile objects that are not marked as being used
+ * from the given array and returns the remaining objects in a an array
+ * of the right size.
+ * @return the new array.
+ */
+ private static ClassFile[] shrinkToNewArray(ClassFile[] array)
+ {
+ if (array == null)
+ {
+ return null;
+ }
+
+ // Shrink the given array in-place.
+ int length = shrinkArray(array, array.length);
+ if (length == 0)
+ {
+ return null;
+ }
+
+ // Return immediately if the array is of right size already.
+ if (length == array.length)
+ {
+ return array;
+ }
+
+ // Copy the remaining elements into a new array of the right size.
+ ClassFile[] newArray = new ClassFile[length];
+ System.arraycopy(array, 0, newArray, 0, length);
+ return newArray;
+ }
+
+
+ /**
+ * Removes all VisitorAccepter objects that are not marked as being used
+ * from the given array.
+ * @return the new number of VisitorAccepter objects.
+ */
+ private static int shrinkArray(VisitorAccepter[] array, int length)
+ {
+ int counter = 0;
+
+ // Shift the used objects together.
+ for (int index = 0; index < length; index++)
+ {
+ if (UsageMarker.isUsed(array[index]))
+ {
+ array[counter++] = array[index];
+ }
+ }
+
+ // Clear the remaining array elements.
+ for (int index = counter; index < length; index++)
+ {
+ array[index] = null;
+ }
+
+ return counter;
+ }
+}
diff --git a/src/proguard/shrink/InnerUsageMarker.java b/src/proguard/shrink/InnerUsageMarker.java
new file mode 100644
index 0000000..26ae15a
--- /dev/null
+++ b/src/proguard/shrink/InnerUsageMarker.java
@@ -0,0 +1,224 @@
+/* $Id: InnerUsageMarker.java,v 1.15 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.shrink;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor recursively marks all inner classes
+ * that are being used in the classes it visits.
+ *
+ * @see UsageMarker
+ *
+ * @author Eric Lafortune
+ */
+public class InnerUsageMarker
+ implements ClassFileVisitor,
+ CpInfoVisitor,
+ AttrInfoVisitor,
+ InnerClassesInfoVisitor
+{
+ private boolean markingAttributes = true;
+ private boolean used;
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ boolean classUsed = UsageMarker.isUsed(programClassFile);
+
+ if (markingAttributes && classUsed)
+ {
+ markingAttributes = false;
+
+ // Check the inner class attribute.
+ programClassFile.attributesAccept(this);
+
+ markingAttributes = true;
+ }
+
+ // The return value.
+ used = classUsed;
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ // The return value.
+ used = true;
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ boolean classUsed = UsageMarker.isUsed(classCpInfo);
+
+ if (!classUsed)
+ {
+ // The ClassCpInfo isn't marked as being used yet. But maybe it should
+ // be included as an interface, so check the actual class.
+ classCpInfo.referencedClassAccept(this);
+ classUsed = used;
+
+ if (classUsed)
+ {
+ // The class is being used. Mark the ClassCpInfo as being used
+ // as well.
+ UsageMarker.markAsUsed(classCpInfo);
+
+ markCpEntry(classFile, classCpInfo.u2nameIndex);
+ }
+ }
+
+ // The return value.
+ used = classUsed;
+ }
+
+
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
+ {
+ if (!UsageMarker.isUsed(utf8CpInfo))
+ {
+ UsageMarker.markAsUsed(utf8CpInfo);
+ }
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo) {}
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ boolean attributeUsed = false;
+
+ // Mark the interfaces that are being used.
+ for (int i = 0; i < innerClassesAttrInfo.u2numberOfClasses; i++)
+ {
+ // Check if the inner class entry is used.
+ visitInnerClassesInfo(classFile, innerClassesAttrInfo.classes[i]);
+ attributeUsed |= used;
+ }
+
+ if (attributeUsed)
+ {
+ // We got a positive used flag, so some inner class is being used.
+ // Mark this attribute as being used as well.
+ UsageMarker.markAsUsed(innerClassesAttrInfo);
+
+ markCpEntry(classFile, innerClassesAttrInfo.u2attrNameIndex);
+ }
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(ClassFile classFile, InnerClassesInfo innerClassesInfo)
+ {
+ boolean innerClassesInfoUsed = UsageMarker.isUsed(innerClassesInfo);
+
+ if (!innerClassesInfoUsed)
+ {
+ int u2innerClassInfoIndex = innerClassesInfo.u2innerClassInfoIndex;
+ int u2outerClassInfoIndex = innerClassesInfo.u2outerClassInfoIndex;
+ int u2innerNameIndex = innerClassesInfo.u2innerNameIndex;
+
+ innerClassesInfoUsed = true;
+
+ if (u2innerClassInfoIndex != 0)
+ {
+ // Check if the inner class is marked as being used.
+ markCpEntry(classFile, u2innerClassInfoIndex);
+ innerClassesInfoUsed &= used;
+ }
+
+ if (u2outerClassInfoIndex != 0)
+ {
+ // Check if the outer class is marked as being used.
+ markCpEntry(classFile, u2outerClassInfoIndex);
+ innerClassesInfoUsed &= used;
+ }
+
+ // If both the inner class and the outer class are marked as being
+ // used, then mark this InnerClassesInfo as well.
+ if (innerClassesInfoUsed)
+ {
+ UsageMarker.markAsUsed(innerClassesInfo);
+
+ if (u2innerNameIndex != 0)
+ {
+ markCpEntry(classFile, u2innerNameIndex);
+ }
+ }
+ }
+
+ // The return value.
+ used = innerClassesInfoUsed;
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given constant pool entry of the given class. This includes
+ * visiting any other referenced constant pool entries.
+ */
+ private void markCpEntry(ClassFile classFile, int index)
+ {
+ classFile.constantPoolEntryAccept(index, this);
+ }
+}
diff --git a/src/proguard/shrink/InterfaceUsageMarker.java b/src/proguard/shrink/InterfaceUsageMarker.java
new file mode 100644
index 0000000..d8c84da
--- /dev/null
+++ b/src/proguard/shrink/InterfaceUsageMarker.java
@@ -0,0 +1,158 @@
+/* $Id: InterfaceUsageMarker.java,v 1.10 2004/12/11 16:35:23 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.shrink;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor recursively marks all interface
+ * classes that are being used in the visited class.
+ *
+ * @see UsageMarker
+ *
+ * @author Eric Lafortune
+ */
+public class InterfaceUsageMarker
+ implements ClassFileVisitor,
+ CpInfoVisitor
+{
+ // A field acting as a return parameter for several methods.
+ private boolean used;
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ boolean classUsed = UsageMarker.isUsed(programClassFile);
+ boolean classPossiblyUsed = UsageMarker.isPossiblyUsed(programClassFile);
+
+ if (classUsed || classPossiblyUsed)
+ {
+ // Mark the references to interfaces that are being used.
+ for (int i = 0; i < programClassFile.u2interfacesCount; i++)
+ {
+ // Check if the interface is used. Mark the constant pool entry
+ // if so.
+ markCpEntry(programClassFile, programClassFile.u2interfaces[i]);
+ classUsed |= used;
+ }
+
+ // Is this an interface with a preliminary mark?
+ if (classPossiblyUsed)
+ {
+ // Should it now be included?
+ if (classUsed)
+ {
+ // At least one if this interface's interfaces is being used.
+ // Mark this interface as well.
+ UsageMarker.markAsUsed(programClassFile);
+
+ // Mark this interface's name.
+ markCpEntry(programClassFile, programClassFile.u2thisClass);
+
+ // Mark the superclass (java/lang/Object).
+ if (programClassFile.u2superClass != 0)
+ {
+ markCpEntry(programClassFile, programClassFile.u2superClass);
+ }
+ }
+ else
+ {
+ // Unmark this interface, so we don't bother looking at it again.
+ UsageMarker.markAsUnused(programClassFile);
+ }
+ }
+ }
+
+ // The return value.
+ used = classUsed;
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ // The return value.
+ used = true;
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ boolean classUsed = UsageMarker.isUsed(classCpInfo);
+
+ if (!classUsed)
+ {
+ // The ClassCpInfo isn't marked as being used yet. But maybe it should
+ // be included as an interface, so check the actual class.
+ classCpInfo.referencedClassAccept(this);
+ classUsed = used;
+
+ if (classUsed)
+ {
+ // The class is being used. Mark the ClassCpInfo as being used
+ // as well.
+ UsageMarker.markAsUsed(classCpInfo);
+
+ markCpEntry(classFile, classCpInfo.u2nameIndex);
+ }
+ }
+
+ // The return value.
+ used = classUsed;
+ }
+
+
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
+ {
+ if (!UsageMarker.isUsed(utf8CpInfo))
+ {
+ UsageMarker.markAsUsed(utf8CpInfo);
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given constant pool entry of the given class. This includes
+ * visiting any referenced objects.
+ */
+ private void markCpEntry(ClassFile classFile, int index)
+ {
+ classFile.constantPoolEntryAccept(index, this);
+ }
+}
diff --git a/src/proguard/shrink/UsageMarker.java b/src/proguard/shrink/UsageMarker.java
new file mode 100644
index 0000000..851f111
--- /dev/null
+++ b/src/proguard/shrink/UsageMarker.java
@@ -0,0 +1,824 @@
+/* $Id: UsageMarker.java,v 1.37 2004/12/19 21:03:54 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.shrink;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor and MemberInfoVisitor recursively marks all
+ * classes and class elements that are being used.
+ *
+ * @see ClassFileShrinker
+ *
+ * @author Eric Lafortune
+ */
+public class UsageMarker
+ implements ClassFileVisitor,
+ MemberInfoVisitor,
+ CpInfoVisitor,
+ AttrInfoVisitor,
+ InnerClassesInfoVisitor,
+ ExceptionInfoVisitor,
+ LocalVariableInfoVisitor,
+ LocalVariableTypeInfoVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor,
+ InstructionVisitor
+{
+ // A visitor info flag to indicate the ProgramMemberInfo object is being used,
+ // if its ClassFile can be determined as being used as well.
+ private static final Object POSSIBLY_USED = new Object();
+ // A visitor info flag to indicate the visitor accepter is being used.
+ private static final Object USED = new Object();
+
+
+ private MyInterfaceUsageMarker interfaceUsageMarker = new MyInterfaceUsageMarker();
+// private ClassFileVisitor dynamicClassMarker =
+// new MultiClassFileVisitor(
+// new ClassFileVisitor[]
+// {
+// this,
+// new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_INIT,
+// ClassConstants.INTERNAL_METHOD_TYPE_INIT,
+// this)
+// });
+
+
+ // A field acting as a parameter to the visitMemberInfo method.
+ private boolean processing = false;
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ if (!isUsed(programClassFile))
+ {
+ // Mark this class.
+ markAsUsed(programClassFile);
+
+ // Mark this class's name.
+ markCpEntry(programClassFile, programClassFile.u2thisClass);
+
+ // Mark the superclass.
+ if (programClassFile.u2superClass != 0)
+ {
+ markCpEntry(programClassFile, programClassFile.u2superClass);
+ }
+
+ // Give the interfaces preliminary marks.
+ programClassFile.hierarchyAccept(false, false, true, false,
+ interfaceUsageMarker);
+
+ // Explicitly mark the <clinit> method.
+ programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
+ ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
+ this);
+
+ // Explicitly mark the parameterless <init> method.
+ programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT,
+ ClassConstants.INTERNAL_METHOD_TYPE_INIT,
+ this);
+
+ // Process all methods that have already been marked as possibly used.
+ processing = true;
+ programClassFile.methodsAccept(this);
+ processing = false;
+
+ // Mark the attributes.
+ programClassFile.attributesAccept(this);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ if (!isUsed(libraryClassFile))
+ {
+ markAsUsed(libraryClassFile);
+
+ // We're not going to analyze all library code. We're assuming that
+ // if this class is being used, all of its methods will be used as
+ // well. We'll mark them as such (here and in all subclasses).
+
+ // Mark the superclass.
+ ClassFile superClass = libraryClassFile.superClass;
+ if (superClass != null)
+ {
+ superClass.accept(this);
+ }
+
+ // Mark the interfaces.
+ ClassFile[] interfaceClasses = libraryClassFile.interfaceClasses;
+ if (interfaceClasses != null)
+ {
+ for (int i = 0; i < interfaceClasses.length; i++)
+ {
+ if (interfaceClasses[i] != null)
+ {
+ interfaceClasses[i].accept(this);
+ }
+ }
+ }
+
+ // Mark all methods.
+ libraryClassFile.methodsAccept(this);
+ }
+ }
+
+
+ /**
+ * This ClassFileVisitor marks ProgramClassFile objects as possibly used,
+ * and it visits LibraryClassFile objects with its outer UsageMarker.
+ */
+ private class MyInterfaceUsageMarker implements ClassFileVisitor
+ {
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ if (!isUsed(programClassFile))
+ {
+ // We can't process the interface yet, because it might not
+ // be required. Give it a preliminary mark.
+ markAsPossiblyUsed(programClassFile);
+ }
+ }
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ // Make sure all library interface methods are marked.
+ UsageMarker.this.visitLibraryClassFile(libraryClassFile);
+ }
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ if (!isUsed(programFieldInfo))
+ {
+ markAsUsed(programFieldInfo);
+
+ // Mark the name and descriptor.
+ markCpEntry(programClassFile, programFieldInfo.u2nameIndex);
+ markCpEntry(programClassFile, programFieldInfo.u2descriptorIndex);
+
+ // Mark the attributes.
+ programFieldInfo.attributesAccept(programClassFile, this);
+
+ // Mark the classes referenced in the descriptor string.
+ programFieldInfo.referencedClassesAccept(this);
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ if (!isUsed(programMethodInfo))
+ {
+ // Are the method and its class used?
+ if (processing ? isPossiblyUsed(programMethodInfo) :
+ isUsed(programClassFile))
+ {
+ markAsUsed(programMethodInfo);
+
+ // Remember the processing flag.
+ boolean oldProcessing = processing;
+ processing = false;
+
+ // Mark the name and descriptor.
+ markCpEntry(programClassFile, programMethodInfo.u2nameIndex);
+ markCpEntry(programClassFile, programMethodInfo.u2descriptorIndex);
+
+ // Mark the attributes.
+ programMethodInfo.attributesAccept(programClassFile, this);
+
+ // Mark the classes referenced in the descriptor string.
+ programMethodInfo.referencedClassesAccept(this);
+
+ // Restore the processing flag.
+ processing = oldProcessing;
+
+ // If the method is being called, mark its hierarchy.
+ if (!processing)
+ {
+ markMethodHierarchy(programClassFile, programMethodInfo);
+ }
+ }
+ else if (!processing && !isPossiblyUsed(programMethodInfo))
+ {
+ // We can't process the class member yet, because the class
+ // file isn't marked as being used (yet). Give it a
+ // preliminary mark.
+ markAsPossiblyUsed(programMethodInfo);
+
+ // The method is being called. Mark its hierarchy.
+ markMethodHierarchy(programClassFile, programMethodInfo);
+ }
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+ {
+ if (!isUsed(libraryMethodInfo))
+ {
+ markAsUsed(libraryMethodInfo);
+
+ markMethodHierarchy(libraryClassFile, libraryMethodInfo);
+ }
+ }
+
+
+ private void markMethodHierarchy(ClassFile classFile, MethodInfo methodInfo)
+ {
+ if ((methodInfo.getAccessFlags() &
+ (ClassConstants.INTERNAL_ACC_PRIVATE |
+ ClassConstants.INTERNAL_ACC_FINAL)) == 0)
+ {
+ String name = methodInfo.getName(classFile);
+ String type = methodInfo.getDescriptor(classFile);
+
+ if (!name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) &&
+ !name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT))
+ {
+ // Mark all implementations of the method.
+ //
+ // For an abstract method:
+ // First go to all concrete implementations or extensions of
+ // the interface or abstract class.
+ // From there, travel up and down the class hierarchy to mark
+ // the method.
+ //
+ // This way, we're also catching retro-fitted interfaces,
+ // where a class's implementation of an interface method is
+ // hiding higher up its class hierarchy.
+ //
+ // For a concrete method:
+ // Simply mark all overriding implementations down the
+ // class hierarchy.
+ classFile.accept(
+ (classFile.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0 ||
+ (methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0 ?
+
+ (ClassFileVisitor)
+ new ConcreteClassFileDownTraveler(
+ new ClassFileHierarchyTraveler(true, true, false, true,
+ new NamedMethodVisitor(name, type,
+ new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this)))) :
+
+ (ClassFileVisitor)
+ new ClassFileHierarchyTraveler(false, false, false, true,
+ new NamedMethodVisitor(name, type,
+ new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this))));
+ }
+ }
+ }
+
+
+ // Implementations for CpInfoVisitor.
+
+ public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo)
+ {
+ if (!isUsed(integerCpInfo))
+ {
+ markAsUsed(integerCpInfo);
+ }
+ }
+
+
+ public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo)
+ {
+ if (!isUsed(longCpInfo))
+ {
+ markAsUsed(longCpInfo);
+ }
+ }
+
+
+ public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo)
+ {
+ if (!isUsed(floatCpInfo))
+ {
+ markAsUsed(floatCpInfo);
+ }
+ }
+
+
+ public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo)
+ {
+ if (!isUsed(doubleCpInfo))
+ {
+ markAsUsed(doubleCpInfo);
+ }
+ }
+
+
+ public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+ {
+ if (!isUsed(stringCpInfo))
+ {
+ markAsUsed(stringCpInfo);
+
+ markCpEntry(classFile, stringCpInfo.u2stringIndex);
+
+ // Mark the referenced class and its parameterless constructor,
+ // if the string is being used in a Class.forName construct.
+ //stringCpInfo.referencedClassAccept(dynamicClassMarker);
+
+ // Mark the referenced class.
+ stringCpInfo.referencedClassAccept(this);
+ }
+ }
+
+
+ public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
+ {
+ if (!isUsed(utf8CpInfo))
+ {
+ markAsUsed(utf8CpInfo);
+ }
+ }
+
+
+ public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+ {
+ visitRefCpInfo(classFile, fieldrefCpInfo);
+ }
+
+
+ public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, interfaceMethodrefCpInfo);
+ }
+
+
+ public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+ {
+ visitRefCpInfo(classFile, methodrefCpInfo);
+ }
+
+
+ private void visitRefCpInfo(ClassFile classFile, RefCpInfo methodrefCpInfo)
+ {
+ if (!isUsed(methodrefCpInfo))
+ {
+ markAsUsed(methodrefCpInfo);
+
+ markCpEntry(classFile, methodrefCpInfo.u2classIndex);
+ markCpEntry(classFile, methodrefCpInfo.u2nameAndTypeIndex);
+
+ // When compiled with "-target 1.2" or higher, the class or
+ // interface actually containing the referenced method may be
+ // higher up the hierarchy. Make sure it's marked, in case it
+ // isn't used elsewhere.
+ methodrefCpInfo.referencedClassAccept(this);
+
+ // Mark the referenced method itself.
+ methodrefCpInfo.referencedMemberInfoAccept(this);
+ }
+ }
+
+
+ public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+ {
+ if (!isUsed(classCpInfo))
+ {
+ markAsUsed(classCpInfo);
+
+ markCpEntry(classFile, classCpInfo.u2nameIndex);
+
+ // Mark the referenced class itself.
+ classCpInfo.referencedClassAccept(this);
+ }
+ }
+
+
+ public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+ {
+ if (!isUsed(nameAndTypeCpInfo))
+ {
+ markAsUsed(nameAndTypeCpInfo);
+
+ markCpEntry(classFile, nameAndTypeCpInfo.u2nameIndex);
+ markCpEntry(classFile, nameAndTypeCpInfo.u2descriptorIndex);
+
+ // Mark the classes referenced in the descriptor string.
+ nameAndTypeCpInfo.referencedClassesAccept(this);
+ }
+ }
+
+
+ // Implementations for AttrInfoVisitor.
+ // Note that attributes are typically only referenced once, so we don't
+ // test if they have been marked already.
+
+ public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo)
+ {
+ // This is the best we can do for unknown attributes.
+ markAsUsed(unknownAttrInfo);
+
+ markCpEntry(classFile, unknownAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo)
+ {
+ // Don't mark the attribute and its name yet. We may mark it later, in
+ // InnerUsageMarker.
+ //markAsUsed(innerClassesAttrInfo);
+
+ //markCpEntry(classFile, innerClassesAttrInfo.u2attrNameIndex);
+ innerClassesAttrInfo.innerClassEntriesAccept(classFile, this);
+ }
+
+
+ public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+ {
+ markAsUsed(enclosingMethodAttrInfo);
+
+ markCpEntry(classFile, enclosingMethodAttrInfo.u2attrNameIndex);
+ markCpEntry(classFile, enclosingMethodAttrInfo.u2classIndex);
+
+ if (enclosingMethodAttrInfo.u2nameAndTypeIndex != 0)
+ {
+ markCpEntry(classFile, enclosingMethodAttrInfo.u2nameAndTypeIndex);
+ }
+ }
+
+
+ public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo)
+ {
+ markAsUsed(constantValueAttrInfo);
+
+ markCpEntry(classFile, constantValueAttrInfo.u2attrNameIndex);
+ markCpEntry(classFile, constantValueAttrInfo.u2constantValueIndex);
+ }
+
+
+ public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo)
+ {
+ markAsUsed(exceptionsAttrInfo);
+
+ markCpEntry(classFile, exceptionsAttrInfo.u2attrNameIndex);
+
+ // Mark the constant pool entries referenced by the exceptions.
+ exceptionsAttrInfo.exceptionEntriesAccept((ProgramClassFile)classFile, this);
+ }
+
+
+ public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+ {
+ markAsUsed(codeAttrInfo);
+
+ markCpEntry(classFile, codeAttrInfo.u2attrNameIndex);
+
+ // Mark the constant pool entries referenced by the instructions,
+ // and the exceptions and attributes.
+ codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
+ codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
+ codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+ }
+
+
+ public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo)
+ {
+ markAsUsed(lineNumberTableAttrInfo);
+
+ markCpEntry(classFile, lineNumberTableAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+ {
+ markAsUsed(localVariableTableAttrInfo);
+
+ markCpEntry(classFile, localVariableTableAttrInfo.u2attrNameIndex);
+
+ // Mark the constant pool entries referenced by the local variables.
+ localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+ {
+ markAsUsed(localVariableTypeTableAttrInfo);
+
+ markCpEntry(classFile, localVariableTypeTableAttrInfo.u2attrNameIndex);
+
+ // Mark the constant pool entries referenced by the local variable types.
+ localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+ }
+
+
+ public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+ {
+ markAsUsed(sourceFileAttrInfo);
+
+ markCpEntry(classFile, sourceFileAttrInfo.u2attrNameIndex);
+ markCpEntry(classFile, sourceFileAttrInfo.u2sourceFileIndex);
+ }
+
+
+ public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
+ {
+ markAsUsed(sourceDirAttrInfo);
+
+ markCpEntry(classFile, sourceDirAttrInfo.u2attrNameIndex);
+ markCpEntry(classFile, sourceDirAttrInfo.u2sourceDirIndex);
+ }
+
+
+ public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo)
+ {
+ markAsUsed(deprecatedAttrInfo);
+
+ markCpEntry(classFile, deprecatedAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo)
+ {
+ markAsUsed(syntheticAttrInfo);
+
+ markCpEntry(classFile, syntheticAttrInfo.u2attrNameIndex);
+ }
+
+
+ public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+ {
+ markAsUsed(signatureAttrInfo);
+
+ markCpEntry(classFile, signatureAttrInfo.u2attrNameIndex);
+ markCpEntry(classFile, signatureAttrInfo.u2signatureIndex);
+ }
+
+
+ public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+ {
+ markAsUsed(runtimeVisibleAnnotationsAttrInfo);
+
+ markCpEntry(classFile, runtimeVisibleAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Mark the constant pool entries referenced by the annotations.
+ runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+ {
+ markAsUsed(runtimeInvisibleAnnotationsAttrInfo);
+
+ markCpEntry(classFile, runtimeInvisibleAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Mark the constant pool entries referenced by the annotations.
+ runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+ {
+ markAsUsed(runtimeVisibleParameterAnnotationsAttrInfo);
+
+ markCpEntry(classFile, runtimeVisibleParameterAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Mark the constant pool entries referenced by the annotations.
+ runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+ {
+ markAsUsed(runtimeInvisibleParameterAnnotationsAttrInfo);
+
+ markCpEntry(classFile, runtimeInvisibleParameterAnnotationsAttrInfo.u2attrNameIndex);
+
+ // Mark the constant pool entries referenced by the annotations.
+ runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+ }
+
+
+ public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+ {
+ markAsUsed(annotationDefaultAttrInfo);
+
+ markCpEntry(classFile, annotationDefaultAttrInfo.u2attrNameIndex);
+
+ // Mark the constant pool entries referenced by the element value.
+ annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+ }
+
+
+ // Implementations for ExceptionInfoVisitor.
+
+ public void visitExceptionInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, ExceptionInfo exceptionInfo)
+ {
+ markAsUsed(exceptionInfo);
+
+ if (exceptionInfo.u2catchType != 0)
+ {
+ markCpEntry(classFile, exceptionInfo.u2catchType);
+ }
+ }
+
+
+ // Implementations for InnerClassesInfoVisitor.
+
+ public void visitInnerClassesInfo(ClassFile classFile, InnerClassesInfo innerClassesInfo)
+ {
+ // At this point, we only mark outer classes of this class.
+ // Inner class can be marked later, by InnerUsageMarker.
+ if (innerClassesInfo.u2innerClassInfoIndex == 0 &&
+ classFile.getName().equals(classFile.getCpClassNameString(innerClassesInfo.u2innerClassInfoIndex)))
+ {
+ markAsUsed(innerClassesInfo);
+
+ if (innerClassesInfo.u2innerClassInfoIndex != 0)
+ {
+ markCpEntry(classFile, innerClassesInfo.u2innerClassInfoIndex);
+ }
+
+ if (innerClassesInfo.u2outerClassInfoIndex != 0)
+ {
+ markCpEntry(classFile, innerClassesInfo.u2outerClassInfoIndex);
+ }
+
+ if (innerClassesInfo.u2innerNameIndex != 0)
+ {
+ markCpEntry(classFile, innerClassesInfo.u2innerNameIndex);
+ }
+ }
+ }
+
+
+ // Implementations for LocalVariableInfoVisitor.
+
+ public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+ {
+ markCpEntry(classFile, localVariableInfo.u2nameIndex);
+ markCpEntry(classFile, localVariableInfo.u2descriptorIndex);
+ }
+
+
+ // Implementations for LocalVariableTypeInfoVisitor.
+
+ public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+ {
+ markCpEntry(classFile, localVariableTypeInfo.u2nameIndex);
+ markCpEntry(classFile, localVariableTypeInfo.u2signatureIndex);
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(ClassFile classFile, Annotation annotation)
+ {
+ markCpEntry(classFile, annotation.u2typeIndex);
+
+ // Mark the constant pool entries referenced by the element values.
+ annotation.elementValuesAccept(classFile, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ if (constantElementValue.u2elementName != 0)
+ {
+ markCpEntry(classFile, constantElementValue.u2elementName);
+ }
+
+ markCpEntry(classFile, constantElementValue.u2constantValueIndex);
+ }
+
+
+ public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ if (enumConstantElementValue.u2elementName != 0)
+ {
+ markCpEntry(classFile, enumConstantElementValue.u2elementName);
+ }
+
+ markCpEntry(classFile, enumConstantElementValue.u2typeNameIndex);
+ markCpEntry(classFile, enumConstantElementValue.u2constantNameIndex);
+ }
+
+
+ public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
+ {
+ if (classElementValue.u2elementName != 0)
+ {
+ markCpEntry(classFile, classElementValue.u2elementName);
+ }
+
+ // Mark the referenced class constant pool entry.
+ markCpEntry(classFile, classElementValue.u2classInfoIndex);
+ }
+
+
+ public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ if (annotationElementValue.u2elementName != 0)
+ {
+ markCpEntry(classFile, annotationElementValue.u2elementName);
+ }
+
+ // Mark the constant pool entries referenced by the annotation.
+ annotationElementValue.annotationAccept(classFile, this);
+ }
+
+
+ public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ if (arrayElementValue.u2elementName != 0)
+ {
+ markCpEntry(classFile, arrayElementValue.u2elementName);
+ }
+
+ // Mark the constant pool entries referenced by the element values.
+ arrayElementValue.elementValuesAccept(classFile, annotation, this);
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+ public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+ public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+ public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+ public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+ public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+ {
+ markCpEntry(classFile, cpInstruction.cpIndex);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Marks the given constant pool entry of the given class. This includes
+ * visiting any referenced objects.
+ */
+ private void markCpEntry(ClassFile classFile, int index)
+ {
+ classFile.constantPoolEntryAccept(index, this);
+ }
+
+
+ static void markAsUnused(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(null);
+ }
+
+
+ static void markAsPossiblyUsed(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(POSSIBLY_USED);
+ }
+
+
+ static boolean isPossiblyUsed(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == POSSIBLY_USED;
+ }
+
+
+ static void markAsUsed(VisitorAccepter visitorAccepter)
+ {
+ visitorAccepter.setVisitorInfo(USED);
+ }
+
+
+ static boolean isUsed(VisitorAccepter visitorAccepter)
+ {
+ return visitorAccepter.getVisitorInfo() == USED;
+ }
+}
diff --git a/src/proguard/shrink/UsagePrinter.java b/src/proguard/shrink/UsagePrinter.java
new file mode 100644
index 0000000..18abcaa
--- /dev/null
+++ b/src/proguard/shrink/UsagePrinter.java
@@ -0,0 +1,174 @@
+/* $Id: UsagePrinter.java,v 1.16 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.shrink;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+
+/**
+ * This ClassFileVisitor prints out the class files and class members that have been
+ * marked as being used (or not used).
+ *
+ * @see UsageMarker
+ *
+ * @author Eric Lafortune
+ */
+public class UsagePrinter
+ implements ClassFileVisitor,
+ MemberInfoVisitor
+{
+ private boolean printUnusedItems;
+ private PrintStream ps;
+
+ // A field to remember the class name, if a header is needed for class members.
+ private String className;
+
+
+ /**
+ * Creates a new UsagePrinter that prints to <code>System.out</code>.
+ * @param printUsedItems a flag that indicates whether only unused items
+ * should be printed, or alternatively, only used items.
+ */
+ public UsagePrinter(boolean printUnusedItems)
+ {
+ this(printUnusedItems, System.out);
+ }
+
+
+ /**
+ * Creates a new UsagePrinter that prints to the given stream.
+ * @param printUsedItems a flag that indicates whether only unused items
+ * should be printed, or alternatively, only used items.
+ * @param printStream the stream to which to print
+ */
+ public UsagePrinter(boolean printUnusedItems, PrintStream printStream)
+ {
+ this.printUnusedItems = printUnusedItems;
+ this.ps = printStream;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ if (UsageMarker.isUsed(programClassFile))
+ {
+ if (printUnusedItems)
+ {
+ className = programClassFile.getName();
+
+ programClassFile.fieldsAccept(this);
+ programClassFile.methodsAccept(this);
+
+ className = null;
+ }
+ else
+ {
+ ps.println(ClassUtil.externalClassName(programClassFile.getName()));
+ }
+ }
+ else
+ {
+ if (printUnusedItems)
+ {
+ ps.println(ClassUtil.externalClassName(programClassFile.getName()));
+ }
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ }
+
+
+ // Implementations for MemberInfoVisitor.
+
+ public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+ {
+ if (UsageMarker.isUsed(programFieldInfo) ^ printUnusedItems)
+ {
+ printClassNameHeader();
+
+ ps.println(" " +
+ lineNumberRange(programClassFile, programFieldInfo) +
+ ClassUtil.externalFullFieldDescription(
+ programFieldInfo.getAccessFlags(),
+ programFieldInfo.getName(programClassFile),
+ programFieldInfo.getDescriptor(programClassFile)));
+ }
+ }
+
+
+ public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+ {
+ if (UsageMarker.isUsed(programMethodInfo) ^ printUnusedItems)
+ {
+ printClassNameHeader();
+
+ ps.println(" " +
+ lineNumberRange(programClassFile, programMethodInfo) +
+ ClassUtil.externalFullMethodDescription(
+ programClassFile.getName(),
+ programMethodInfo.getAccessFlags(),
+ programMethodInfo.getName(programClassFile),
+ programMethodInfo.getDescriptor(programClassFile)));
+ }
+ }
+
+
+ public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+ public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+ // Small utility methods.
+
+ /**
+ * Prints the class name field. The field is then cleared, so it is not
+ * printed again.
+ */
+ private void printClassNameHeader()
+ {
+ if (className != null)
+ {
+ ps.println(ClassUtil.externalClassName(className) + ":");
+ className = null;
+ }
+ }
+
+
+ /**
+ * Returns the line number range of the given class member, followed by a
+ * colon, or just an empty String if no range is available.
+ */
+ private static String lineNumberRange(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+ {
+ String range = programMemberInfo.getLineNumberRange(programClassFile);
+ return range != null ?
+ (range + ":") :
+ "";
+ }
+}
diff --git a/src/proguard/shrink/UsedClassFileFilter.java b/src/proguard/shrink/UsedClassFileFilter.java
new file mode 100644
index 0000000..6b33c62
--- /dev/null
+++ b/src/proguard/shrink/UsedClassFileFilter.java
@@ -0,0 +1,65 @@
+/* $Id: UsedClassFileFilter.java,v 1.9 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.shrink;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor delegates all its method calls to another
+ * ClassFileVisitor, but only for ClassFile objects that are marked as used.
+ *
+ * @see UsageMarker
+ *
+ * @author Eric Lafortune
+ */
+public class UsedClassFileFilter
+ implements ClassFileVisitor
+{
+ ClassFileVisitor classFileVisitor;
+
+
+ public UsedClassFileFilter(ClassFileVisitor classFileVisitor)
+ {
+ this.classFileVisitor = classFileVisitor;
+ }
+
+
+ // Implementations for ClassFileVisitor.
+
+ public void visitProgramClassFile(ProgramClassFile programClassFile)
+ {
+ if (UsageMarker.isUsed(programClassFile))
+ {
+ classFileVisitor.visitProgramClassFile(programClassFile);
+ }
+ }
+
+
+ public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+ {
+ if (UsageMarker.isUsed(libraryClassFile))
+ {
+ classFileVisitor.visitLibraryClassFile(libraryClassFile);
+ }
+ }
+}
diff --git a/src/proguard/shrink/package.html b/src/proguard/shrink/package.html
new file mode 100644
index 0000000..8973198
--- /dev/null
+++ b/src/proguard/shrink/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains classes to perform shrinking of class files.
+</body>
diff --git a/src/proguard/util/BasicListMatcher.java b/src/proguard/util/BasicListMatcher.java
new file mode 100644
index 0000000..3a3c44d
--- /dev/null
+++ b/src/proguard/util/BasicListMatcher.java
@@ -0,0 +1,148 @@
+/* $Id: BasicListMatcher.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.util;
+
+import java.util.*;
+
+
+/**
+ * This StringMatcher tests whether strings match an entry in a given list of
+ * regular expressions. The list is given as a comma-separated string or as a
+ * List of strings. An exclamation mark preceding a list entry acts as a
+ * negator: if the expression matches, a negative match is returned, without
+ * considering any subsequent entries. If none of the entries match, a positive
+ * match is returned depending on whether the last regular expression had a
+ * negator or not.
+ * <p>
+ * The individual regular expression matching is delegated to a StringMatcher
+ * that is created by the {@link #createBasicMatcher(String}} method. If it is
+ * not overridden, this method returns a BasicMatcher.
+ *
+ * @see BasicMatcher
+ * @author Eric Lafortune
+ */
+public class BasicListMatcher implements StringMatcher
+{
+ private static final char REGULAR_EXPRESSION_SEPARATOR = ',';
+ private static final char REGULAR_EXPRESSION_NEGATOR = '!';
+
+ private StringMatcher[] regularExpressionMatchers;
+ private boolean[] negatedRegularExpressions;
+
+
+ /**
+ * Creates a new BasicListMatcher.
+ * @param regularExpression the comma-separated list of regular expressions
+ * against which strings will be matched.
+ */
+ public BasicListMatcher(String regularExpression)
+ {
+ this(ListUtil.commaSeparatedList(regularExpression));
+ }
+
+
+ /**
+ * Creates a new BasicListMatcher.
+ * @param regularExpressionList the list of regular expressions against which
+ * strings will be matched.
+ */
+ public BasicListMatcher(List regularExpressionList)
+ {
+ // Collect the regular expressions in arrays.
+ int regularExpressionCount = regularExpressionList.size();
+
+ regularExpressionMatchers = new StringMatcher[regularExpressionCount];
+ negatedRegularExpressions = new boolean[regularExpressionCount];
+
+ for (int index = 0; index < regularExpressionCount; index++)
+ {
+ String regularExpression = (String)regularExpressionList.get(index);
+
+ // Does the regular expression start with an exclamation mark?
+ if (regularExpression.length() > 0 &&
+ regularExpression.charAt(0) == REGULAR_EXPRESSION_NEGATOR)
+ {
+ // Trim the regular expression.
+ regularExpression = regularExpression.substring(1);
+
+ // Remember the negator.
+ negatedRegularExpressions[index] = true;
+ }
+
+ regularExpressionMatchers[index] =
+ createBasicMatcher(regularExpression);
+ }
+ }
+
+
+ /**
+ * Creates a new StringMatcher for the given regular expression.
+ */
+ protected StringMatcher createBasicMatcher(String regularExpression)
+ {
+ return new BasicMatcher(regularExpression);
+ }
+
+
+ // Implementations for StringMatcher.
+
+ public boolean matches(String string)
+ {
+ boolean result = true;
+
+ for (int index = 0; index < regularExpressionMatchers.length; index++)
+ {
+ result = negatedRegularExpressions[index];
+
+ if (regularExpressionMatchers[index].matches(string))
+ {
+ return !result;
+ }
+ }
+
+ return result;
+ }
+
+
+ /**
+ * A main method for testing string matching.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ System.out.println("Regular expression ["+args[0]+"]");
+ BasicListMatcher matcher =
+ new BasicListMatcher(args[0]);
+
+ for (int index = 1; index < args.length; index++)
+ {
+ String string = args[index];
+ System.out.print("String ["+string+"]");
+ System.out.println(" -> match = "+matcher.matches(args[index]));
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/util/BasicMatcher.java b/src/proguard/util/BasicMatcher.java
new file mode 100644
index 0000000..ee173eb
--- /dev/null
+++ b/src/proguard/util/BasicMatcher.java
@@ -0,0 +1,360 @@
+/* $Id: BasicMatcher.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.util;
+
+import java.util.*;
+
+
+/**
+ * This StringMatcher tests whether strings match a given regular
+ * expression. Supported wildcards are
+ * <ul>
+ * <li>'?' for a single Java identifier character or other wildcard
+ * matching character,
+ * <li>'*' for any number of Java identifier characters or other wildcard
+ * matching characters, and
+ * <li>'**' for any number of Java identifier characters or extended wildcard
+ * matching characters,
+ * <li>'%' for a single special wildcard matching character.
+ * </ul>
+ * The sets of wildcard characters, extended wildcard characters, and special
+ * wildcard characters can be defined by the user.
+ *
+ * @author Eric Lafortune
+ */
+public class BasicMatcher implements StringMatcher
+{
+ private static final String SINGLE_CHARACTER_WILDCARD = "?";
+ private static final String MULTIPLE_CHARACTERS_WILDCARD1 = "*";
+ private static final String MULTIPLE_CHARACTERS_WILDCARD2 = "**";
+ private static final String SPECIAL_CHARACTER_WILDCARD = "%";
+
+ private String[] expressionParts;
+ private char[] wildcardCharacters;
+ private char[] extendedWildcardCharacters;
+ private char[] specialWildcardCharacters;
+
+
+ /**
+ * Creates a new BasicMatcher without extra wildcard matching
+ * characters.
+ * @param regularExpression the regular expression against which strings
+ * will be matched.
+ */
+ public BasicMatcher(String regularExpression)
+ {
+ this(regularExpression, null, null, null);
+ }
+
+
+ /**
+ * Creates a new BasicMatcher.
+ * @param regularExpression the regular expression against which strings
+ * will be matched.
+ * @param wildcardCharacters an optional extra list of wildcard matching
+ * characters.
+ * @param wildcardCharacters an optional extra list of extended wildcard
+ * matching characters.
+ */
+ public BasicMatcher(String regularExpression,
+ char[] wildcardCharacters,
+ char[] extendedWildcardCharacters,
+ char[] specialWildcardCharacters)
+ {
+ this.wildcardCharacters = wildcardCharacters;
+ this.extendedWildcardCharacters = extendedWildcardCharacters;
+ this.specialWildcardCharacters = specialWildcardCharacters;
+
+ // Split the given regular expression into an array of parts: "?",
+ // "*", "**", "%", and simple text strings.
+
+ // A List to collect the subsequent regular expression parts.
+ List expressionPartsList = new ArrayList();
+
+ String wildcard = null;
+ int previousIndex = 0;
+ int index = 0;
+ int regularExpressionLength = regularExpression.length();
+ while (index < regularExpressionLength)
+ {
+ wildcard =
+ regularExpression.regionMatches(index, MULTIPLE_CHARACTERS_WILDCARD2, 0, MULTIPLE_CHARACTERS_WILDCARD2.length()) ? MULTIPLE_CHARACTERS_WILDCARD2 :
+ regularExpression.regionMatches(index, MULTIPLE_CHARACTERS_WILDCARD1, 0, MULTIPLE_CHARACTERS_WILDCARD1.length()) ? MULTIPLE_CHARACTERS_WILDCARD1 :
+ regularExpression.regionMatches(index, SINGLE_CHARACTER_WILDCARD, 0, SINGLE_CHARACTER_WILDCARD.length()) ? SINGLE_CHARACTER_WILDCARD :
+ regularExpression.regionMatches(index, SPECIAL_CHARACTER_WILDCARD, 0, SINGLE_CHARACTER_WILDCARD.length()) ? SPECIAL_CHARACTER_WILDCARD :
+ null;
+ if (wildcard != null)
+ {
+ // Add the simple text string that we've skipped.
+ if (previousIndex < index)
+ {
+ expressionPartsList.add(regularExpression.substring(previousIndex, index));
+ }
+
+ // Add the wildcard that we've found.
+ expressionPartsList.add(wildcard);
+
+ // We'll continue parsing after this wildcard.
+ index += wildcard.length();
+ previousIndex = index;
+ }
+ else
+ {
+ // We'll continue parsing at the next character.
+ index++;
+ }
+ }
+
+ // Add the final simple text string that we've skipped, if any.
+ if (wildcard == null)
+ {
+ expressionPartsList.add(regularExpression.substring(previousIndex));
+ }
+
+ // Copy the List into the array.
+ expressionParts = new String[expressionPartsList.size()];
+ expressionPartsList.toArray(expressionParts);
+ }
+
+
+ // Implementations for StringMatcher.
+
+ public boolean matches(String string)
+ {
+ return matches(string, 0, 0);
+ }
+
+
+ /**
+ * Tries to match the given string, starting at the given index, with the
+ * regular expression parts starting at the given index.
+ */
+ private boolean matches(String string,
+ int stringStartIndex,
+ int expressionIndex)
+ {
+ // Are we out of expression parts?
+ if (expressionIndex == expressionParts.length)
+ {
+ // There's a match, at least if we're at the end of the string as well.
+ return stringStartIndex == string.length();
+ }
+
+ String expressionPart = expressionParts[expressionIndex];
+
+ // Did we get a wildcard of some sort?
+ if (expressionPart.equals(SINGLE_CHARACTER_WILDCARD))
+ {
+ // Do we have any characters left to match?
+ if (stringStartIndex == string.length())
+ {
+ // We've run out of characters.
+ return false;
+ }
+
+ // Make sure we're matching an allowed character and then check if
+ // the rest of the expression parts match.
+ return
+ matchesWildcard(string.charAt(stringStartIndex)) &&
+ matches(string, stringStartIndex + 1, expressionIndex + 1);
+ }
+ else if (expressionPart.equals(MULTIPLE_CHARACTERS_WILDCARD1))
+ {
+ // Try out all possible matches for '*', not matching the package
+ // separator.
+ for (int stringEndIndex = stringStartIndex;
+ stringEndIndex <= string.length();
+ stringEndIndex++)
+ {
+ // Are we matching some characters already?
+ if (stringEndIndex > stringStartIndex)
+ {
+ // Make sure we don't start matching the wrong characters.
+ if (!matchesWildcard(string.charAt(stringEndIndex-1)))
+ {
+ // We can never get a match.
+ return false;
+ }
+ }
+
+ // Continue looking for a match of the next expression part,
+ // starting from the end index.
+ if (matches(string, stringEndIndex, expressionIndex + 1))
+ {
+ return true;
+ }
+ }
+
+ // We could get a match for '*', but not for the rest of the
+ // expression parts.
+ return false;
+ }
+ else if (expressionPart.equals(MULTIPLE_CHARACTERS_WILDCARD2))
+ {
+ // Try out all possible matches for '**'.
+ for (int stringEndIndex = stringStartIndex;
+ stringEndIndex <= string.length();
+ stringEndIndex++)
+ {
+ // Are we matching some characters already?
+ if (stringEndIndex > stringStartIndex)
+ {
+ // Make sure we don't start matching the wrong characters.
+ if (!matchesExtendedWildcard(string.charAt(stringEndIndex-1)))
+ {
+ // We can never get a match.
+ return false;
+ }
+ }
+
+ // Continue looking for a match of the next expression part,
+ // starting from this index.
+ if (matches(string, stringEndIndex, expressionIndex + 1))
+ {
+ return true;
+ }
+ }
+
+ // We could get a match for '**', but not for the rest of the
+ // expression parts.
+ return stringStartIndex == string.length();
+ }
+ else if (expressionPart.equals(SPECIAL_CHARACTER_WILDCARD))
+ {
+ // Do we have any characters left to match?
+ if (stringStartIndex == string.length())
+ {
+ // We've run out of characters.
+ return false;
+ }
+
+ // Make sure we're matching an allowed character and then check if
+ // the rest of the expression parts match.
+ return
+ matchesSpecialWildcard(string.charAt(stringStartIndex)) &&
+ matches(string, stringStartIndex + 1, expressionIndex + 1);
+ }
+ else
+ {
+ // The expression part is a simple text string. Check if it matches,
+ // and if the rest of the expression parts match.
+ int expressionPartLength = expressionPart.length();
+ return
+ string.regionMatches(stringStartIndex, expressionPart, 0, expressionPartLength) &&
+ matches(string, stringStartIndex + expressionPartLength, expressionIndex + 1);
+ }
+ }
+
+
+ /**
+ * Returns whether the given character matches a simple '?' or '*' wildcard.
+ */
+ private boolean matchesWildcard(char character)
+ {
+ if (Character.isJavaIdentifierPart(character))
+ {
+ return true;
+ }
+
+ if (wildcardCharacters != null)
+ {
+ for (int index = 0; index < wildcardCharacters.length; index++)
+ {
+ if (character == wildcardCharacters[index])
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether the given character matches an extended '**' wildcard.
+ */
+ private boolean matchesExtendedWildcard(char character)
+ {
+ if (matchesWildcard(character))
+ {
+ return true;
+ }
+
+ if (extendedWildcardCharacters != null)
+ {
+ for (int index = 0; index < extendedWildcardCharacters.length; index++)
+ {
+ if (character == extendedWildcardCharacters[index])
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns whether the given character matches a special '%' wildcard.
+ */
+ private boolean matchesSpecialWildcard(char character)
+ {
+ if (specialWildcardCharacters != null)
+ {
+ for (int index = 0; index < specialWildcardCharacters.length; index++)
+ {
+ if (character == specialWildcardCharacters[index])
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * A main method for testing string matching.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ System.out.println("Regular expression ["+args[0]+"]");
+ BasicMatcher matcher =
+ new BasicMatcher(args[0], null, new char[] {'/'}, null);
+
+ for (int index = 1; index < args.length; index++)
+ {
+ String string = args[index];
+ System.out.print("String ["+string+"]");
+ System.out.println(" -> match = "+matcher.matches(args[index]));
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/util/ClassNameListMatcher.java b/src/proguard/util/ClassNameListMatcher.java
new file mode 100644
index 0000000..557883a
--- /dev/null
+++ b/src/proguard/util/ClassNameListMatcher.java
@@ -0,0 +1,88 @@
+/* $Id: ClassNameListMatcher.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.util;
+
+import java.util.List;
+
+
+/**
+ * This StringMatcher tests whether internal class names match any
+ * entry in a given list of regular expressions.
+ *
+ * @see BasicListMatcher
+ * @see ClassNameMatcher
+ *
+ * @author Eric Lafortune
+ */
+public class ClassNameListMatcher extends BasicListMatcher
+{
+ /**
+ * Creates a new ClassNameListMatcher.
+ * @param regularExpression the comma-separated list of regular expressions
+ * against which strings will be matched.
+ */
+ public ClassNameListMatcher(String regularExpression)
+ {
+ super(regularExpression);
+ }
+
+
+ /**
+ * Creates a new ClassNameListMatcher.
+ * @param regularExpressionList the list of regular expressions against which
+ * strings will be matched.
+ */
+ public ClassNameListMatcher(List regularExpressionList)
+ {
+ super(regularExpressionList);
+ }
+
+
+ // Overridden method of BasicListMatcher
+
+ protected StringMatcher createBasicMatcher(String regularExpression)
+ {
+ return new ClassNameMatcher(regularExpression);
+ }
+
+
+ /**
+ * A main method for testing file name matching.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ System.out.println("Regular expression ["+args[0]+"]");
+ ClassNameListMatcher matcher = new ClassNameListMatcher(args[0]);
+ for (int index = 1; index < args.length; index++)
+ {
+ String string = args[index];
+ System.out.print("String ["+string+"]");
+ System.out.println(" -> match = "+matcher.matches(args[index]));
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/util/ClassNameMatcher.java b/src/proguard/util/ClassNameMatcher.java
new file mode 100644
index 0000000..f711300
--- /dev/null
+++ b/src/proguard/util/ClassNameMatcher.java
@@ -0,0 +1,93 @@
+/* $Id: ClassNameMatcher.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.util;
+
+import proguard.classfile.ClassConstants;
+
+
+/**
+ * This StringMatcher tests whether internal class names match a
+ * given regular expression.
+ * Supported wildcards are
+ * '?' for a single Java identifier character,
+ * '*' for any number of regular Java identifier characters, and
+ * '**' for any number of regular Java identifier characters or package separator
+ * characters.
+ * '%' for a single internal primitive type character (Z, B, C, S, I, F, J, or D),
+ *
+ * @author Eric Lafortune
+ */
+public class ClassNameMatcher extends BasicMatcher
+{
+ private static final char[] EXTENDED_CLASS_NAME_CHARACTERS = new char[]
+ {
+ ClassConstants.INTERNAL_PACKAGE_SEPARATOR
+ };
+
+ private static final char[] SPECIAL_PRIMITIVE_CHARACTERS = new char[]
+ {
+ ClassConstants.INTERNAL_TYPE_BOOLEAN,
+ ClassConstants.INTERNAL_TYPE_BYTE,
+ ClassConstants.INTERNAL_TYPE_CHAR,
+ ClassConstants.INTERNAL_TYPE_SHORT,
+ ClassConstants.INTERNAL_TYPE_INT,
+ ClassConstants.INTERNAL_TYPE_FLOAT,
+ ClassConstants.INTERNAL_TYPE_LONG,
+ ClassConstants.INTERNAL_TYPE_DOUBLE
+ };
+
+
+ /**
+ * Creates a new ClassNameMatcher.
+ * @param regularExpression the regular expression against which strings
+ * will be matched.
+ */
+ public ClassNameMatcher(String regularExpression)
+ {
+ super(regularExpression,
+ null,
+ EXTENDED_CLASS_NAME_CHARACTERS,
+ SPECIAL_PRIMITIVE_CHARACTERS);
+ }
+
+
+ /**
+ * A main method for testing class name matching.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ System.out.println("Regular expression ["+args[0]+"]");
+ ClassNameMatcher matcher = new ClassNameMatcher(args[0]);
+ for (int index = 1; index < args.length; index++)
+ {
+ String string = args[index];
+ System.out.print("String ["+string+"]");
+ System.out.println(" -> match = "+matcher.matches(args[index]));
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/util/ExtensionMatcher.java b/src/proguard/util/ExtensionMatcher.java
new file mode 100644
index 0000000..84cc834
--- /dev/null
+++ b/src/proguard/util/ExtensionMatcher.java
@@ -0,0 +1,52 @@
+/* $Id: ExtensionMatcher.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.util;
+
+import java.util.*;
+
+
+/**
+ * This StringMatcher tests whether strings end in a given extension.
+ *
+ * @author Eric Lafortune
+ */
+public class ExtensionMatcher implements StringMatcher
+{
+ private String extension;
+
+
+ /**
+ * Creates a new StringMatcher.
+ * @param extension the extension against which strings will be matched.
+ */
+ public ExtensionMatcher(String extension)
+ {
+ this.extension = extension;
+ }
+
+
+ // Implementations for StringMatcher.
+
+ public boolean matches(String string)
+ {
+ return string.endsWith(extension);
+ }
+}
diff --git a/src/proguard/util/FileNameListMatcher.java b/src/proguard/util/FileNameListMatcher.java
new file mode 100644
index 0000000..765d100
--- /dev/null
+++ b/src/proguard/util/FileNameListMatcher.java
@@ -0,0 +1,88 @@
+/* $Id: FileNameListMatcher.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.util;
+
+import java.util.List;
+
+
+/**
+ * This StringMatcher tests whether file names match any entry in a
+ * given list of regular expressions.
+ *
+ * @see BasicListMatcher
+ * @see FileNameMatcher
+ *
+ * @author Eric Lafortune
+ */
+public class FileNameListMatcher extends BasicListMatcher
+{
+ /**
+ * Creates a new FileNameListMatcher.
+ * @param regularExpression the comma-separated list of regular expressions
+ * against which strings will be matched.
+ */
+ public FileNameListMatcher(String regularExpression)
+ {
+ super(regularExpression);
+ }
+
+
+ /**
+ * Creates a new FileNameListMatcher.
+ * @param regularExpressionList the list of regular expressions against which
+ * strings will be matched.
+ */
+ public FileNameListMatcher(List regularExpressionList)
+ {
+ super(regularExpressionList);
+ }
+
+
+ // Overridden method of BasicListMatcher
+
+ protected StringMatcher createBasicMatcher(String regularExpression)
+ {
+ return new FileNameMatcher(regularExpression);
+ }
+
+
+ /**
+ * A main method for testing file name matching.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ System.out.println("Regular expression ["+args[0]+"]");
+ FileNameListMatcher matcher = new FileNameListMatcher(args[0]);
+ for (int index = 1; index < args.length; index++)
+ {
+ String string = args[index];
+ System.out.print("String ["+string+"]");
+ System.out.println(" -> match = "+matcher.matches(args[index]));
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/util/FileNameMatcher.java b/src/proguard/util/FileNameMatcher.java
new file mode 100644
index 0000000..719c71f
--- /dev/null
+++ b/src/proguard/util/FileNameMatcher.java
@@ -0,0 +1,89 @@
+/* $Id: FileNameMatcher.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.util;
+
+import proguard.classfile.ClassConstants;
+
+import java.io.*;
+
+
+/**
+ * This StringMatcher tests whether file names match a given regular
+ * expression.
+ * Supported wildcards are
+ * '?' for a single regular file name character,
+ * '*' for any number of regular file name characters, and
+ * '**' for any number of regular file name characters or directory separator
+ * characters (always including '/').
+ *
+ * @author Eric Lafortune
+ */
+public class FileNameMatcher extends BasicMatcher
+{
+ private static final char[] FILE_NAME_CHARACTERS = new char[]
+ {
+ ' ',
+ '.'
+ };
+
+ private static final char[] EXTENDED_FILE_NAME_CHARACTERS = new char[]
+ {
+ ClassConstants.INTERNAL_PACKAGE_SEPARATOR,
+ File.separatorChar
+ };
+
+
+ /**
+ * Creates a new FileNameMatcher.
+ * @param regularExpression the regular expression against which strings
+ * will be matched.
+ */
+ public FileNameMatcher(String regularExpression)
+ {
+ super(regularExpression,
+ FILE_NAME_CHARACTERS,
+ EXTENDED_FILE_NAME_CHARACTERS,
+ null);
+ }
+
+
+ /**
+ * A main method for testing file name matching.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ System.out.println("Regular expression ["+args[0]+"]");
+ FileNameMatcher matcher = new FileNameMatcher(args[0]);
+ for (int index = 1; index < args.length; index++)
+ {
+ String string = args[index];
+ System.out.print("String ["+string+"]");
+ System.out.println(" -> match = "+matcher.matches(args[index]));
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/proguard/util/ListUtil.java b/src/proguard/util/ListUtil.java
new file mode 100644
index 0000000..c0f7721
--- /dev/null
+++ b/src/proguard/util/ListUtil.java
@@ -0,0 +1,87 @@
+/* $Id: ListUtil.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.util;
+
+import java.util.*;
+
+
+/**
+ * This class provides some utility methods for working with
+ * <code>java.util.List</code> objects.
+ *
+ * @author Eric Lafortune
+ */
+public class ListUtil
+{
+ /**
+ * Creates a comma-separated String from the given List of String objects.
+ */
+ public static String commaSeparatedString(List list)
+ {
+ if (list == null)
+ {
+ return null;
+ }
+
+ StringBuffer buffer = new StringBuffer();
+
+ for (int index = 0; index < list.size(); index++)
+ {
+ if (index > 0)
+ {
+ buffer.append(',');
+ }
+
+ buffer.append(list.get(index));
+ }
+
+ return buffer.toString();
+ }
+
+
+ /**
+ * Creates a List of String objects from the given comma-separated String.
+ */
+ public static List commaSeparatedList(String string)
+ {
+ if (string == null)
+ {
+ return null;
+ }
+
+ List list = new ArrayList();
+ int index = 0;
+ while (index < string.length())
+ {
+ int nextIndex = string.indexOf(',', index);
+ if (nextIndex < 0)
+ {
+ nextIndex = string.length();
+ }
+
+ list.add(string.substring(index, nextIndex).trim());
+
+ index = nextIndex + 1;
+ }
+
+ return list;
+ }
+}
diff --git a/src/proguard/util/StringMatcher.java b/src/proguard/util/StringMatcher.java
new file mode 100644
index 0000000..92dd665
--- /dev/null
+++ b/src/proguard/util/StringMatcher.java
@@ -0,0 +1,38 @@
+/* $Id: StringMatcher.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.util;
+
+
+/**
+ * This interface provides a method to determine whether strings match a given
+ * criterion, which is specified by the implementation.
+ *
+ * @author Eric Lafortune
+ */
+public interface StringMatcher
+{
+ /**
+ * Checks whether the given string matches.
+ * @param string the string to match.
+ * @return a boolean indicating whether the string matches the criterion.
+ */
+ public boolean matches(String string);
+}
diff --git a/src/proguard/util/package.html b/src/proguard/util/package.html
new file mode 100644
index 0000000..cb14fdc
--- /dev/null
+++ b/src/proguard/util/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains utility classes for regular expression matching,...
+</body>
diff --git a/src/proguard/wtk/ProGuardObfuscator.java b/src/proguard/wtk/ProGuardObfuscator.java
new file mode 100644
index 0000000..c406805
--- /dev/null
+++ b/src/proguard/wtk/ProGuardObfuscator.java
@@ -0,0 +1,138 @@
+/* $Id: ProGuardObfuscator.java,v 1.12 2004/08/15 12:39:30 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.wtk;
+
+import com.sun.kvem.environment.*;
+import proguard.*;
+import proguard.classfile.*;
+
+import java.io.*;
+import java.util.*;
+
+
+/**
+ * ProGuard plug-in for the J2ME Wireless Toolkit.
+ * <p>
+ * In order to integrate this plug-in in the toolkit, you'll have to put the
+ * following lines in the file
+ * {j2mewtk.dir}<code>/wtklib/Linux/ktools.properties</code> or
+ * {j2mewtk.dir}<code>\wtklib\Windows\ktools.properties</code> (whichever is
+ * applicable).
+ * <p>
+ * <pre>
+ * obfuscator.runner.class.name: proguard.wtk.ProGuardObfuscator
+ * obfuscator.runner.classpath: /usr/local/java/proguard1.6/lib/proguard.jar
+ * </pre>
+ * Please make sure the class path is set correctly for your system.
+ *
+ * @author Eric Lafortune
+ */
+public class ProGuardObfuscator implements Obfuscator
+{
+ private static final String DEFAULT_CONFIGURATION = "default.pro";
+
+
+ // Implementations for Obfuscator.
+
+ public void createScriptFile(File jadFile,
+ File projectDir)
+ {
+ // We don't really need to create a script file;
+ // we'll just fill out all options in the run method.
+ }
+
+
+ public void run(File obfuscatedJarFile,
+ String wtkBinDir,
+ String wtkLibDir,
+ String jarFileName,
+ String projectDirName,
+ String classPath,
+ String emptyAPI)
+ throws IOException
+ {
+ try
+ {
+ // Create the ProGuard configuration.
+ Configuration configuration = new Configuration();
+
+ // Parse the default configuration file.
+ ConfigurationParser parser = new ConfigurationParser(this.getClass().getResource(DEFAULT_CONFIGURATION));
+ parser.parse(configuration);
+
+ // Fill out the library class path.
+ configuration.libraryJars = classPath(classPath);
+
+ // Fill out the program class path (input and output).
+ configuration.programJars = new ClassPath();
+ configuration.programJars.add(new ClassPathEntry(jarFileName, false));
+ configuration.programJars.add(new ClassPathEntry(obfuscatedJarFile.getPath(), true));
+
+ // The preverify tool seems to unpack the resulting class files,
+ // so we must not use mixed-case class names on Windows.
+ configuration.useMixedCaseClassNames =
+ !System.getProperty("os.name").regionMatches(true, 0, "windows", 0, 7);
+
+ // Run ProGuard with these options.
+ ProGuard proGuard = new ProGuard(configuration);
+ proGuard.execute();
+
+ }
+ catch (ParseException ex)
+ {
+ throw new IOException(ex.getMessage());
+ }
+ }
+
+
+ /**
+ * Converts the given class path String into a ClassPath object.
+ */
+ private ClassPath classPath(String classPathString)
+ {
+ ClassPath classPath = new ClassPath();
+
+ String separator = System.getProperty("path.separator");
+
+ int index = 0;
+ while (index < classPathString.length())
+ {
+ // Find the next separator, or the end of the String.
+ int next_index = classPathString.indexOf(separator, index);
+ if (next_index < 0)
+ {
+ next_index = classPathString.length();
+ }
+
+ // Create and add the found class path entry.
+ ClassPathEntry classPathEntry =
+ new ClassPathEntry(classPathString.substring(index, next_index),
+ false);
+
+ classPath.add(classPathEntry);
+
+ // Continue after the separator.
+ index = next_index + 1;
+ }
+
+ return classPath;
+ }
+}
diff --git a/src/proguard/wtk/default.pro b/src/proguard/wtk/default.pro
new file mode 100644
index 0000000..d5e068c
--- /dev/null
+++ b/src/proguard/wtk/default.pro
@@ -0,0 +1,112 @@
+-dontnote
+-overloadaggressively
+-defaultpackage ''
+-allowaccessmodification
+
+# Keep all extensions of javax.microedition.midlet.MIDlet.
+-keep public class * extends javax.microedition.midlet.MIDlet
+
+# Keep all native class/method names.
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# Remove all invocations of System methods without side effects
+# whose return values are not used.
+-assumenosideeffects public class java.lang.System {
+ public static native long currentTimeMillis();
+ static java.lang.Class getCallerClass();
+ public static native int identityHashCode(java.lang.Object);
+ public static java.lang.SecurityManager getSecurityManager();
+ public static java.util.Properties getProperties();
+ public static java.lang.String getProperty(java.lang.String);
+ public static java.lang.String getenv(java.lang.String);
+ public static native java.lang.String mapLibraryName(java.lang.String);
+ public static java.lang.String getProperty(java.lang.String,java.lang.String);
+}
+
+# Remove all invocations of String methods without side effects
+# whose return values are not used.
+-assumenosideeffects public class java.lang.String {
+ public java.lang.String();
+ public java.lang.String(byte[]);
+ public java.lang.String(byte[],int);
+ public java.lang.String(byte[],int,int);
+ public java.lang.String(byte[],int,int,int);
+ public java.lang.String(byte[],int,int,java.lang.String);
+ public java.lang.String(byte[],java.lang.String);
+ public java.lang.String(char[]);
+ public java.lang.String(char[],int,int);
+ public java.lang.String(java.lang.String);
+ public java.lang.String(java.lang.StringBuffer);
+ public static java.lang.String copyValueOf(char[]);
+ public static java.lang.String copyValueOf(char[],int,int);
+ public static java.lang.String valueOf(boolean);
+ public static java.lang.String valueOf(char);
+ public static java.lang.String valueOf(char[]);
+ public static java.lang.String valueOf(char[],int,int);
+ public static java.lang.String valueOf(double);
+ public static java.lang.String valueOf(float);
+ public static java.lang.String valueOf(int);
+ public static java.lang.String valueOf(java.lang.Object);
+ public static java.lang.String valueOf(long);
+ public boolean contentEquals(java.lang.StringBuffer);
+ public boolean endsWith(java.lang.String);
+ public boolean equalsIgnoreCase(java.lang.String);
+ public boolean equals(java.lang.Object);
+ public boolean matches(java.lang.String);
+ public boolean regionMatches(boolean,int,java.lang.String,int,int);
+ public boolean regionMatches(int,java.lang.String,int,int);
+ public boolean startsWith(java.lang.String);
+ public boolean startsWith(java.lang.String,int);
+ public byte[] getBytes();
+ public byte[] getBytes(java.lang.String);
+ public char charAt(int);
+ public char[] toCharArray();
+ public int compareToIgnoreCase(java.lang.String);
+ public int compareTo(java.lang.Object);
+ public int compareTo(java.lang.String);
+ public int hashCode();
+ public int indexOf(int);
+ public int indexOf(int,int);
+ public int indexOf(java.lang.String);
+ public int indexOf(java.lang.String,int);
+ public int lastIndexOf(int);
+ public int lastIndexOf(int,int);
+ public int lastIndexOf(java.lang.String);
+ public int lastIndexOf(java.lang.String,int);
+ public int length();
+ public java.lang.CharSequence subSequence(int,int);
+ public java.lang.String concat(java.lang.String);
+ public java.lang.String replaceAll(java.lang.String,java.lang.String);
+ public java.lang.String replace(char,char);
+ public java.lang.String replaceFirst(java.lang.String,java.lang.String);
+ public java.lang.String[] split(java.lang.String);
+ public java.lang.String[] split(java.lang.String,int);
+ public java.lang.String substring(int);
+ public java.lang.String substring(int,int);
+ public java.lang.String toLowerCase();
+ public java.lang.String toLowerCase(java.util.Locale);
+ public java.lang.String toString();
+ public java.lang.String toUpperCase();
+ public java.lang.String toUpperCase(java.util.Locale);
+ public java.lang.String trim();
+}
+
+
+# Remove all invocations of StringBuffer methods without side effects
+# whose return values are not used.
+-assumenosideeffects public class java.lang.StringBuffer {
+ public java.lang.StringBuffer();
+ public java.lang.StringBuffer(int);
+ public java.lang.StringBuffer(java.lang.String);
+ public java.lang.String toString();
+ public char charAt(int);
+ public int capacity();
+ public int indexOf(java.lang.String,int);
+ public int lastIndexOf(java.lang.String);
+ public int lastIndexOf(java.lang.String,int);
+ public int length();
+ public java.lang.String substring(int);
+ public java.lang.String substring(int,int);
+}
diff --git a/src/proguard/wtk/package.html b/src/proguard/wtk/package.html
new file mode 100644
index 0000000..6efc644
--- /dev/null
+++ b/src/proguard/wtk/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains the J2ME Wireless Toolkit plug-in for ProGuard.
+</body>
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/proguard.git
More information about the pkg-java-commits
mailing list