summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcin Kosiba <mkosiba@google.com>2014-06-17 09:56:21 +0100
committerMarcin Kosiba <mkosiba@google.com>2014-06-20 11:55:22 +0100
commitab61347a2cb3254688c42c993278cefd43e5d99d (patch)
treede9bb96cdb2bc7a710c8222edcdd3e3a33e7086e
parentfe7bad2c42f39829e8d4fd990ac1da776bcaeee2 (diff)
downloadandroid_external_jarjar-ab61347a2cb3254688c42c993278cefd43e5d99d.tar.gz
android_external_jarjar-ab61347a2cb3254688c42c993278cefd43e5d99d.tar.bz2
android_external_jarjar-ab61347a2cb3254688c42c993278cefd43e5d99d.zip
Add JarJar 1.4
Change-Id: Iadcec27828223189f579b70d050cd7246cb488c2
-rw-r--r--Android.mk44
-rw-r--r--COPYING202
-rw-r--r--LICENSE.txt202
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--build.xml271
-rw-r--r--lib/apache-ant-1.9.4.jarbin0 -> 2019274 bytes
-rw-r--r--lib/asm-4.0.jarbin0 -> 46022 bytes
-rw-r--r--lib/asm-commons-4.0.jarbin0 -> 37776 bytes
-rw-r--r--lib/maven-plugin-api.jarbin0 -> 8331 bytes
-rw-r--r--manifest.txt1
-rw-r--r--maven/plugin.xml63
-rw-r--r--maven/pom.properties3
-rw-r--r--maven/pom.xml17
-rw-r--r--res/com/tonicsystems/jarjar/help.txt75
-rw-r--r--src/Jarjar.iml23
-rw-r--r--src/main/com/tonicsystems/jarjar/AbstractDepHandler.java56
-rw-r--r--src/main/com/tonicsystems/jarjar/DepFind.java80
-rw-r--r--src/main/com/tonicsystems/jarjar/DepFindVisitor.java71
-rw-r--r--src/main/com/tonicsystems/jarjar/DepHandler.java29
-rw-r--r--src/main/com/tonicsystems/jarjar/EmptyClassVisitor.java50
-rw-r--r--src/main/com/tonicsystems/jarjar/ExcludeProcessor.java40
-rw-r--r--src/main/com/tonicsystems/jarjar/JarJarMojo.java53
-rw-r--r--src/main/com/tonicsystems/jarjar/JarJarTask.java61
-rw-r--r--src/main/com/tonicsystems/jarjar/Keep.java21
-rw-r--r--src/main/com/tonicsystems/jarjar/KeepProcessor.java112
-rw-r--r--src/main/com/tonicsystems/jarjar/Main.java97
-rw-r--r--src/main/com/tonicsystems/jarjar/MainProcessor.java106
-rw-r--r--src/main/com/tonicsystems/jarjar/MainUtil.java86
-rw-r--r--src/main/com/tonicsystems/jarjar/ManifestProcessor.java38
-rw-r--r--src/main/com/tonicsystems/jarjar/PackageRemapper.java128
-rw-r--r--src/main/com/tonicsystems/jarjar/PathClass.java40
-rw-r--r--src/main/com/tonicsystems/jarjar/PatternElement.java44
-rw-r--r--src/main/com/tonicsystems/jarjar/ResourceProcessor.java37
-rw-r--r--src/main/com/tonicsystems/jarjar/Rule.java30
-rw-r--r--src/main/com/tonicsystems/jarjar/RulesFileParser.java81
-rw-r--r--src/main/com/tonicsystems/jarjar/StringDumper.java96
-rw-r--r--src/main/com/tonicsystems/jarjar/StringReader.java100
-rw-r--r--src/main/com/tonicsystems/jarjar/TextDepHandler.java34
-rw-r--r--src/main/com/tonicsystems/jarjar/Wildcard.java143
-rw-r--r--src/main/com/tonicsystems/jarjar/Zap.java21
-rw-r--r--src/main/com/tonicsystems/jarjar/ZapProcessor.java47
-rw-r--r--src/main/com/tonicsystems/jarjar/util/AntJarProcessor.java107
-rw-r--r--src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java186
-rw-r--r--src/main/com/tonicsystems/jarjar/util/ClassPathEntry.java26
-rw-r--r--src/main/com/tonicsystems/jarjar/util/ClassPathIterator.java234
-rw-r--r--src/main/com/tonicsystems/jarjar/util/EntryStruct.java27
-rw-r--r--src/main/com/tonicsystems/jarjar/util/GetNameClassWriter.java43
-rw-r--r--src/main/com/tonicsystems/jarjar/util/IoUtil.java131
-rw-r--r--src/main/com/tonicsystems/jarjar/util/JarProcessor.java35
-rw-r--r--src/main/com/tonicsystems/jarjar/util/JarProcessorChain.java48
-rw-r--r--src/main/com/tonicsystems/jarjar/util/JarTransformer.java47
-rw-r--r--src/main/com/tonicsystems/jarjar/util/JarTransformerChain.java36
-rw-r--r--src/main/com/tonicsystems/jarjar/util/RemappingClassTransformer.java34
-rw-r--r--src/main/com/tonicsystems/jarjar/util/RuntimeIOException.java28
-rw-r--r--src/main/com/tonicsystems/jarjar/util/StandaloneJarProcessor.java71
-rw-r--r--src/test/Generics.classbin0 -> 575 bytes
-rw-r--r--src/test/com/tonicsystems/jarjar/GenericsTest.java44
-rw-r--r--src/test/com/tonicsystems/jarjar/PackageRemapperTest.java59
-rw-r--r--src/test/com/tonicsystems/jarjar/RulesFileParserTest.java36
-rw-r--r--src/test/com/tonicsystems/jarjar/WildcardTest.java48
-rw-r--r--src/test/com/tonicsystems/jarjar/example/Example.java5
-rw-r--r--src/test/enumtest.jarbin0 -> 1324 bytes
62 files changed, 3847 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..e7656fd
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,44 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main)
+
+LOCAL_JAVA_LIBRARIES := \
+ asm-tools \
+ asm-commons \
+ maven-plugin-api \
+ apache-ant
+
+LOCAL_MODULE := jarjar
+LOCAL_MODULE_TAGS := optional
+LOCAL_JAR_MANIFEST := manifest.txt
+LOCAL_JAVA_RESOURCE_DIRS := res
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+##################################################
+include $(CLEAR_VARS)
+
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ asm-tools:lib/asm-4.0$(COMMON_JAVA_PACKAGE_SUFFIX) \
+ asm-commons:lib/asm-commons-4.0$(COMMON_JAVA_PACKAGE_SUFFIX) \
+ maven-plugin-api:lib/maven-plugin-api$(COMMON_JAVA_PACKAGE_SUFFIX) \
+ apache-ant:lib/apache-ant-1.9.4$(COMMON_JAVA_PACKAGE_SUFFIX)
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_PREBUILT)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..d0d73f5
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,271 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<project name="Jar Jar Links" default="jar" xmlns:artifact="antlib:org.apache.maven.artifact.ant">
+ <property file="${user.home}/build.properties" />
+ <property file="build.properties" />
+
+ <property name="javadoc.access" value="public"/>
+
+ <property name="compile.source" value="1.5"/>
+ <property name="compile.target" value="1.5"/>
+ <property name="compile.bootclasspath" value=""/>
+ <property name="compile.extdirs" value=""/>
+
+ <property name="compile.debug" value="true"/>
+ <property name="compile.deprecation" value="false"/>
+ <property name="compile.optimize" value="false"/>
+
+ <property name="src" location="src" />
+ <property name="build" location="build" />
+ <property name="dist" location="dist" />
+
+ <!-- define Maven coordinates -->
+ <property name="groupId" value="com.googlecode.jarjar" />
+ <property name="artifactId" value="jarjar" />
+ <property name="version" value="1.4"/>
+
+ <!-- define artifacts' name, which follows the convention of Maven -->
+ <property name="maven-jar" value="${dist}/${artifactId}-${version}.jar" />
+ <property name="maven-javadoc-jar" value="${dist}/${artifactId}-${version}-javadoc.jar" />
+ <property name="maven-sources-jar" value="${dist}/${artifactId}-${version}-sources.jar" />
+
+ <!-- defined maven snapshots and staging repository id and url -->
+ <property name="maven-snapshots-repository-id" value="sonatype-nexus-snapshots" />
+ <property name="maven-snapshots-repository-url" value="https://oss.sonatype.org/content/repositories/snapshots/" />
+ <property name="maven-staging-repository-id" value="sonatype-nexus-staging" />
+ <property name="maven-staging-repository-url" value="https://oss.sonatype.org/service/local/staging/deploy/maven2/" />
+
+
+ <property name="jarfile" value="dist/jarjar-${version}.jar"/>
+ <property name="jarfile.util" value="dist/jarjar-util-${version}.jar"/>
+ <property name="jarfile.mojo" value="dist/jarjar-plugin-${version}.jar"/>
+
+ <property name="test.jar" value="build/rejar.jar"/>
+
+ <target name="init">
+ <echo>bootclasspath ${compile.bootclasspath}</echo>
+ <tstamp/>
+ <path id="path.build">
+ <fileset dir="lib" includes="**/*.jar"/>
+ </path>
+ <path id="path.run">
+ <path refid="path.build"/>
+ <pathelement path="build/main"/>
+ </path>
+ <path id="path.test">
+ <path refid="path.run"/>
+ <pathelement path="build/test"/>
+ </path>
+ </target>
+
+ <macrodef name="compile">
+ <attribute name="module"/>
+ <attribute name="refid"/>
+ <attribute name="bootclasspath" default=""/>
+ <sequential>
+ <mkdir dir="build/@{module}"/>
+ <copy todir="build/@{module}">
+ <fileset dir="src/@{module}" excludes="**/*.java"/>
+ </copy>
+ <javac includeantruntime="true" srcdir="src/@{module}" destdir="build/@{module}"
+ source="${compile.source}"
+ target="${compile.target}" bootclasspath="@{bootclasspath}" extdirs="${compile.extdirs}"
+ debug="${compile.debug}" optimize="${compile.optimize}" deprecation="${compile.deprecation}">
+ <classpath refid="@{refid}"/>
+ <compilerarg value="-Xlint"/>
+ </javac>
+ </sequential>
+ </macrodef>
+
+ <target name="compile" depends="init" description="Compile">
+ <compile module="main" refid="path.build" bootclasspath="${compile.bootclasspath}"/>
+ <taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpathref="path.run"/>
+ </target>
+
+ <target name="compile-test" depends="compile" description="Compile tests">
+ <compile module="test" refid="path.run"/>
+ </target>
+
+ <target name="clean" description="Clean">
+ <delete dir="build"/>
+ <delete dir="dist"/>
+ <delete dir="dist/javadoc"/>
+ </target>
+
+ <target name="jar" depends="compile" description="Create Jar">
+ <mkdir dir="dist"/>
+ <jarjar jarfile="${jarfile}">
+ <fileset dir="build/main"/>
+ <zipfileset src="lib/asm-4.0.jar"/>
+ <zipfileset src="lib/asm-commons-4.0.jar">
+ <include name="org/objectweb/asm/commons/Remap*.class"/>
+ <include name="org/objectweb/asm/commons/LocalVariablesSorter.class"/>
+ </zipfileset>
+ <keep pattern="com.tonicsystems.jarjar.Main"/>
+ <keep pattern="com.tonicsystems.jarjar.JarJarTask"/>
+ <rule pattern="com.tonicsystems.jarjar.util.**" result="com.tonicsystems.jarjar.ext_util.@1"/>
+ <rule pattern="org.objectweb.asm.**" result="com.tonicsystems.jarjar.asm.@1"/>
+ <manifest>
+ <attribute name="Main-Class" value="com.tonicsystems.jarjar.Main"/>
+ <attribute name="Implementation-Version" value="${version}"/>
+ </manifest>
+ </jarjar>
+ </target>
+
+ <target name="jar-util" depends="compile" description="Create utility Jar">
+ <mkdir dir="dist"/>
+ <jar jarfile="${jarfile.util}">
+ <fileset dir="build/main" includes="com/tonicsystems/jarjar/util/**"/>
+ </jar>
+ </target>
+
+ <target name="dist" depends="jar,dist-src,javadoc" description="generate the distribution">
+ <copy file="${dist}/jarjar-src-${version}.zip" tofile="${maven-sources-jar}" />
+ <jar jarfile="${maven-javadoc-jar}">
+ <fileset dir="${dist}/javadoc" />
+ </jar>
+ </target>
+
+ <!-- before this, update project version (both build.xml and pom.xml) from SNAPSHOT to RELEASE -->
+ <target name="stage" depends="dist" description="deploy release version to Maven staging repository">
+ <!-- sign and deploy the main artifact -->
+ <artifact:mvn>
+ <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
+ <arg value="-Durl=${maven-staging-repository-url}" />
+ <arg value="-DrepositoryId=${maven-staging-repository-id}" />
+ <arg value="-DpomFile=pom.xml" />
+ <arg value="-Dfile=${maven-jar}" />
+ <arg value="-Pgpg" />
+ </artifact:mvn>
+
+ <!-- sign and deploy the sources artifact -->
+ <artifact:mvn>
+ <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
+ <arg value="-Durl=${maven-staging-repository-url}" />
+ <arg value="-DrepositoryId=${maven-staging-repository-id}" />
+ <arg value="-DpomFile=pom.xml" />
+ <arg value="-Dfile=${maven-sources-jar}" />
+ <arg value="-Dclassifier=sources" />
+ <arg value="-Pgpg" />
+ </artifact:mvn>
+
+ <!-- sign and deploy the javadoc artifact -->
+ <artifact:mvn>
+ <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
+ <arg value="-Durl=${maven-staging-repository-url}" />
+ <arg value="-DrepositoryId=${maven-staging-repository-id}" />
+ <arg value="-DpomFile=pom.xml" />
+ <arg value="-Dfile=${maven-javadoc-jar}" />
+ <arg value="-Dclassifier=javadoc" />
+ <arg value="-Pgpg" />
+ </artifact:mvn>
+ </target>
+
+ <target name="dist-src" depends="compile" description="Create source distribution">
+ <mkdir dir="${dist}"/>
+ <zip destfile="${dist}/jarjar-src-${version}.zip">
+ <zipfileset dir="src" excludes="**/*.save" prefix="jarjar-${version}/src"/>
+ <zipfileset dir="lib" prefix="jarjar-${version}/lib"/>
+ <zipfileset dir="maven" prefix="jarjar-${version}/maven"/>
+ <zipfileset dir="." includes="build.xml,COPYING" prefix="jarjar-${version}"/>
+ </zip>
+ </target>
+
+ <target name="mojo" depends="jar" description="Create Maven plugin">
+ <mkdir dir="dist"/>
+ <copy todir="dist/maven">
+ <fileset dir="maven"/>
+ <filterset>
+ <filter token="VERSION" value="${version}"/>
+ </filterset>
+ </copy>
+ <jar jarfile="${jarfile.mojo}">
+ <zipfileset src="${jarfile}"/>
+ <zipfileset dir="dist/maven" prefix="META-INF/maven" includes="plugin.xml"/>
+ <zipfileset
+ dir="dist/maven"
+ prefix="META-INF/maven/com.tonicsystems.jarjar/jarjar-plugin"
+ includes="pom.xml,pom.properties"/>
+ </jar>
+ </target>
+
+ <target name="test" depends="junit,test-rejar,test-manifest,test-enum" description="Run tests"/>
+
+ <target name="junit" depends="compile-test">
+ <junit haltonfailure="on">
+ <!-- <jvmarg value="-Xint"/> -->
+ <!-- <jvmarg value="-Xprof"/> -->
+ <!-- <jvmarg value="-server"/> -->
+ <formatter type="plain" usefile="false"/>
+ <classpath refid="path.test"/>
+ <batchtest>
+ <fileset dir="src/test" includes="**/*Test.java"/>
+ </batchtest>
+ </junit>
+ </target>
+
+ <target name="test-rejar" depends="jar">
+ <taskdef name="jarjar2" classname="com.tonicsystems.jarjar.JarJarTask" classpath="${jarfile}"/>
+ <delete file="${test.jar}"/>
+ <jarjar2 jarfile="${test.jar}">
+ <fileset dir="build/main"/>
+ <zipfileset src="lib/asm-4.0.jar"/>
+ <zipfileset src="lib/asm-commons-4.0.jar"/>
+ <rule pattern="org.objectweb.asm.**" result="com.tonicsystems.jarjar.asm.@1"/>
+ </jarjar2>
+ <delete file="${test.jar}"/>
+ </target>
+
+ <target name="test-enum" depends="compile">
+ <delete file="build/enumtest.jar"/>
+ <jarjar jarfile="build/enumtest.jar" verbose="true">
+ <zipfileset src="src/test/enumtest.jar"/>
+ <rule pattern="foo.**" result="bar.@1"/>
+ </jarjar>
+ <java classpath="build/enumtest.jar" classname="bar.EnumTest"/>
+ <!-- TODO: check output -->
+ <!-- <delete file="build/enumtest.jar"/> -->
+ </target>
+
+ <target name="test-manifest" depends="compile">
+ <delete>
+ <fileset dir="build" includes="manifest*.jar"/>
+ </delete>
+ <jar jarfile="build/manifest1.jar">
+ <manifest>
+ <attribute name="Built-By" value="Chris"/>
+ <attribute name="Specification-Title" value="Example"/>
+ </manifest>
+ </jar>
+ <jar jarfile="build/manifest2.jar">
+ <manifest>
+ <attribute name="Built-By" value="CJN"/>
+ <attribute name="Implementation-Title" value="common"/>
+ </manifest>
+ </jar>
+ <jar jarfile="build/manifest3.jar" filesetmanifest="merge">
+ <zipfileset src="build/manifest1.jar"/>
+ <zipfileset src="build/manifest2.jar"/>
+ </jar>
+ <jarjar jarfile="build/manifest4.jar" filesetmanifest="merge">
+ <zipfileset src="build/manifest1.jar"/>
+ <zipfileset src="build/manifest2.jar"/>
+ </jarjar>
+ <!-- TODO: check manifest contents here -->
+ </target>
+
+ <!-- TODO: reference ant javadocs -->
+ <target name="javadoc" depends="compile" description="Generate the javadoc">
+ <mkdir dir="dist/javadoc"/>
+ <javadoc
+ sourcepath="${src}/main"
+ destdir="${dist}/javadoc"
+ access="${javadoc.access}"
+ failonerror="true"
+ packagenames="com.tonicsystems.jarjar.*"
+ classpathref="path.run"
+ Author="true"
+ Version="true"
+ Use="true"
+ />
+ </target>
+</project>
diff --git a/lib/apache-ant-1.9.4.jar b/lib/apache-ant-1.9.4.jar
new file mode 100644
index 0000000..24641e7
--- /dev/null
+++ b/lib/apache-ant-1.9.4.jar
Binary files differ
diff --git a/lib/asm-4.0.jar b/lib/asm-4.0.jar
new file mode 100644
index 0000000..cca0d9c
--- /dev/null
+++ b/lib/asm-4.0.jar
Binary files differ
diff --git a/lib/asm-commons-4.0.jar b/lib/asm-commons-4.0.jar
new file mode 100644
index 0000000..169400e
--- /dev/null
+++ b/lib/asm-commons-4.0.jar
Binary files differ
diff --git a/lib/maven-plugin-api.jar b/lib/maven-plugin-api.jar
new file mode 100644
index 0000000..379b2c8
--- /dev/null
+++ b/lib/maven-plugin-api.jar
Binary files differ
diff --git a/manifest.txt b/manifest.txt
new file mode 100644
index 0000000..63c68e0
--- /dev/null
+++ b/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.tonicsystems.jarjar.Main
diff --git a/maven/plugin.xml b/maven/plugin.xml
new file mode 100644
index 0000000..9f59300
--- /dev/null
+++ b/maven/plugin.xml
@@ -0,0 +1,63 @@
+<plugin>
+ <description></description>
+ <groupId>com.tonicsystems.jarjar</groupId>
+ <artifactId>jarjar-plugin</artifactId>
+ <version>@VERSION@</version>
+ <goalPrefix>jarjar</goalPrefix>
+ <isolatedRealm>false</isolatedRealm>
+ <inheritedByDefault>true</inheritedByDefault>
+ <mojos>
+ <mojo>
+ <goal>jarjar</goal>
+ <description>Repackage class files into a new namespace.</description>
+ <requiresDirectInvocation>false</requiresDirectInvocation>
+ <requiresProject>true</requiresProject>
+ <requiresReports>false</requiresReports>
+ <aggregator>false</aggregator>
+ <requiresOnline>false</requiresOnline>
+ <inheritedByDefault>true</inheritedByDefault>
+ <implementation>com.tonicsystems.jarjar.JarJarMojo</implementation>
+ <language>java</language>
+ <instantiationStrategy>per-lookup</instantiationStrategy>
+ <executionStrategy>once-per-session</executionStrategy>
+ <parameters>
+ <parameter>
+ <name>fromJar</name>
+ <type>java.io.File</type>
+ <required>true</required>
+ <editable>true</editable>
+ <description>Jar file to process</description>
+ </parameter>
+ <parameter>
+ <name>toJar</name>
+ <type>java.io.File</type>
+ <required>true</required>
+ <editable>true</editable>
+ <description>Output jar file</description>
+ </parameter>
+ <parameter>
+ <name>rules</name>
+ <type>java.lang.String</type>
+ <required>false</required>
+ <editable>true</editable>
+ <description>External rules file</description>
+ </parameter>
+ <parameter>
+ <name>rulesFile</name>
+ <type>java.io.File</type>
+ <required>false</required>
+ <editable>true</editable>
+ <description>Rules</description>
+ </parameter>
+ <parameter>
+ <name>verbose</name>
+ <type>boolean</type>
+ <required>false</required>
+ <editable>true</editable>
+ <description>Verbose</description>
+ </parameter>
+ </parameters>
+ </mojo>
+ </mojos>
+ <dependencies/>
+</plugin>
diff --git a/maven/pom.properties b/maven/pom.properties
new file mode 100644
index 0000000..4aa8403
--- /dev/null
+++ b/maven/pom.properties
@@ -0,0 +1,3 @@
+version=@VERSION@
+groupId=com.tonicsystems.jarjar
+artifactId=jarjar-plugin
diff --git a/maven/pom.xml b/maven/pom.xml
new file mode 100644
index 0000000..9521fc4
--- /dev/null
+++ b/maven/pom.xml
@@ -0,0 +1,17 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.tonicsystems.jarjar</groupId>
+ <artifactId>jarjar-plugin</artifactId>
+ <packaging>maven-plugin</packaging>
+ <version>@VERSION@</version>
+ <name>Jar Jar Links Maven Plugin</name>
+ <url>http://tonicsystems.com/products/jarjar/</url>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>2.0</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/res/com/tonicsystems/jarjar/help.txt b/res/com/tonicsystems/jarjar/help.txt
new file mode 100644
index 0000000..8410909
--- /dev/null
+++ b/res/com/tonicsystems/jarjar/help.txt
@@ -0,0 +1,75 @@
+Jar Jar Links - A utility to repackage and embed Java libraries
+Copyright 2007 Google Inc.
+
+Command-line usage:
+
+ java -jar jarjar.jar [help]
+
+ Prints this help message.
+
+ java -jar jarjar.jar strings <cp>
+
+ Dumps all string literals in classpath <cp>. Line numbers will be
+ included if the classes have debug information.
+
+ java -jar jarjar.jar find <level> <cp1> [<cp2>]
+
+ Prints dependencies on classpath <cp2> in classpath <cp1>. If <cp2>
+ is omitted, <cp1> is used for both arguments.
+
+ The level argument must be "class" or "jar". The former prints
+ dependencies between individual classes, while the latter only
+ prints jar->jar dependencies. A "jar" in this context is actually
+ any classpath component, which can be a jar file, a zip file, or a
+ parent directory (see below).
+
+ java -jar jarjar.jar process <rulesFile> <inJar> <outJar>
+
+ Transform the <inJar> jar file, writing a new jar file to <outJar>.
+ Any existing file named by <outJar> will be deleted.
+
+ The transformation is defined by a set of rules in the file specified
+ by the rules argument (see below).
+
+Classpath format:
+
+ The classpath argument is a colon or semi-colon delimited set
+ (depending on platform) of directories, jar files, or zip files. See
+ the following page for more details:
+ http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/classpath.html
+
+ Mustang-style wildcards are also supported:
+ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6268383
+
+Rules file format:
+
+ The rules file is a text file, one rule per line. Leading and trailing
+ whitespace is ignored. There are three types of rules:
+
+ rule <pattern> <result>
+ zap <pattern>
+ keep <pattern>
+
+ The standard rule ("rule") is used to rename classes. All references
+ to the renamed classes will also be updated. If a class name is
+ matched by more than one rule, only the first one will apply.
+
+ <pattern> is a class name with optional wildcards. "**" will
+ match against any valid class name substring. To match a single
+ package component (by excluding "." from the match), a single "*" may
+ be used instead.
+
+ <result> is a class name which can optionally reference the
+ substrings matched by the wildcards. A numbered reference is available
+ for every "*" or "**" in the <pattern>, starting from left to
+ right: "@1", "@2", etc. A special "@0" reference contains the entire
+ matched class name.
+
+ The "zap" rule causes any matched class to be removed from the resulting
+ jar file. All zap rules are processed before renaming rules.
+
+ The "keep" rule marks all matched classes as "roots". If any keep
+ rules are defined all classes which are not reachable from the roots
+ via dependency analysis are discarded when writing the output
+ jar. This is the last step in the process, after renaming and zapping.
+
diff --git a/src/Jarjar.iml b/src/Jarjar.iml
new file mode 100644
index 0000000..70f1faf
--- /dev/null
+++ b/src/Jarjar.iml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/main" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="library" name="lib" level="project" />
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MAVEN_REPOSITORY$/org/apache/ant/ant/1.7.1/ant-1.7.1.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ </component>
+</module>
+
diff --git a/src/main/com/tonicsystems/jarjar/AbstractDepHandler.java b/src/main/com/tonicsystems/jarjar/AbstractDepHandler.java
new file mode 100644
index 0000000..5a54737
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/AbstractDepHandler.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.*;
+import java.util.*;
+
+abstract public class AbstractDepHandler implements DepHandler
+{
+ protected final int level;
+ private final Set<List<Object>> seenIt = new HashSet<List<Object>>();
+
+ protected AbstractDepHandler(int level) {
+ this.level = level;
+ }
+
+ public void handle(PathClass from, PathClass to) throws IOException {
+ List<Object> pair;
+ if (level == LEVEL_JAR) {
+ pair = createPair(from.getClassPath(), to.getClassPath());
+ } else {
+ pair = createPair(from.getClassName(), to.getClassName());
+ }
+ if (!seenIt.contains(pair)) {
+ seenIt.add(pair);
+ handle(pair.get(0).toString(), pair.get(1).toString());
+ }
+ }
+
+ abstract protected void handle(String from, String to) throws IOException;
+
+ public void handleStart() throws IOException { }
+ public void handleEnd() throws IOException { }
+
+ private static List<Object> createPair(Object o1, Object o2) {
+ List<Object> list = new ArrayList<Object>(2);
+ list.add(o1);
+ list.add(o2);
+ return list;
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/DepFind.java b/src/main/com/tonicsystems/jarjar/DepFind.java
new file mode 100644
index 0000000..40f68ff
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/DepFind.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.*;
+import java.util.*;
+import java.util.zip.ZipEntry;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+
+public class DepFind
+{
+ private File curDir = new File(System.getProperty("user.dir"));
+
+ public void setCurrentDirectory(File curDir) {
+ this.curDir = curDir;
+ }
+
+ public void run(String from, String to, DepHandler handler) throws IOException {
+ try {
+ ClassHeaderReader header = new ClassHeaderReader();
+ Map<String, String> classes = new HashMap<String, String>();
+ ClassPathIterator cp = new ClassPathIterator(curDir, to, null);
+ try {
+ while (cp.hasNext()) {
+ ClassPathEntry entry = cp.next();
+ InputStream in = entry.openStream();
+ try {
+ header.read(in);
+ classes.put(header.getClassName(), entry.getSource());
+ } catch (Exception e) {
+ System.err.println("Error reading " + entry.getName() + ": " + e.getMessage());
+ } finally {
+ in.close();
+ }
+ }
+ } finally {
+ cp.close();
+ }
+
+ handler.handleStart();
+ cp = new ClassPathIterator(curDir, from, null);
+ try {
+ while (cp.hasNext()) {
+ ClassPathEntry entry = cp.next();
+ InputStream in = entry.openStream();
+ try {
+ new ClassReader(in).accept(
+ new DepFindVisitor(classes, entry.getSource(), handler),
+ ClassReader.SKIP_DEBUG);
+ } catch (Exception e) {
+ System.err.println("Error reading " + entry.getName() + ": " + e.getMessage());
+ } finally {
+ in.close();
+ }
+ }
+ } finally {
+ cp.close();
+ }
+ handler.handleEnd();
+ } catch (RuntimeIOException e) {
+ throw (IOException)e.getCause();
+ }
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/DepFindVisitor.java b/src/main/com/tonicsystems/jarjar/DepFindVisitor.java
new file mode 100644
index 0000000..9d6611e
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/DepFindVisitor.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.*;
+import java.util.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import org.objectweb.asm.*;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.*;
+
+class DepFindVisitor extends RemappingClassAdapter
+{
+ public DepFindVisitor(Map<String, String> classes, String source, DepHandler handler) throws IOException {
+ super(null, new DepFindRemapper(classes, source, handler));
+ }
+
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ ((DepFindRemapper)remapper).setClassName(name);
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ private static class DepFindRemapper extends Remapper
+ {
+ private final Map<String, String> classes;
+ private final String source;
+ private final DepHandler handler;
+ private PathClass curPathClass;
+
+ public DepFindRemapper(Map<String, String> classes, String source, DepHandler handler) throws IOException {
+ this.classes = classes;
+ this.source = source;
+ this.handler = handler;
+ }
+
+ public void setClassName(String name) {
+ curPathClass = new PathClass(source, name);
+ }
+
+ public String map(String key) {
+ try {
+ if (classes.containsKey(key)) {
+ String otherSource = classes.get(key);
+ if (!source.equals(otherSource)) {
+ // TODO: some escape mechanism?
+ handler.handle(curPathClass, new PathClass(otherSource, key));
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeIOException(e);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/DepHandler.java b/src/main/com/tonicsystems/jarjar/DepHandler.java
new file mode 100644
index 0000000..33107d4
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/DepHandler.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import java.io.IOException;
+
+public interface DepHandler
+{
+ public static final int LEVEL_CLASS = 0;
+ public static final int LEVEL_JAR = 1;
+
+ void handleStart() throws IOException;
+ void handle(PathClass from, PathClass to) throws IOException;
+ void handleEnd() throws IOException;
+}
diff --git a/src/main/com/tonicsystems/jarjar/EmptyClassVisitor.java b/src/main/com/tonicsystems/jarjar/EmptyClassVisitor.java
new file mode 100644
index 0000000..348e03d
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/EmptyClassVisitor.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2003-2010 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tonicsystems.jarjar;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * An ASM3 EmptyVisitor replacement
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class EmptyClassVisitor extends ClassVisitor {
+
+ public EmptyClassVisitor() {
+ super(Opcodes.ASM4);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ return new MethodVisitor(Opcodes.ASM4) {};
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return new AnnotationVisitor(Opcodes.ASM4) {};
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ return new FieldVisitor(Opcodes.ASM4) {};
+ }
+
+}
diff --git a/src/main/com/tonicsystems/jarjar/ExcludeProcessor.java b/src/main/com/tonicsystems/jarjar/ExcludeProcessor.java
new file mode 100644
index 0000000..191803f
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/ExcludeProcessor.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.IOException;
+import java.util.*;
+
+class ExcludeProcessor implements JarProcessor
+{
+ private final Set<String> excludes;
+ private final boolean verbose;
+
+ public ExcludeProcessor(Set<String> excludes, boolean verbose) {
+ this.excludes = excludes;
+ this.verbose = verbose;
+ }
+
+ public boolean process(EntryStruct struct) throws IOException {
+ boolean toKeep = !excludes.contains(struct.name);
+ if (verbose && !toKeep)
+ System.err.println("Excluding " + struct.name);
+ return toKeep;
+ }
+}
+
diff --git a/src/main/com/tonicsystems/jarjar/JarJarMojo.java b/src/main/com/tonicsystems/jarjar/JarJarMojo.java
new file mode 100644
index 0000000..9d37b77
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/JarJarMojo.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+
+public class JarJarMojo extends AbstractMojo
+{
+ private File fromJar;
+ private File toJar;
+ private File rulesFile;
+ private String rules;
+ private boolean verbose;
+
+ public void execute() throws MojoExecutionException {
+ if (!((rulesFile == null || !rulesFile.exists()) ^ (rules == null)))
+ throw new MojoExecutionException("Exactly one of rules or rulesFile is required");
+
+ try {
+ List<PatternElement> patterns;
+ if (rules != null) {
+ patterns = RulesFileParser.parse(rules);
+ } else {
+ patterns = RulesFileParser.parse(rulesFile);
+ }
+ // TODO: refactor with Main.java
+ MainProcessor proc = new MainProcessor(patterns, verbose, true);
+ StandaloneJarProcessor.run(fromJar, toJar, proc);
+ proc.strip(toJar);
+ } catch (IOException e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/JarJarTask.java b/src/main/com/tonicsystems/jarjar/JarJarTask.java
new file mode 100644
index 0000000..2c183c9
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/JarJarTask.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import org.apache.tools.ant.BuildException;
+
+public class JarJarTask extends AntJarProcessor
+{
+ private List<PatternElement> patterns = new ArrayList<PatternElement>();
+
+ public void addConfiguredRule(Rule rule) {
+ if (rule.getPattern() == null || rule.getResult() == null)
+ throw new IllegalArgumentException("The <rule> element requires both \"pattern\" and \"result\" attributes.");
+ patterns.add(rule);
+ }
+
+ public void addConfiguredZap(Zap zap) {
+ if (zap.getPattern() == null)
+ throw new IllegalArgumentException("The <zap> element requires a \"pattern\" attribute.");
+ patterns.add(zap);
+ }
+
+ public void addConfiguredKeep(Keep keep) {
+ if (keep.getPattern() == null)
+ throw new IllegalArgumentException("The <keep> element requires a \"pattern\" attribute.");
+ patterns.add(keep);
+ }
+
+ public void execute() throws BuildException {
+ MainProcessor proc = new MainProcessor(patterns, verbose, false);
+ execute(proc);
+ try {
+ proc.strip(getDestFile());
+ } catch (IOException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ protected void cleanHelper() {
+ super.cleanHelper();
+ patterns.clear();
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/Keep.java b/src/main/com/tonicsystems/jarjar/Keep.java
new file mode 100644
index 0000000..14b719e
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/Keep.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+public class Keep extends PatternElement
+{
+}
diff --git a/src/main/com/tonicsystems/jarjar/KeepProcessor.java b/src/main/com/tonicsystems/jarjar/KeepProcessor.java
new file mode 100644
index 0000000..0176b84
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/KeepProcessor.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.*;
+import java.util.*;
+import org.objectweb.asm.*;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.*;
+
+// TODO: this can probably be refactored into JarClassVisitor, etc.
+class KeepProcessor extends Remapper implements JarProcessor
+{
+ private final ClassVisitor cv = new RemappingClassAdapter(new EmptyClassVisitor(), this);
+ private final List<Wildcard> wildcards;
+ private final List<String> roots = new ArrayList<String>();
+ private final Map<String, Set<String>> depend = new HashMap<String, Set<String>>();
+
+ public KeepProcessor(List<Keep> patterns) {
+ wildcards = PatternElement.createWildcards(patterns);
+ }
+
+ public boolean isEnabled() {
+ return !wildcards.isEmpty();
+ }
+
+ public Set<String> getExcludes() {
+ Set<String> closure = new HashSet<String>();
+ closureHelper(closure, roots);
+ Set<String> removable = new HashSet<String>(depend.keySet());
+ removable.removeAll(closure);
+ return removable;
+ }
+
+ private void closureHelper(Set<String> closure, Collection<String> process) {
+ if (process == null)
+ return;
+ for (String name : process) {
+ if (closure.add(name))
+ closureHelper(closure, depend.get(name));
+ }
+ }
+
+ private Set<String> curSet;
+ private byte[] buf = new byte[0x2000];
+
+ public boolean process(EntryStruct struct) throws IOException {
+ try {
+ if (struct.name.endsWith(".class")) {
+ String name = struct.name.substring(0, struct.name.length() - 6);
+ for (Wildcard wildcard : wildcards)
+ if (wildcard.matches(name))
+ roots.add(name);
+ depend.put(name, curSet = new HashSet<String>());
+ new ClassReader(new ByteArrayInputStream(struct.data)).accept(cv,
+ ClassReader.EXPAND_FRAMES);
+ curSet.remove(name);
+ }
+ } catch (Exception e) {
+ System.err.println("Error reading " + struct.name + ": " + e.getMessage());
+ }
+ return true;
+ }
+
+ public String map(String key) {
+ if (key.startsWith("java/") || key.startsWith("javax/"))
+ return null;
+ curSet.add(key);
+ return null;
+ }
+
+ public Object mapValue(Object value) {
+ if (value instanceof String) {
+ String s = (String)value;
+ if (PackageRemapper.isArrayForName(s)) {
+ mapDesc(s.replace('.', '/'));
+ } else if (isForName(s)) {
+ map(s.replace('.', '/'));
+ }
+ return value;
+ } else {
+ return super.mapValue(value);
+ }
+ }
+
+ // TODO: use this for package remapping too?
+ private static boolean isForName(String value) {
+ if (value.equals(""))
+ return false;
+ for (int i = 0, len = value.length(); i < len; i++) {
+ char c = value.charAt(i);
+ if (c != '.' && !Character.isJavaIdentifierPart(c))
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/Main.java b/src/main/com/tonicsystems/jarjar/Main.java
new file mode 100644
index 0000000..117bdbb
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/Main.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.*;
+import java.util.*;
+
+public class Main {
+
+ private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+ private static final String HELP;
+
+ static {
+ try {
+ HELP = readIntoString(Main.class.getResourceAsStream("help.txt"));
+ } catch (IOException e) {
+ throw new RuntimeIOException(e);
+ }
+ }
+
+ private static String readIntoString(InputStream in) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ BufferedReader r = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+ String line = null;
+ while ((line = r.readLine()) != null)
+ sb.append(line).append(LINE_SEPARATOR);
+ return sb.toString();
+ }
+
+ private boolean verbose;
+ private List patterns;
+ private int level = DepHandler.LEVEL_CLASS;
+
+ public static void main(String[] args) throws Exception {
+ MainUtil.runMain(new Main(), args, "help");
+ }
+
+ public void help() {
+ System.err.print(HELP);
+ }
+
+ public void strings(String cp) throws IOException {
+ if (cp == null) {
+ throw new IllegalArgumentException("cp is required");
+ }
+ new StringDumper().run(cp, new PrintWriter(System.out));
+ }
+
+ // TODO: make level an enum
+ public void find(String level, String cp1, String cp2) throws IOException {
+ if (level == null || cp1 == null) {
+ throw new IllegalArgumentException("level and cp1 are required");
+ }
+ if (cp2 == null) {
+ cp2 = cp1;
+ }
+ int levelFlag;
+ if ("class".equals(level)) {
+ levelFlag = DepHandler.LEVEL_CLASS;
+ } else if ("jar".equals(level)) {
+ levelFlag = DepHandler.LEVEL_JAR;
+ } else {
+ throw new IllegalArgumentException("unknown level " + level);
+ }
+ PrintWriter w = new PrintWriter(System.out);
+ DepHandler handler = new TextDepHandler(w, levelFlag);
+ new DepFind().run(cp1, cp2, handler);
+ w.flush();
+ }
+
+ public void process(File rulesFile, File inJar, File outJar) throws IOException {
+ if (rulesFile == null || inJar == null || outJar == null) {
+ throw new IllegalArgumentException("rulesFile, inJar, and outJar are required");
+ }
+ List<PatternElement> rules = RulesFileParser.parse(rulesFile);
+ boolean verbose = Boolean.getBoolean("verbose");
+ boolean skipManifest = Boolean.getBoolean("skipManifest");
+ MainProcessor proc = new MainProcessor(rules, verbose, skipManifest);
+ StandaloneJarProcessor.run(inJar, outJar, proc);
+ proc.strip(outJar);
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/MainProcessor.java b/src/main/com/tonicsystems/jarjar/MainProcessor.java
new file mode 100644
index 0000000..de15924
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/MainProcessor.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+class MainProcessor implements JarProcessor
+{
+ private final boolean verbose;
+ private final JarProcessorChain chain;
+ private final KeepProcessor kp;
+ private final Map<String, String> renames = new HashMap<String, String>();
+
+ public MainProcessor(List<PatternElement> patterns, boolean verbose, boolean skipManifest) {
+ this.verbose = verbose;
+ List<Zap> zapList = new ArrayList<Zap>();
+ List<Rule> ruleList = new ArrayList<Rule>();
+ List<Keep> keepList = new ArrayList<Keep>();
+ for (PatternElement pattern : patterns) {
+ if (pattern instanceof Zap) {
+ zapList.add((Zap) pattern);
+ } else if (pattern instanceof Rule) {
+ ruleList.add((Rule) pattern);
+ } else if (pattern instanceof Keep) {
+ keepList.add((Keep) pattern);
+ }
+ }
+
+ PackageRemapper pr = new PackageRemapper(ruleList, verbose);
+ kp = keepList.isEmpty() ? null : new KeepProcessor(keepList);
+
+ List<JarProcessor> processors = new ArrayList<JarProcessor>();
+ if (skipManifest)
+ processors.add(ManifestProcessor.getInstance());
+ if (kp != null)
+ processors.add(kp);
+ processors.add(new ZapProcessor(zapList));
+ processors.add(new JarTransformerChain(new RemappingClassTransformer[]{ new RemappingClassTransformer(pr) }));
+ processors.add(new ResourceProcessor(pr));
+ chain = new JarProcessorChain(processors.toArray(new JarProcessor[processors.size()]));
+ }
+
+ public void strip(File file) throws IOException {
+ if (kp == null)
+ return;
+ Set<String> excludes = getExcludes();
+ if (!excludes.isEmpty())
+ StandaloneJarProcessor.run(file, file, new ExcludeProcessor(excludes, verbose));
+ }
+
+ /**
+ * Returns the <code>.class</code> files to delete. As well the root-parameter as the rename ones
+ * are taken in consideration, so that the concerned files are not listed in the result.
+ *
+ * @return the paths of the files in the jar-archive, including the <code>.class</code> suffix
+ */
+ private Set<String> getExcludes() {
+ Set<String> result = new HashSet<String>();
+ for (String exclude : kp.getExcludes()) {
+ String name = exclude + ".class";
+ String renamed = renames.get(name);
+ result.add((renamed != null) ? renamed : name);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * @param struct
+ * @return <code>true</code> if the entry is to include in the output jar
+ * @throws IOException
+ */
+ public boolean process(EntryStruct struct) throws IOException {
+ String name = struct.name;
+ boolean keepIt = chain.process(struct);
+ if (keepIt) {
+ if (!name.equals(struct.name)) {
+ if (kp != null)
+ renames.put(name, struct.name);
+ if (verbose)
+ System.err.println("Renamed " + name + " -> " + struct.name);
+ }
+ } else {
+ if (verbose)
+ System.err.println("Removed " + name);
+ }
+ return keepIt;
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/MainUtil.java b/src/main/com/tonicsystems/jarjar/MainUtil.java
new file mode 100644
index 0000000..068ece6
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/MainUtil.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+class MainUtil
+{
+ public static void runMain(Object main, String[] args, String defCommand) throws Exception {
+ if (args.length > 0) {
+ String command = args[0];
+ Method[] methods = main.getClass().getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ if (method.getName().equals(command)) {
+ String[] remaining = new String[args.length - 1];
+ System.arraycopy(args, 1, remaining, 0, remaining.length);
+ try {
+ method.invoke(main, bindParameters(method, remaining));
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof IllegalArgumentException) {
+ System.err.println("Syntax error: " + cause.getMessage());
+ } else if (cause instanceof Exception) {
+ throw (Exception) cause;
+ } else {
+ throw e;
+ }
+ }
+ return;
+ }
+ }
+ }
+ if (defCommand != null)
+ runMain(main, new String[]{ defCommand }, null);
+ }
+
+ private static Object[] bindParameters(Method method, String[] args) {
+ List<Object> parameters = new ArrayList<Object>();
+ Class[] parameterTypes = method.getParameterTypes();
+ for (int i = 0, len = parameterTypes.length; i < len; i++) {
+ Class type = parameterTypes[i];
+ int remaining = Math.max(0, args.length - i);
+ if (type.equals(String[].class)) {
+ String[] rest = new String[remaining];
+ System.arraycopy(args, 1, rest, 0, remaining);
+ parameters.add(rest);
+ } else if (remaining > 0) {
+ parameters.add(convertParameter(args[i], parameterTypes[i]));
+ } else {
+ parameters.add(null);
+ }
+ }
+ return parameters.toArray();
+ }
+
+ private static Object convertParameter(String arg, Class type) {
+ if (type.equals(String.class)) {
+ return arg;
+ } else if (type.equals(Integer.class)) {
+ return Integer.valueOf(arg, 10);
+ } else if (type.equals(File.class)) {
+ return new File(arg);
+ } else {
+ throw new UnsupportedOperationException("Unknown type " + type);
+ }
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/ManifestProcessor.java b/src/main/com/tonicsystems/jarjar/ManifestProcessor.java
new file mode 100644
index 0000000..91f1f76
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/ManifestProcessor.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.IOException;
+import java.util.*;
+
+class ManifestProcessor implements JarProcessor
+{
+ private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
+ private static final ManifestProcessor INSTANCE = new ManifestProcessor();
+
+ public static ManifestProcessor getInstance() {
+ return INSTANCE;
+ }
+
+ private ManifestProcessor() {}
+
+ public boolean process(EntryStruct struct) throws IOException {
+ return !struct.name.equalsIgnoreCase(MANIFEST_PATH);
+ }
+}
+
diff --git a/src/main/com/tonicsystems/jarjar/PackageRemapper.java b/src/main/com/tonicsystems/jarjar/PackageRemapper.java
new file mode 100644
index 0000000..4d102be
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/PackageRemapper.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import org.objectweb.asm.*;
+import org.objectweb.asm.commons.*;
+import java.util.*;
+import java.util.regex.Pattern;
+
+class PackageRemapper extends Remapper
+{
+ private static final String RESOURCE_SUFFIX = "RESOURCE";
+
+ private static final Pattern ARRAY_FOR_NAME_PATTERN
+ = Pattern.compile("\\[L[\\p{javaJavaIdentifierPart}\\.]+?;");
+
+ private final List<Wildcard> wildcards;
+ private final Map<String, String> typeCache = new HashMap<String, String>();
+ private final Map<String, String> pathCache = new HashMap<String, String>();
+ private final Map<Object, String> valueCache = new HashMap<Object, String>();
+ private final boolean verbose;
+
+ public PackageRemapper(List<Rule> ruleList, boolean verbose) {
+ this.verbose = verbose;
+ wildcards = PatternElement.createWildcards(ruleList);
+ }
+
+ // also used by KeepProcessor
+ static boolean isArrayForName(String value) {
+ return ARRAY_FOR_NAME_PATTERN.matcher(value).matches();
+ }
+
+ public String map(String key) {
+ String s = typeCache.get(key);
+ if (s == null) {
+ s = replaceHelper(key);
+ if (key.equals(s))
+ s = null;
+ typeCache.put(key, s);
+ }
+ return s;
+ }
+
+ public String mapPath(String path) {
+ String s = pathCache.get(path);
+ if (s == null) {
+ s = path;
+ int slash = s.lastIndexOf('/');
+ String end;
+ if (slash < 0) {
+ end = s;
+ s = RESOURCE_SUFFIX;
+ } else {
+ end = s.substring(slash + 1);
+ s = s.substring(0, slash + 1) + RESOURCE_SUFFIX;
+ }
+ boolean absolute = s.startsWith("/");
+ if (absolute) s = s.substring(1);
+
+ s = replaceHelper(s);
+
+ if (absolute) s = "/" + s;
+ if (s.indexOf(RESOURCE_SUFFIX) < 0)
+ return path;
+ s = s.substring(0, s.length() - RESOURCE_SUFFIX.length()) + end;
+ pathCache.put(path, s);
+ }
+ return s;
+ }
+
+ public Object mapValue(Object value) {
+ if (value instanceof String) {
+ String s = valueCache.get(value);
+ if (s == null) {
+ s = (String)value;
+ if (isArrayForName(s)) {
+ String desc1 = s.replace('.', '/');
+ String desc2 = mapDesc(desc1);
+ if (!desc2.equals(desc1))
+ return desc2.replace('/', '.');
+ } else {
+ s = mapPath(s);
+ if (s.equals(value)) {
+ boolean hasDot = s.indexOf('.') >= 0;
+ boolean hasSlash = s.indexOf('/') >= 0;
+ if (!(hasDot && hasSlash)) {
+ if (hasDot) {
+ s = replaceHelper(s.replace('.', '/')).replace('/', '.');
+ } else {
+ s = replaceHelper(s);
+ }
+ }
+ }
+ }
+ valueCache.put(value, s);
+ }
+ // TODO: add back class name to verbose message
+ if (verbose && !s.equals(value))
+ System.err.println("Changed \"" + value + "\" -> \"" + s + "\"");
+ return s;
+ } else {
+ return super.mapValue(value);
+ }
+ }
+
+ private String replaceHelper(String value) {
+ for (Wildcard wildcard : wildcards) {
+ String test = wildcard.replace(value);
+ if (test != null)
+ return test;
+ }
+ return value;
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/PathClass.java b/src/main/com/tonicsystems/jarjar/PathClass.java
new file mode 100644
index 0000000..fbbb7ed
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/PathClass.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+public class PathClass
+{
+ private String classPath;
+ private String className;
+
+ public PathClass(String classPath, String className) {
+ this.classPath = classPath;
+ this.className = className;
+ }
+
+ public String getClassPath() {
+ return classPath;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public String toString() {
+ return classPath + "!" + className;
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/PatternElement.java b/src/main/com/tonicsystems/jarjar/PatternElement.java
new file mode 100644
index 0000000..6ccd9ea
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/PatternElement.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import java.util.*;
+
+abstract public class PatternElement
+{
+ private String pattern;
+
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ static List<Wildcard> createWildcards(List<? extends PatternElement> patterns) {
+ List<Wildcard> wildcards = new ArrayList<Wildcard>();
+ for (PatternElement pattern : patterns) {
+ String result = (pattern instanceof Rule) ? ((Rule)pattern).getResult() : "";
+ String expr = pattern.getPattern();
+ if (expr.indexOf('/') >= 0)
+ throw new IllegalArgumentException("Patterns cannot contain slashes");
+ wildcards.add(new Wildcard(expr.replace('.', '/'), result));
+ }
+ return wildcards;
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/ResourceProcessor.java b/src/main/com/tonicsystems/jarjar/ResourceProcessor.java
new file mode 100644
index 0000000..c07f664
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/ResourceProcessor.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.IOException;
+import java.util.*;
+
+class ResourceProcessor implements JarProcessor
+{
+ private PackageRemapper pr;
+
+ public ResourceProcessor(PackageRemapper pr) {
+ this.pr = pr;
+ }
+
+ public boolean process(EntryStruct struct) throws IOException {
+ if (!struct.name.endsWith(".class"))
+ struct.name = pr.mapPath(struct.name);
+ return true;
+ }
+}
+
diff --git a/src/main/com/tonicsystems/jarjar/Rule.java b/src/main/com/tonicsystems/jarjar/Rule.java
new file mode 100644
index 0000000..2e76ca8
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/Rule.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+public class Rule extends PatternElement
+{
+ private String result;
+
+ public void setResult(String result) {
+ this.result = result;
+ }
+
+ public String getResult() {
+ return result;
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/RulesFileParser.java b/src/main/com/tonicsystems/jarjar/RulesFileParser.java
new file mode 100644
index 0000000..f54f3b9
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/RulesFileParser.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import java.io.*;
+import java.util.*;
+
+class RulesFileParser
+{
+ private RulesFileParser() {
+ }
+
+ public static List<PatternElement> parse(File file) throws IOException {
+ return parse(new FileReader(file));
+ }
+
+ public static List<PatternElement> parse(String value) throws IOException {
+ return parse(new java.io.StringReader(value));
+ }
+
+ private static String stripComment(String in) {
+ int p = in.indexOf("#");
+ return p < 0 ? in : in.substring(0, p);
+ }
+
+ private static List<PatternElement> parse(Reader r) throws IOException {
+ try {
+ List<PatternElement> patterns = new ArrayList<PatternElement>();
+ BufferedReader br = new BufferedReader(r);
+ int c = 1;
+ String line;
+ while ((line = br.readLine()) != null) {
+ line = stripComment(line);
+ if (line.isEmpty())
+ continue;
+ String[] parts = line.split("\\s+");
+ if (parts.length < 2)
+ error(c, parts);
+ String type = parts[0];
+ PatternElement element = null;
+ if (type.equals("rule")) {
+ if (parts.length < 3)
+ error(c, parts);
+ Rule rule = new Rule();
+ rule.setResult(parts[2]);
+ element = rule;
+ } else if (type.equals("zap")) {
+ element = new Zap();
+ } else if (type.equals("keep")) {
+ element = new Keep();
+ } else {
+ error(c, parts);
+ }
+ element.setPattern(parts[1]);
+ patterns.add(element);
+ c++;
+ }
+ return patterns;
+ } finally {
+ r.close();
+ }
+ }
+
+ private static void error(int line, String[] parts) {
+ throw new IllegalArgumentException("Error on line " + line + ": " + Arrays.asList(parts));
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/StringDumper.java b/src/main/com/tonicsystems/jarjar/StringDumper.java
new file mode 100644
index 0000000..5086314
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/StringDumper.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.*;
+import org.objectweb.asm.*;
+
+class StringDumper
+{
+ public StringDumper() {
+ }
+
+ public void run(String classPath, PrintWriter pw) throws IOException {
+ StringReader stringReader = new DumpStringReader(pw);
+ ClassPathIterator cp = new ClassPathIterator(classPath);
+ try {
+ while (cp.hasNext()) {
+ ClassPathEntry entry = cp.next();
+ InputStream in = entry.openStream();
+ try {
+ new ClassReader(in).accept(stringReader, 0);
+ } catch (Exception e) {
+ System.err.println("Error reading " + entry.getName() + ": " + e.getMessage());
+ } finally {
+ in.close();
+ }
+ pw.flush();
+ }
+ } catch (RuntimeIOException e) {
+ throw (IOException)e.getCause();
+ } finally {
+ cp.close();
+ }
+ }
+
+ private static class DumpStringReader extends StringReader
+ {
+ private final PrintWriter pw;
+ private String className;
+
+ public DumpStringReader(PrintWriter pw) {
+ this.pw = pw;
+ }
+
+ public void visitString(String className, String value, int line) {
+ if (value.length() > 0) {
+ if (!className.equals(this.className)) {
+ this.className = className;
+ pw.println(className.replace('/', '.'));
+ }
+ pw.print("\t");
+ if (line >= 0)
+ pw.print(line + ": ");
+ pw.print(escapeStringLiteral(value));
+ pw.println();
+ }
+ }
+ };
+
+ private static String escapeStringLiteral(String value) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\"");
+ char[] chars = value.toCharArray();
+ for (int i = 0, size = chars.length; i < size; i++) {
+ char ch = chars[i];
+ switch (ch) {
+ case '\n': sb.append("\\n"); break;
+ case '\r': sb.append("\\r"); break;
+ case '\b': sb.append("\\b"); break;
+ case '\f': sb.append("\\f"); break;
+ case '\t': sb.append("\\t"); break;
+ case '\"': sb.append("\\\""); break;
+ case '\\': sb.append("\\\\"); break;
+ default:
+ sb.append(ch);
+ }
+ }
+ sb.append("\"");
+ return sb.toString();
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/StringReader.java b/src/main/com/tonicsystems/jarjar/StringReader.java
new file mode 100644
index 0000000..ba7bb29
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/StringReader.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import org.objectweb.asm.*;
+
+abstract class StringReader extends ClassVisitor
+{
+ private int line = -1;
+ private String className;
+
+ public StringReader() {
+ super(Opcodes.ASM4);
+ }
+
+ abstract public void visitString(String className, String value, int line);
+
+ private void handleObject(Object value) {
+ if (value instanceof String)
+ visitString(className, (String)value, line);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ className = name;
+ line = -1;
+ }
+
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ handleObject(value);
+ return new FieldVisitor(Opcodes.ASM4){
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return StringReader.this.visitAnnotation(desc, visible);
+ }
+ };
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return new AnnotationVisitor(Opcodes.ASM4) {
+ @Override
+ public void visit(String name, Object value) {
+ handleObject(value);
+ }
+ @Override
+ public void visitEnum(String name, String desc, String value) {
+ handleObject(value);
+ }
+ @Override
+ public AnnotationVisitor visitAnnotation(String name, String desc) {
+ return this;
+ }
+ };
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ MethodVisitor mv = new MethodVisitor(Opcodes.ASM4){
+ @Override
+ public void visitLdcInsn(Object cst) {
+ handleObject(cst);
+ }
+ @Override
+ public void visitLineNumber(int line, Label start) {
+ StringReader.this.line = line;
+ }
+ @Override
+ public void visitInvokeDynamicInsn(String name, String desc,
+ Handle bsm, Object... bsmArgs) {
+ for (Object bsmArg : bsmArgs) handleObject(bsmArg);
+ }
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return StringReader.this.visitAnnotation(desc, visible);
+ }
+ @Override
+ public AnnotationVisitor visitParameterAnnotation(int parameter,
+ String desc, boolean visible) {
+ return StringReader.this.visitAnnotation(desc, visible);
+ }
+ };
+ return mv;
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/TextDepHandler.java b/src/main/com/tonicsystems/jarjar/TextDepHandler.java
new file mode 100644
index 0000000..3551395
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/TextDepHandler.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import java.io.*;
+import java.util.*;
+
+public class TextDepHandler extends AbstractDepHandler
+{
+ private PrintWriter w;
+
+ public TextDepHandler(PrintWriter w, int level) {
+ super(level);
+ this.w = w;
+ }
+
+ protected void handle(String from, String to) throws IOException {
+ w.println(from + " -> " + to);
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/Wildcard.java b/src/main/com/tonicsystems/jarjar/Wildcard.java
new file mode 100644
index 0000000..723c6f5
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/Wildcard.java
@@ -0,0 +1,143 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+class Wildcard
+{
+ private static Pattern dstar = Pattern.compile("\\*\\*");
+ private static Pattern star = Pattern.compile("\\*");
+ private static Pattern estar = Pattern.compile("\\+\\??\\)\\Z");
+
+ private final Pattern pattern;
+ private final int count;
+ private final ArrayList<Object> parts = new ArrayList<Object>(16); // kept for debugging
+ private final String[] strings;
+ private final int[] refs;
+
+ public Wildcard(String pattern, String result) {
+ if (pattern.equals("**"))
+ throw new IllegalArgumentException("'**' is not a valid pattern");
+ if (!checkIdentifierChars(pattern, "/*"))
+ throw new IllegalArgumentException("Not a valid package pattern: " + pattern);
+ if (pattern.indexOf("***") >= 0)
+ throw new IllegalArgumentException("The sequence '***' is invalid in a package pattern");
+
+ String regex = pattern;
+ regex = replaceAllLiteral(dstar, regex, "(.+?)");
+ regex = replaceAllLiteral(star, regex, "([^/]+)");
+ regex = replaceAllLiteral(estar, regex, "*)");
+ this.pattern = Pattern.compile("\\A" + regex + "\\Z");
+ this.count = this.pattern.matcher("foo").groupCount();
+
+ // TODO: check for illegal characters
+ char[] chars = result.toCharArray();
+ int max = 0;
+ for (int i = 0, mark = 0, state = 0, len = chars.length; i < len + 1; i++) {
+ char ch = (i == len) ? '@' : chars[i];
+ if (state == 0) {
+ if (ch == '@') {
+ parts.add(new String(chars, mark, i - mark));
+ mark = i + 1;
+ state = 1;
+ }
+ } else {
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ break;
+ default:
+ if (i == mark)
+ throw new IllegalArgumentException("Backslash not followed by a digit");
+ int n = Integer.parseInt(new String(chars, mark, i - mark));
+ if (n > max)
+ max = n;
+ parts.add(new Integer(n));
+ mark = i--;
+ state = 0;
+ }
+ }
+ }
+ int size = parts.size();
+ strings = new String[size];
+ refs = new int[size];
+ Arrays.fill(refs, -1);
+ for (int i = 0; i < size; i++) {
+ Object v = parts.get(i);
+ if (v instanceof String) {
+ strings[i] = ((String)v).replace('.', '/');
+ } else {
+ refs[i] = ((Integer)v).intValue();
+ }
+ }
+ if (count < max)
+ throw new IllegalArgumentException("Result includes impossible placeholder \"@" + max + "\": " + result);
+ // System.err.println(this);
+ }
+
+ public boolean matches(String value) {
+ return getMatcher(value) != null;
+ }
+
+ public String replace(String value) {
+ Matcher matcher = getMatcher(value);
+ if (matcher != null) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < strings.length; i++)
+ sb.append((refs[i] >= 0) ? matcher.group(refs[i]) : strings[i]);
+ return sb.toString();
+ }
+ return null;
+ }
+
+ private Matcher getMatcher(String value) {
+ Matcher matcher = pattern.matcher(value);
+ if (matcher.matches() && checkIdentifierChars(value, "/"))
+ return matcher;
+ return null;
+ }
+
+ private static boolean checkIdentifierChars(String expr, String extra) {
+ // package-info violates the spec for Java Identifiers.
+ // Nevertheless, expressions that end with this string are still legal.
+ // See 7.4.1.1 of the Java language spec for discussion.
+ if (expr.endsWith("package-info")) {
+ expr = expr.substring(0, expr.length() - "package-info".length());
+ }
+ for (int i = 0, len = expr.length(); i < len; i++) {
+ char c = expr.charAt(i);
+ if (extra.indexOf(c) >= 0)
+ continue;
+ if (!Character.isJavaIdentifierPart(c))
+ return false;
+ }
+ return true;
+ }
+
+ private static String replaceAllLiteral(Pattern pattern, String value, String replace) {
+ replace = replace.replaceAll("([$\\\\])", "\\\\$0");
+ return pattern.matcher(value).replaceAll(replace);
+ }
+
+ public String toString() {
+ return "Wildcard{pattern=" + pattern + ",parts=" + parts + "}";
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/Zap.java b/src/main/com/tonicsystems/jarjar/Zap.java
new file mode 100644
index 0000000..ed5c828
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/Zap.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+public class Zap extends PatternElement
+{
+}
diff --git a/src/main/com/tonicsystems/jarjar/ZapProcessor.java b/src/main/com/tonicsystems/jarjar/ZapProcessor.java
new file mode 100644
index 0000000..5b6b680
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/ZapProcessor.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import java.io.IOException;
+import java.util.*;
+
+class ZapProcessor implements JarProcessor
+{
+ private List<Wildcard> wildcards;
+
+ public ZapProcessor(List<Zap> zapList) {
+ wildcards = PatternElement.createWildcards(zapList);
+ }
+
+ public boolean process(EntryStruct struct) throws IOException {
+ String name = struct.name;
+ if (name.endsWith(".class"))
+ return !zap(name.substring(0, name.length() - 6));
+ return true;
+ }
+
+ private boolean zap(String desc) {
+ // TODO: optimize
+ for (Wildcard wildcard : wildcards) {
+ if (wildcard.matches(desc))
+ return true;
+ }
+ return false;
+ }
+}
+
diff --git a/src/main/com/tonicsystems/jarjar/util/AntJarProcessor.java b/src/main/com/tonicsystems/jarjar/util/AntJarProcessor.java
new file mode 100644
index 0000000..ac30418
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/AntJarProcessor.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.*;
+import java.util.*;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Jar;
+import org.apache.tools.ant.types.ZipFileSet;
+import org.apache.tools.zip.JarMarker;
+import org.apache.tools.zip.ZipExtraField;
+import org.apache.tools.zip.ZipOutputStream;
+
+abstract public class AntJarProcessor extends Jar
+{
+ private EntryStruct struct = new EntryStruct();
+ private JarProcessor proc;
+ private byte[] buf = new byte[0x2000];
+
+ private Set<String> dirs = new HashSet<String>();
+ private boolean filesOnly;
+
+ protected boolean verbose;
+
+ private static final ZipExtraField[] JAR_MARKER = new ZipExtraField[] {
+ JarMarker.getInstance()
+ };
+
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ public abstract void execute() throws BuildException;
+
+ public void execute(JarProcessor proc) throws BuildException {
+ this.proc = proc;
+ super.execute();
+ }
+
+ public void setFilesonly(boolean f) {
+ super.setFilesonly(f);
+ filesOnly = f;
+ }
+
+ protected void zipDir(File dir, ZipOutputStream zOut, String vPath, int mode)
+ throws IOException {
+ }
+
+ protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath,
+ long lastModified, File fromArchive, int mode) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ IoUtil.pipe(is, baos, buf);
+ struct.data = baos.toByteArray();
+ struct.name = vPath;
+ struct.time = lastModified;
+ if (proc.process(struct)) {
+ if (mode == 0)
+ mode = ZipFileSet.DEFAULT_FILE_MODE;
+ if (!filesOnly) {
+ addParentDirs(struct.name, zOut);
+ }
+ super.zipFile(new ByteArrayInputStream(struct.data),
+ zOut, struct.name, struct.time, fromArchive, mode);
+ }
+ }
+
+ private void addParentDirs(String file, ZipOutputStream zOut) throws IOException {
+ int slash = file.lastIndexOf('/');
+ if (slash >= 0) {
+ String dir = file.substring(0, slash);
+ if (dirs.add(dir)) {
+ addParentDirs(dir, zOut);
+ super.zipDir((File) null, zOut, dir + "/", ZipFileSet.DEFAULT_DIR_MODE, JAR_MARKER);
+ }
+ }
+ }
+
+ public void reset() {
+ super.reset();
+ cleanHelper();
+ }
+
+ protected void cleanUp() {
+ super.cleanUp();
+ cleanHelper();
+ }
+
+ protected void cleanHelper() {
+ verbose = false;
+ filesOnly = false;
+ dirs.clear();
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java b/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java
new file mode 100644
index 0000000..6e448be
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/ClassHeaderReader.java
@@ -0,0 +1,186 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.*;
+import java.lang.reflect.Array;
+import java.util.*;
+
+public class ClassHeaderReader
+{
+ private int access;
+ private String thisClass;
+ private String superClass;
+ private String[] interfaces;
+
+ private InputStream in;
+ private byte[] b = new byte[0x2000];
+ private int[] items = new int[1000];
+ private int bsize = 0;
+ private MyByteArrayInputStream bin = new MyByteArrayInputStream();
+ private DataInputStream data = new DataInputStream(bin);
+
+ public int getAccess() {
+ return access;
+ }
+
+ public String getClassName() {
+ return thisClass;
+ }
+
+ public String getSuperName() {
+ return superClass;
+ }
+
+ public String[] getInterfaces() {
+ return interfaces;
+ }
+
+ public void read(InputStream in) throws IOException {
+ try {
+ this.in = in;
+ bsize = 0;
+ access = 0;
+ thisClass = superClass = null;
+ interfaces = null;
+
+ try {
+ buffer(4);
+ } catch (IOException e) {
+ // ignore
+ }
+ if (b[0] != (byte)0xCA || b[1] != (byte)0xFE || b[2] != (byte)0xBA || b[3] != (byte)0xBE)
+ throw new ClassFormatError("Bad magic number");
+
+ buffer(6);
+ readUnsignedShort(4); // minorVersion
+ readUnsignedShort(6); // majorVersion
+ // TODO: check version
+ int constant_pool_count = readUnsignedShort(8);
+ items = (int[])resizeArray(items, constant_pool_count);
+
+ int index = 10;
+ for (int i = 1; i < constant_pool_count; i++) {
+ int size;
+ buffer(index + 3); // TODO: reduce calls to buffer
+ int tag = b[index];
+ items[i] = index + 1;
+ switch (tag) {
+ case 9: // Fieldref
+ case 10: // Methodref
+ case 11: // InterfaceMethodref
+ case 3: // Integer
+ case 4: // Float
+ case 12: // NameAndType
+ size = 4;
+ break;
+ case 5: // Long
+ case 6: // Double
+ size = 8;
+ i++;
+ break;
+ case 1: // Utf8
+ size = 2 + readUnsignedShort(index + 1);
+ break;
+ case 7: // Class
+ case 8: // String
+ size = 2;
+ break;
+ default:
+ throw new IllegalStateException("Unknown constant pool tag " + tag);
+ }
+ index += size + 1;
+ }
+ buffer(index + 8);
+ access = readUnsignedShort(index);
+ thisClass = readClass(index + 2);
+ superClass = readClass(index + 4);
+ int interfaces_count = readUnsignedShort(index + 6);
+
+ index += 8;
+ buffer(index + interfaces_count * 2);
+ interfaces = new String[interfaces_count];
+ for (int i = 0; i < interfaces_count; i++) {
+ interfaces[i] = readClass(index);
+ index += 2;
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ private String readClass(int index) throws IOException {
+ index = readUnsignedShort(index);
+ if (index == 0)
+ return null;
+ index = readUnsignedShort(items[index]);
+ bin.readFrom(b, items[index]);
+ return data.readUTF();
+ }
+
+ private int readUnsignedShort(int index) {
+ byte[] b = this.b;
+ return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
+ }
+
+ private static final int CHUNK = 2048;
+ private void buffer(int amount) throws IOException {
+ if (amount > b.length)
+ b = (byte[])resizeArray(b, b.length * 2);
+ if (amount > bsize) {
+ int rounded = (int)(CHUNK * Math.ceil((float)amount / CHUNK));
+ bsize += read(in, b, bsize, rounded - bsize);
+ if (amount > bsize)
+ throw new EOFException();
+ }
+ }
+
+ private static int read(InputStream in, byte[] b, int off, int len) throws IOException {
+ int total = 0;
+ while (total < len) {
+ int result = in.read(b, off + total, len - total);
+ if (result == -1)
+ break;
+ total += result;
+ }
+ return total;
+ }
+
+ private static Object resizeArray(Object array, int length)
+ {
+ if (Array.getLength(array) < length) {
+ Object newArray = Array.newInstance(array.getClass().getComponentType(), length);
+ System.arraycopy(array, 0, newArray, 0, Array.getLength(array));
+ return newArray;
+ } else {
+ return array;
+ }
+ }
+
+ private static class MyByteArrayInputStream extends ByteArrayInputStream
+ {
+ public MyByteArrayInputStream() {
+ super(new byte[0]);
+ }
+
+ public void readFrom(byte[] buf, int pos) {
+ this.buf = buf;
+ this.pos = pos;
+ count = buf.length;
+ }
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/ClassPathEntry.java b/src/main/com/tonicsystems/jarjar/util/ClassPathEntry.java
new file mode 100644
index 0000000..d8de708
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/ClassPathEntry.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+public interface ClassPathEntry {
+ String getSource() throws IOException;
+ String getName();
+ InputStream openStream() throws IOException;
+} \ No newline at end of file
diff --git a/src/main/com/tonicsystems/jarjar/util/ClassPathIterator.java b/src/main/com/tonicsystems/jarjar/util/ClassPathIterator.java
new file mode 100644
index 0000000..f4f54f0
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/ClassPathIterator.java
@@ -0,0 +1,234 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.util.*;
+import java.util.zip.*;
+import java.io.*;
+import java.util.jar.*;
+
+public class ClassPathIterator implements Iterator<ClassPathEntry>
+{
+ private static final FileFilter CLASS_FILTER = new FileFilter() {
+ public boolean accept(File file) {
+ return file.isDirectory() || isClass(file.getName());
+ }
+ };
+
+ private static final FileFilter JAR_FILTER = new FileFilter() {
+ public boolean accept(File file) {
+ return hasExtension(file.getName(), ".jar");
+ }
+ };
+
+ private final Iterator<File> files;
+ private Iterator<ClassPathEntry> entries = Collections.<ClassPathEntry>emptyList().iterator();
+ private ClassPathEntry next;
+ private List<ZipFile> zips = new ArrayList<ZipFile>();
+
+ public ClassPathIterator(String classPath) throws IOException {
+ this(new File(System.getProperty("user.dir")), classPath, null);
+ }
+
+ public ClassPathIterator(File parent, String classPath, String delim) throws IOException {
+ if (delim == null) {
+ delim = System.getProperty("path.separator");
+ }
+ StringTokenizer st = new StringTokenizer(classPath, delim);
+ List<File> fileList = new ArrayList<File>();
+ while (st.hasMoreTokens()) {
+ String part = (String)st.nextElement();
+ boolean wildcard = false;
+ if (part.endsWith("/*")) {
+ part = part.substring(0, part.length() - 1);
+ if (part.indexOf('*') >= 0)
+ throw new IllegalArgumentException("Multiple wildcards are not allowed: " + part);
+ wildcard = true;
+ } else if (part.indexOf('*') >= 0) {
+ throw new IllegalArgumentException("Incorrect wildcard usage: " + part);
+ }
+
+ File file = new File(part);
+ if (!file.isAbsolute())
+ file = new File(parent, part);
+ if (!file.exists())
+ throw new IllegalArgumentException("File " + file + " does not exist");
+
+ if (wildcard) {
+ if (!file.isDirectory())
+ throw new IllegalArgumentException("File " + file + " + is not a directory");
+ fileList.addAll(findFiles(file, JAR_FILTER, false, new ArrayList<File>()));
+ } else {
+ fileList.add(file);
+ }
+ }
+ this.files = fileList.iterator();
+ advance();
+ }
+
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ /** Closes all zip files opened by this iterator. */
+ public void close() throws IOException {
+ next = null;
+ for (ZipFile zip : zips) {
+ zip.close();
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public ClassPathEntry next() {
+ if (!hasNext())
+ throw new NoSuchElementException();
+ ClassPathEntry result = next;
+ try {
+ advance();
+ } catch (IOException e) {
+ throw new RuntimeIOException(e);
+ }
+ return result;
+ }
+
+ private void advance() throws IOException {
+ if (!entries.hasNext()) {
+ if (!files.hasNext()) {
+ next = null;
+ return;
+ }
+ File file = files.next();
+ if (hasExtension(file.getName(), ".jar")) {
+ ZipFile zip = new JarFile(file);
+ zips.add(zip);
+ entries = new ZipIterator(zip);
+ } else if (hasExtension(file.getName(), ".zip")) {
+ ZipFile zip = new ZipFile(file);
+ zips.add(zip);
+ entries = new ZipIterator(zip);
+ } else if (file.isDirectory()) {
+ entries = new FileIterator(file);
+ } else {
+ throw new IllegalArgumentException("Do not know how to handle " + file);
+ }
+ }
+
+ boolean foundClass = false;
+ while (!foundClass && entries.hasNext()) {
+ next = entries.next();
+ foundClass = isClass(next.getName());
+ }
+ if (!foundClass) {
+ advance();
+ }
+ }
+
+ private static class ZipIterator implements Iterator<ClassPathEntry> {
+ private final ZipFile zip;
+ private final Enumeration<? extends ZipEntry> entries;
+
+ ZipIterator(ZipFile zip) {
+ this.zip = zip;
+ this.entries = zip.entries();
+ }
+
+ public boolean hasNext() {
+ return entries.hasMoreElements();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public ClassPathEntry next() {
+ final ZipEntry entry = entries.nextElement();
+ return new ClassPathEntry() {
+ public String getSource() {
+ return zip.getName();
+ }
+
+ public String getName() {
+ return entry.getName();
+ }
+
+ public InputStream openStream() throws IOException {
+ return zip.getInputStream(entry);
+ }
+ };
+ }
+ }
+
+ private static class FileIterator implements Iterator<ClassPathEntry> {
+ private final File dir;
+ private final Iterator<File> entries;
+
+ FileIterator(File dir) {
+ this.dir = dir;
+ this.entries = findFiles(dir, CLASS_FILTER, true, new ArrayList<File>()).iterator();
+ }
+
+ public boolean hasNext() {
+ return entries.hasNext();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public ClassPathEntry next() {
+ final File file = entries.next();
+ return new ClassPathEntry() {
+ public String getSource() throws IOException {
+ return dir.getCanonicalPath();
+ }
+
+ public String getName() {
+ return file.getName();
+ }
+
+ public InputStream openStream() throws IOException {
+ return new BufferedInputStream(new FileInputStream(file));
+ }
+ };
+ }
+ }
+
+ private static List<File> findFiles(File dir, FileFilter filter, boolean recurse, List<File> collect) {
+ for (File file : dir.listFiles(filter)) {
+ if (recurse && file.isDirectory()) {
+ findFiles(file, filter, recurse, collect);
+ } else {
+ collect.add(file);
+ }
+ }
+ return collect;
+ }
+
+ private static boolean isClass(String name) {
+ return hasExtension(name, ".class");
+ }
+
+ private static boolean hasExtension(String name, String ext) {
+ if (name.length() < ext.length())
+ return false;
+ String actual = name.substring(name.length() - ext.length());
+ return actual.equals(ext) || actual.equals(ext.toUpperCase());
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/EntryStruct.java b/src/main/com/tonicsystems/jarjar/util/EntryStruct.java
new file mode 100644
index 0000000..93f7622
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/EntryStruct.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.InputStream;
+import java.io.File;
+
+public class EntryStruct
+{
+ public byte[] data;
+ public String name;
+ public long time;
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/GetNameClassWriter.java b/src/main/com/tonicsystems/jarjar/util/GetNameClassWriter.java
new file mode 100644
index 0000000..bbb8590
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/GetNameClassWriter.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+
+public class GetNameClassWriter extends ClassVisitor
+{
+ private String className;
+
+ public GetNameClassWriter(int flags) {
+ super(Opcodes.ASM4,new ClassWriter(flags));
+ }
+
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ className = name;
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public byte[] toByteArray() {
+ return ((ClassWriter) cv).toByteArray();
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/IoUtil.java b/src/main/com/tonicsystems/jarjar/util/IoUtil.java
new file mode 100644
index 0000000..aef7ade
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/IoUtil.java
@@ -0,0 +1,131 @@
+/**
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+class IoUtil {
+ private IoUtil() {}
+
+ public static void pipe(InputStream is, OutputStream out, byte[] buf) throws IOException {
+ for (;;) {
+ int amt = is.read(buf);
+ if (amt < 0)
+ break;
+ out.write(buf, 0, amt);
+ }
+ }
+
+ public static void copy(File from, File to, byte[] buf) throws IOException {
+ InputStream in = new FileInputStream(from);
+ try {
+ OutputStream out = new FileOutputStream(to);
+ try {
+ pipe(in, out, buf);
+ } finally {
+ out.close();
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ /**
+ * Create a copy of an zip file without its empty directories.
+ * @param inputFile
+ * @param outputFile
+ * @throws IOException
+ */
+ public static void copyZipWithoutEmptyDirectories(final File inputFile, final File outputFile) throws IOException
+ {
+ final byte[] buf = new byte[0x2000];
+
+ final ZipFile inputZip = new ZipFile(inputFile);
+ final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(outputFile));
+ try
+ {
+ // read a the entries of the input zip file and sort them
+ final Enumeration<? extends ZipEntry> e = inputZip.entries();
+ final ArrayList<ZipEntry> sortedList = new ArrayList<ZipEntry>();
+ while (e.hasMoreElements()) {
+ final ZipEntry entry = e.nextElement();
+ sortedList.add(entry);
+ }
+
+ Collections.sort(sortedList, new Comparator<ZipEntry>()
+ {
+ public int compare(ZipEntry o1, ZipEntry o2)
+ {
+ return o1.getName().compareTo(o2.getName());
+ }
+ });
+
+ // treat them again and write them in output, wenn they not are empty directories
+ for (int i = sortedList.size()-1; i>=0; i--)
+ {
+ final ZipEntry inputEntry = sortedList.get(i);
+ final String name = inputEntry.getName();
+ final boolean isEmptyDirectory;
+ if (inputEntry.isDirectory())
+ {
+ if (i == sortedList.size()-1)
+ {
+ // no item afterwards; it was an empty directory
+ isEmptyDirectory = true;
+ }
+ else
+ {
+ final String nextName = sortedList.get(i+1).getName();
+ isEmptyDirectory = !nextName.startsWith(name);
+ }
+ }
+ else
+ {
+ isEmptyDirectory = false;
+ }
+
+
+ // write the entry
+ if (isEmptyDirectory)
+ {
+ sortedList.remove(inputEntry);
+ }
+ else
+ {
+ final ZipEntry outputEntry = new ZipEntry(inputEntry);
+ outputStream.putNextEntry(outputEntry);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final InputStream is = inputZip.getInputStream(inputEntry);
+ IoUtil.pipe(is, baos, buf);
+ is.close();
+ outputStream.write(baos.toByteArray());
+ }
+ }
+ } finally {
+ outputStream.close();
+ }
+
+ }
+
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/JarProcessor.java b/src/main/com/tonicsystems/jarjar/util/JarProcessor.java
new file mode 100644
index 0000000..1560696
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/JarProcessor.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.IOException;
+
+public interface JarProcessor
+{
+ /**
+ * Process the entry (p.ex. rename the file)
+ * <p>
+ * Returns <code>true</code> if the processor has has changed the entry. In this case, the entry can be removed
+ * from the jar file in a future time. Return <code>false</code> for the entries which do not have been changed and
+ * there fore are not to be deleted
+ *
+ * @param struct
+ * @return <code>true</code> if he process chain can continue after this process
+ * @throws IOException
+ */
+ boolean process(EntryStruct struct) throws IOException;
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/JarProcessorChain.java b/src/main/com/tonicsystems/jarjar/util/JarProcessorChain.java
new file mode 100644
index 0000000..06ac85d
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/JarProcessorChain.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.IOException;
+
+public class JarProcessorChain implements JarProcessor
+{
+ private final JarProcessor[] chain;
+
+ public JarProcessorChain(JarProcessor[] chain)
+ {
+ this.chain = chain.clone();
+ }
+
+ /**
+ * @param struct
+ * @return <code>true</code> if the entry has run the complete chain
+ * @throws IOException
+ */
+ public boolean process(EntryStruct struct) throws IOException
+ {
+
+ for (JarProcessor aChain : chain)
+ {
+ if (!aChain.process(struct))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
diff --git a/src/main/com/tonicsystems/jarjar/util/JarTransformer.java b/src/main/com/tonicsystems/jarjar/util/JarTransformer.java
new file mode 100644
index 0000000..95f1216
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/JarTransformer.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.*;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+
+abstract public class JarTransformer implements JarProcessor
+{
+ public boolean process(EntryStruct struct) throws IOException {
+ if (struct.name.endsWith(".class")) {
+ ClassReader reader;
+ try {
+ reader = new ClassReader(struct.data);
+ } catch (Exception e) {
+ return true; // TODO?
+ }
+ GetNameClassWriter w = new GetNameClassWriter(ClassWriter.COMPUTE_MAXS);
+ reader.accept(transform(w), ClassReader.EXPAND_FRAMES);
+ struct.data = w.toByteArray();
+ struct.name = pathFromName(w.getClassName());
+ }
+ return true;
+ }
+
+ abstract protected ClassVisitor transform(ClassVisitor v);
+
+ private static String pathFromName(String className) {
+ return className.replace('.', '/') + ".class";
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/JarTransformerChain.java b/src/main/com/tonicsystems/jarjar/util/JarTransformerChain.java
new file mode 100644
index 0000000..be16d9b
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/JarTransformerChain.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import org.objectweb.asm.ClassVisitor;
+
+public class JarTransformerChain extends JarTransformer
+{
+ private final RemappingClassTransformer[] chain;
+
+ public JarTransformerChain(RemappingClassTransformer[] chain) {
+ this.chain = chain.clone();
+ for (int i = chain.length - 1; i > 0; i--) {
+ chain[i - 1].setTarget(chain[i]);
+ }
+ }
+
+ protected ClassVisitor transform(ClassVisitor v) {
+ chain[chain.length - 1].setTarget(v);
+ return chain[0];
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/RemappingClassTransformer.java b/src/main/com/tonicsystems/jarjar/util/RemappingClassTransformer.java
new file mode 100644
index 0000000..fd1b9d7
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/RemappingClassTransformer.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.commons.Remapper;
+import org.objectweb.asm.commons.RemappingClassAdapter;
+
+import com.tonicsystems.jarjar.EmptyClassVisitor;
+
+public class RemappingClassTransformer extends RemappingClassAdapter
+{
+ public RemappingClassTransformer(Remapper pr) {
+ super(new EmptyClassVisitor(), pr);
+ }
+
+ public void setTarget(ClassVisitor target) {
+ cv = target;
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/RuntimeIOException.java b/src/main/com/tonicsystems/jarjar/util/RuntimeIOException.java
new file mode 100644
index 0000000..9b5d4a8
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/RuntimeIOException.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.io.IOException;
+
+public class RuntimeIOException extends RuntimeException
+{
+ private static final long serialVersionUID = 0L;
+
+ public RuntimeIOException(IOException e) {
+ super(e);
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/util/StandaloneJarProcessor.java b/src/main/com/tonicsystems/jarjar/util/StandaloneJarProcessor.java
new file mode 100644
index 0000000..70b169b
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/util/StandaloneJarProcessor.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar.util;
+
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.Enumeration;
+import java.io.*;
+import java.util.*;
+
+public class StandaloneJarProcessor
+{
+ public static void run(File from, File to, JarProcessor proc) throws IOException {
+ byte[] buf = new byte[0x2000];
+
+ JarFile in = new JarFile(from);
+ final File tmpTo = File.createTempFile("jarjar", ".jar");
+ JarOutputStream out = new JarOutputStream(new FileOutputStream(tmpTo));
+ Set<String> entries = new HashSet<String>();
+ try {
+ EntryStruct struct = new EntryStruct();
+ Enumeration<JarEntry> e = in.entries();
+ while (e.hasMoreElements()) {
+ JarEntry entry = e.nextElement();
+ struct.name = entry.getName();
+ struct.time = entry.getTime();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ IoUtil.pipe(in.getInputStream(entry), baos, buf);
+ struct.data = baos.toByteArray();
+ if (proc.process(struct)) {
+ if (entries.add(struct.name)) {
+ entry = new JarEntry(struct.name);
+ entry.setTime(struct.time);
+ entry.setCompressedSize(-1);
+ out.putNextEntry(entry);
+ out.write(struct.data);
+ } else if (struct.name.endsWith("/")) {
+ // TODO(chrisn): log
+ } else {
+ throw new IllegalArgumentException("Duplicate jar entries: " + struct.name);
+ }
+ }
+ }
+
+ }
+ finally {
+ in.close();
+ out.close();
+ }
+
+ // delete the empty directories
+ IoUtil.copyZipWithoutEmptyDirectories(tmpTo, to);
+ tmpTo.delete();
+
+ }
+}
diff --git a/src/test/Generics.class b/src/test/Generics.class
new file mode 100644
index 0000000..827519a
--- /dev/null
+++ b/src/test/Generics.class
Binary files differ
diff --git a/src/test/com/tonicsystems/jarjar/GenericsTest.java b/src/test/com/tonicsystems/jarjar/GenericsTest.java
new file mode 100644
index 0000000..1996a24
--- /dev/null
+++ b/src/test/com/tonicsystems/jarjar/GenericsTest.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.util.*;
+import junit.framework.*;
+import java.util.*;
+import org.objectweb.asm.ClassReader;
+
+public class GenericsTest
+extends TestCase
+{
+ public void testTransform() throws Exception {
+ Rule rule = new Rule();
+ rule.setPattern("java.lang.String");
+ rule.setResult("com.tonicsystems.String");
+ RemappingClassTransformer t = new RemappingClassTransformer(new PackageRemapper(Arrays.asList(rule), false));
+ t.setTarget(new EmptyClassVisitor());
+ ClassReader reader = new ClassReader(getClass().getResourceAsStream("/Generics.class"));
+ reader.accept(t, 0);
+ }
+
+ public GenericsTest(String name) {
+ super(name);
+ }
+
+ public static Test suite() {
+ return new TestSuite(GenericsTest.class);
+ }
+}
diff --git a/src/test/com/tonicsystems/jarjar/PackageRemapperTest.java b/src/test/com/tonicsystems/jarjar/PackageRemapperTest.java
new file mode 100644
index 0000000..aea9d46
--- /dev/null
+++ b/src/test/com/tonicsystems/jarjar/PackageRemapperTest.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import junit.framework.*;
+
+import java.util.Collections;
+
+public class PackageRemapperTest
+extends TestCase
+{
+ protected PackageRemapper remapper;
+
+ protected void setUp() {
+ Rule rule = new Rule();
+ rule.setPattern("org.**");
+ rule.setResult("foo.@1");
+ remapper = new PackageRemapper(Collections.singletonList(rule), false);
+ }
+
+ public void testMapValue() {
+ assertUnchangedValue("[^\\s;/@&=,.?:+$]");
+ assertUnchangedValue("[Ljava/lang/Object;");
+ assertUnchangedValue("[Lorg/example/Object;");
+ assertUnchangedValue("[Ljava.lang.Object;");
+ assertUnchangedValue("[Lorg.example/Object;");
+ assertUnchangedValue("[L;");
+ assertUnchangedValue("[Lorg.example.Object;;");
+ assertUnchangedValue("[Lorg.example.Obj ct;");
+ assertUnchangedValue("org.example/Object");
+
+ assertEquals("[Lfoo.example.Object;", remapper.mapValue("[Lorg.example.Object;"));
+ assertEquals("foo.example.Object", remapper.mapValue("org.example.Object"));
+ assertEquals("foo/example/Object", remapper.mapValue("org/example/Object"));
+ assertEquals("foo/example.Object", remapper.mapValue("org/example.Object")); // path match
+
+ assertEquals("foo.example.package-info", remapper.mapValue("org.example.package-info"));
+ assertEquals("foo/example/package-info", remapper.mapValue("org/example/package-info"));
+ assertEquals("foo/example.package-info", remapper.mapValue("org/example.package-info"));
+ }
+
+ private void assertUnchangedValue(String value) {
+ assertEquals(value, remapper.mapValue(value));
+ }
+}
diff --git a/src/test/com/tonicsystems/jarjar/RulesFileParserTest.java b/src/test/com/tonicsystems/jarjar/RulesFileParserTest.java
new file mode 100644
index 0000000..4a4c371
--- /dev/null
+++ b/src/test/com/tonicsystems/jarjar/RulesFileParserTest.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import junit.framework.*;
+import java.io.*;
+
+public class RulesFileParserTest
+extends TestCase
+{
+ public void testSimple() throws Exception {
+ // TODO
+ }
+
+ public RulesFileParserTest(String name) {
+ super(name);
+ }
+
+ public static Test suite() {
+ return new TestSuite(RulesFileParserTest.class);
+ }
+}
diff --git a/src/test/com/tonicsystems/jarjar/WildcardTest.java b/src/test/com/tonicsystems/jarjar/WildcardTest.java
new file mode 100644
index 0000000..7cdcdf7
--- /dev/null
+++ b/src/test/com/tonicsystems/jarjar/WildcardTest.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tonicsystems.jarjar;
+
+import junit.framework.*;
+
+public class WildcardTest
+extends TestCase
+{
+ public void testWildcards() {
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/proxy/Mixin$Generator",
+ "foo/proxy/Mixin$Generator");
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/Bar", "foo/Bar");
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/Bar/Baz", "foo/Bar/Baz");
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/", "foo/");
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/!", null);
+ wildcard("net/sf/cglib/*", "foo/@1", "net/sf/cglib/Bar", "foo/Bar");
+ wildcard("net/sf/cglib/*/*", "foo/@2/@1", "net/sf/cglib/Bar/Baz", "foo/Baz/Bar");
+ }
+
+ private void wildcard(String pattern, String result, String value, String expect) {
+ Wildcard wc = new Wildcard(pattern, result);
+ // System.err.println(wc);
+ assertEquals(expect, wc.replace(value));
+ }
+
+ public WildcardTest(String name) {
+ super(name);
+ }
+
+ public static Test suite() {
+ return new TestSuite(WildcardTest.class);
+ }
+}
diff --git a/src/test/com/tonicsystems/jarjar/example/Example.java b/src/test/com/tonicsystems/jarjar/example/Example.java
new file mode 100644
index 0000000..2129962
--- /dev/null
+++ b/src/test/com/tonicsystems/jarjar/example/Example.java
@@ -0,0 +1,5 @@
+package com.tonicsystems.jarjar.example;
+
+public class Example
+{
+}
diff --git a/src/test/enumtest.jar b/src/test/enumtest.jar
new file mode 100644
index 0000000..df34d16
--- /dev/null
+++ b/src/test/enumtest.jar
Binary files differ