From dfdde7719123b7db9cf1e49e6ee8fd175608dd23 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Mon, 15 Jul 2019 18:54:17 +0200 Subject: [PATCH] Update JD-Core 1.0.7 First code commit since 2015 --- .gitignore | 3 + .project | 9 + LICENSE | 6 +- build.gradle | 26 ++- gradle/wrapper/gradle-wrapper.jar | Bin 51010 -> 52266 bytes gradle/wrapper/gradle-wrapper.properties | 12 +- org.jd.ide.eclipse.feature/.classpath | 5 + org.jd.ide.eclipse.feature/.project | 21 +++ org.jd.ide.eclipse.feature/build.gradle | 6 + org.jd.ide.eclipse.feature/build.properties | 1 + org.jd.ide.eclipse.feature/feature.xml | 90 +++++++++ org.jd.ide.eclipse.plugin/.classpath | 8 + org.jd.ide.eclipse.plugin/.project | 25 +++ .../META-INF/MANIFEST.MF | 25 +++ org.jd.ide.eclipse.plugin/about.ini | 7 + org.jd.ide.eclipse.plugin/build.gradle | 81 +++++++++ org.jd.ide.eclipse.plugin/build.properties | 9 + org.jd.ide.eclipse.plugin/icons/jd_16.png | Bin 0 -> 734 bytes org.jd.ide.eclipse.plugin/icons/jd_32.png | Bin 0 -> 1691 bytes org.jd.ide.eclipse.plugin/plugin.xml | 33 ++++ .../jd/ide/eclipse/JavaDecompilerPlugin.java | 129 +++++++++++++ .../eclipse/editors/JDClassFileEditor.java | 171 ++++++++++++++++++ .../ide/eclipse/editors/JDSourceMapper.java | 163 +++++++++++++++++ .../preferences/PreferenceInitializer.java | 32 ++++ .../eclipse/preferences/PreferencePage.java | 63 +++++++ .../ide/eclipse/startup/JDStartupClass.java | 20 ++ .../eclipse/util/loader/DirectoryLoader.java | 48 +++++ .../jd/ide/eclipse/util/loader/ZipLoader.java | 61 +++++++ .../LineNumberStringBuilderPrinter.java | 106 +++++++++++ .../util/printer/StringBuilderPrinter.java | 95 ++++++++++ org.jd.ide.eclipse.site/.project | 17 ++ org.jd.ide.eclipse.site/site.xml | 7 + settings.gradle | 2 +- 33 files changed, 1264 insertions(+), 17 deletions(-) create mode 100644 .project create mode 100644 org.jd.ide.eclipse.feature/.classpath create mode 100644 org.jd.ide.eclipse.feature/.project create mode 100644 org.jd.ide.eclipse.feature/build.gradle create mode 100644 org.jd.ide.eclipse.feature/build.properties create mode 100644 org.jd.ide.eclipse.feature/feature.xml create mode 100644 org.jd.ide.eclipse.plugin/.classpath create mode 100644 org.jd.ide.eclipse.plugin/.project create mode 100644 org.jd.ide.eclipse.plugin/META-INF/MANIFEST.MF create mode 100644 org.jd.ide.eclipse.plugin/about.ini create mode 100644 org.jd.ide.eclipse.plugin/build.gradle create mode 100644 org.jd.ide.eclipse.plugin/build.properties create mode 100644 org.jd.ide.eclipse.plugin/icons/jd_16.png create mode 100644 org.jd.ide.eclipse.plugin/icons/jd_32.png create mode 100644 org.jd.ide.eclipse.plugin/plugin.xml create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/JavaDecompilerPlugin.java create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/editors/JDClassFileEditor.java create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/editors/JDSourceMapper.java create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/preferences/PreferenceInitializer.java create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/preferences/PreferencePage.java create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/startup/JDStartupClass.java create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/loader/DirectoryLoader.java create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/loader/ZipLoader.java create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/printer/LineNumberStringBuilderPrinter.java create mode 100644 org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/printer/StringBuilderPrinter.java create mode 100644 org.jd.ide.eclipse.site/.project create mode 100644 org.jd.ide.eclipse.site/site.xml diff --git a/.gitignore b/.gitignore index 0bacf76..a19a1bc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ *.class *.jar +# JD +debug* + # Eclipse .settings/ bin/ diff --git a/.project b/.project new file mode 100644 index 0000000..044654e --- /dev/null +++ b/.project @@ -0,0 +1,9 @@ + + + jd-eclipse + + + + + + diff --git a/LICENSE b/LICENSE index 21dbbc6..230579e 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (c) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -635,7 +635,7 @@ the "copyright" line and a pointer to where the full notice is found. JD-Eclipse is a plug-in for the Eclipse platform. It allows you to display all the Java sources during your debugging process, even if you do not have them all. - Copyright (C) 2008-2015 Emmanuel Dupuy + Copyright (c) 2008, 2019 Emmanuel Dupuy This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -655,7 +655,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - JD-Eclipse Copyright (C) 2008-2015 Emmanuel Dupuy + JD-Eclipse Copyright (c) 2008, 2019 Emmanuel Dupuy This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/build.gradle b/build.gradle index 22c7c6d..6bf9df5 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'distribution' // Common configuration // allprojects { - version='1.0.0' + version='2.0.0' } subprojects.each { subproject -> @@ -10,17 +10,29 @@ subprojects.each { subproject -> } distributions { - site { + distZip { + // Create JAR files before final ZIP file + dependsOn subprojects.tasks['jar'] + // For each file, remove root directory + eachFile { file -> + String path = file.relativePath + file.setPath(path.substring(path.indexOf('/')+1, path.length())) + } + } + + main { contents { into('features') { - from { fileTree('jd.ide.eclipse.feature/build/libs') { include '*.jar' } } + from { + fileTree 'org.jd.ide.eclipse.feature/build/libs' + } } into('plugins') { - from { fileTree('jd.ide.eclipse.plugin/build/libs') { include '*.jar' } } + from { + fileTree 'org.jd.ide.eclipse.plugin/build/libs' + } } - from 'jd.ide.eclipse.site/site.xml', 'LICENSE', 'NOTICE', 'README.md' + from 'org.jd.ide.eclipse.site/site.xml', 'LICENSE', 'NOTICE', 'README.md' } } } - -installSiteDist.dependsOn subprojects.tasks['jar'] diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 2322723c7ed5f591adfa4c87b6c51932f591249a..b5166dad4d90021f6a0b45268c0755719f1d5cd4 100644 GIT binary patch delta 20819 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%0As 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 bASgruN7Vt0FQi$Nz-7#K7@V{Ez1IH$92=ST delta 19525 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5b79a30..1715e2b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jul 06 16:38:55 CEST 2015 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip +#Sat Mar 02 11:11:32 CET 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip diff --git a/org.jd.ide.eclipse.feature/.classpath b/org.jd.ide.eclipse.feature/.classpath new file mode 100644 index 0000000..b7e2871 --- /dev/null +++ b/org.jd.ide.eclipse.feature/.classpath @@ -0,0 +1,5 @@ + + + + + diff --git a/org.jd.ide.eclipse.feature/.project b/org.jd.ide.eclipse.feature/.project new file mode 100644 index 0000000..2194f53 --- /dev/null +++ b/org.jd.ide.eclipse.feature/.project @@ -0,0 +1,21 @@ + + + org.jd.ide.eclipse.feature + + + + org.eclipse.pde.FeatureNature + org.eclipse.jdt.core.javanature + + + + org.eclipse.pde.FeatureBuilder + + + + org.eclipse.jdt.core.javabuilder + + + + + diff --git a/org.jd.ide.eclipse.feature/build.gradle b/org.jd.ide.eclipse.feature/build.gradle new file mode 100644 index 0000000..269e3be --- /dev/null +++ b/org.jd.ide.eclipse.feature/build.gradle @@ -0,0 +1,6 @@ +apply plugin: 'java' + +jar { + from 'feature.xml' + archiveName baseName + '_' + version + '.' + extension +} diff --git a/org.jd.ide.eclipse.feature/build.properties b/org.jd.ide.eclipse.feature/build.properties new file mode 100644 index 0000000..64f93a9 --- /dev/null +++ b/org.jd.ide.eclipse.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/org.jd.ide.eclipse.feature/feature.xml b/org.jd.ide.eclipse.feature/feature.xml new file mode 100644 index 0000000..5680b88 --- /dev/null +++ b/org.jd.ide.eclipse.feature/feature.xml @@ -0,0 +1,90 @@ + + + + + JD-Eclipse is a plug-in for the Eclipse platform. It allows you to display all the Java sources during your debugging process, even if you do not have them all. + + + + Copyright (c) 2008, 2019 Emmanuel Dupuy + + + + . + GNU GENERAL PUBLIC LICENSE + + Version 3, 29 June 2007 + + <http://www.gnu.org/licenses/gpl-3.0.html> + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + JD-Eclipse is a plug-in for the Eclipse platform. It allows you to + display all the Java sources during your debugging process, even if you + do not have them all. + Copyright (c) 2008, 2019 Emmanuel Dupuy + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + JD-Eclipse Copyright (c) 2008, 2019 Emmanuel Dupuy + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. + + + + + diff --git a/org.jd.ide.eclipse.plugin/.classpath b/org.jd.ide.eclipse.plugin/.classpath new file mode 100644 index 0000000..a6d508d --- /dev/null +++ b/org.jd.ide.eclipse.plugin/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.jd.ide.eclipse.plugin/.project b/org.jd.ide.eclipse.plugin/.project new file mode 100644 index 0000000..e5dfac0 --- /dev/null +++ b/org.jd.ide.eclipse.plugin/.project @@ -0,0 +1,25 @@ + + + org.jd.ide.eclipse.plugin + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + + + org.eclipse.jdt.core.javabuilder + + + + org.eclipse.pde.ManifestBuilder + + + + org.eclipse.pde.SchemaBuilder + + + + + diff --git a/org.jd.ide.eclipse.plugin/META-INF/MANIFEST.MF b/org.jd.ide.eclipse.plugin/META-INF/MANIFEST.MF new file mode 100644 index 0000000..9f14a20 --- /dev/null +++ b/org.jd.ide.eclipse.plugin/META-INF/MANIFEST.MF @@ -0,0 +1,25 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: JD-Eclipse Plug-in +Bundle-SymbolicName: org.jd.ide.eclipse.plugin;singleton:=true +Bundle-Version: 2.0.0 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.eclipse.ui, + org.eclipse.ui.editors, + org.eclipse.jdt.ui, + org.eclipse.jdt.core, + org.eclipse.core.runtime, + org.eclipse.core.resources, + org.eclipse.ui.ide, + org.eclipse.jface.text +Bundle-Vendor: Java Decompiler +Bundle-Activator: org.jd.ide.eclipse.JavaDecompilerPlugin +Bundle-ActivationPolicy: lazy +Bundle-ClassPath: /lib/jd-core-1.0.7.jar,. +Export-Package: org.jd.core.v1, + org.jd.ide.eclipse, + org.jd.ide.eclipse.editors, + org.jd.ide.eclipse.preferences, + org.jd.ide.eclipse.startup, + org.jd.ide.eclipse.util.loader, + org.jd.ide.eclipse.util.printer diff --git a/org.jd.ide.eclipse.plugin/about.ini b/org.jd.ide.eclipse.plugin/about.ini new file mode 100644 index 0000000..6892842 --- /dev/null +++ b/org.jd.ide.eclipse.plugin/about.ini @@ -0,0 +1,7 @@ +featureImage=icons/jd_32.png +aboutText=Java Decompiler\n\ +\n\ +Web site: http://java-decompiler.github.io\n\ +Issues: https://github.com/java-decompiler/jd-eclipse/issues\n\ +\n\ +Copyright (c) 2008, 2019 Emmanuel Dupuy diff --git a/org.jd.ide.eclipse.plugin/build.gradle b/org.jd.ide.eclipse.plugin/build.gradle new file mode 100644 index 0000000..5a48efc --- /dev/null +++ b/org.jd.ide.eclipse.plugin/build.gradle @@ -0,0 +1,81 @@ +apply plugin: 'java' + +repositories { + jcenter() +} + +configurations { + provided + compile.extendsFrom provided +} + +dependencies { + compile 'org.jd:jd-core:1.0.7' + + provided 'org.eclipse.core:org.eclipse.core.commands:3.6.0' + provided 'org.eclipse.core:org.eclipse.core.resources:3.7.100' + + provided('org.eclipse.jdt:org.eclipse.jdt.core:3.18.0') { + exclude group:'org.eclipse.platform' + } + provided('org.eclipse.jdt:org.eclipse.jdt.ui:3.18.0') { + exclude group:'org.eclipse.birt.runtime' + exclude group:'org.eclipse.emf' + exclude group:'org.eclipse.jdt' + exclude group:'org.eclipse.platform' + exclude group:'com.ibm.icu' + } + provided('org.eclipse.platform:org.eclipse.jface:3.15.0') { + exclude group:'org.eclipse.platform' + } + provided('org.eclipse.platform:org.eclipse.jface.text:3.15.0') { + exclude group:'org.eclipse.platform' + } + provided('org.eclipse.platform:org.eclipse.swt.win32.win32.x86_64:3.111.0') { + exclude group:'org.eclipse.platform' + } + provided('org.eclipse.platform:org.eclipse.ui.workbench:3.111.0') { + exclude group:'org.eclipse.emf' + exclude group:'org.eclipse.platform' + } + provided('org.eclipse.platform:org.eclipse.ui.workbench.texteditor:3.11.0') { + exclude group:'org.eclipse.platform' + } + provided('org.eclipse.platform:org.eclipse.ui.ide:3.15.0') { + exclude group:'org.eclipse.platform' + } + provided('org.eclipse.platform:org.eclipse.ui.editors:3.11.0') { + exclude group:'org.eclipse.platform' + } + provided('org.eclipse.platform:org.eclipse.ui.editors:3.11.0') { + exclude group:'org.eclipse.platform' + } +} + +compileJava { + sourceCompatibility = '1.8' + targetCompatibility = '1.8' + source 'src' +} + +jar { + archiveName baseName + '_' + version + '.' + extension + manifest { + from 'META-INF/MANIFEST.MF' + } + from fileTree('.') { + include 'icons/**' + include 'about.ini' + include 'plugin.xml' + } + into('lib') { + from project.configurations.runtime - project.configurations.provided + } +} + +task copyDependencies(type: Copy) { + from project.configurations.runtime - project.configurations.provided + into 'lib' +} + +build.finalizedBy copyDependencies diff --git a/org.jd.ide.eclipse.plugin/build.properties b/org.jd.ide.eclipse.plugin/build.properties new file mode 100644 index 0000000..290bd9f --- /dev/null +++ b/org.jd.ide.eclipse.plugin/build.properties @@ -0,0 +1,9 @@ +bin.includes = META-INF/,\ + plugin.xml,\ + icons/,\ + about.ini,\ + lib/jd-core-1.0.7.jar,\ + . +source.. = src/ +jars.compile.order = . + diff --git a/org.jd.ide.eclipse.plugin/icons/jd_16.png b/org.jd.ide.eclipse.plugin/icons/jd_16.png new file mode 100644 index 0000000000000000000000000000000000000000..986fb1dc8af8e429c39d3b1821491e1d14117414 GIT binary patch literal 734 zcmV<40wMj0P)2KP3(|OO$(6m5($w}VlobztZy(Sb{ZnxXX zId?F|V!ge+E3K`q7#SJa!xM@bP)b9LF^42c9qsMy4yV&8?Z+!>P*YP=X|vhRsjAu} z%kt&H!9ltoj}$5Yg3srxCxo2d-rf#+z21ppADMPv+`n}V5vk&trfElhPy1f|^iB*V z)NK5}26vn5E!9;*=dq@!n?d#|H7k#74qX2k; z!Sn7@eOGQj=t_L-hqaW#<}8I0m!Pc^kgy7v80;6@;9r_zUENPzpXS5wcML=TxbCX! zY;@f`Dx^gaH4SZR5&FUsGQYw|uVi5=tAtQj3yq{qLH}H|t?BR?SuiimY{X-^5Jd}t z-0T8y$;ehPD%Am~P?Z=;R?F~ksN)XTHH2@poWNw@s<5{y1b_s<3czBVMF0Y5VgqAC zkC6&^VLwpb06-#zc?t$Z!$b$bj5iZ#Y8_U(f{od6d>ES<2S9ht0nfvZnCC(#q6Mi` zl0A7e{L(WW>;b??p_my$El->^_6!-CMo<5bdlQS10RV~IC`Tjlpss8hWDNiXpcPx#32;bRa{vGf6951U69E94oEQKA00(qQO+^RU0RjvI4KfPQW&i*NElET{R9M5s zmtAZeR~3N2J2N}GYp>UK{1-cRXhWPp5*sB_qqYR8AtDH+QU$Jx1QG~@5Kpc9#8bo* z4MAEUP7zO686pKkhuL9{o`lo;hgi1Y2HkwQt8d=&>q$J>C>l;vuDpf?>NqjmSwf| z^z?imXxOYCW3vlRojTQ_lsahJ_R(UoxWl&Xgp^X3Qa%}tMnB=YZuYSNoIH85DGbB! zWwY6*N~Kc5^SqdpQU`>TQr@_6W7u`w!ejG5p-|}0WHQgVu3G~LP1A(yy3YLk{KU}E z(3R=w>1)8`V*xmE;soh*y2-Mv8l{xbG)+uSPL5r^eECADR7wGJKoL-nD-#jtN&UedgX9;tM9ABF*EpVZQS3NNSfPg z;zqOCwlkRxTM>ePZ8m#9OsHAMwu4L|@6P6J4Fewy3TXYe3I6tdR)&XpZ;KNSw!L2^cl#ox>32|GmWUyVBqA6w z9ZedH-PMRmgZ5+%wY72d`UKIAX0*CyM05wLW*3?93!MAuYtEa4*{@%@w{+p-ARY#x zABdw*f4+NL%bstL9X(I>H$R~+mZWBT3$czyjJgEq5u~GYpdErNcr!lshZzbZLzKoR zi1&2TcljDAG#LB+)ob4d{tPTv1qhWgHBAzUYb16YBIx`OV_^g_J&*U` z9!|^x%_hkE`19aSYLxyVab_ec1kEsT=N3e$;zHjbyFD5a9SS`*Em+u1^<=-O|M z%=%T2p)f+?ZB4{qewn~6;iqQ^9^8Z64ANSJLIKg{VeXD#9I2(gt^u=iE9R5iiFS0L zM{DtX!P49!GITj|py}DVy3X4|2=cj7K4us{Ja_&6&j7DV9#EiZ81W=VXD@W_FDn~j z?RyU;KoKAV7wP0d26P?x7X3$e>UykM7g_{s_G;6Q`(OP*W8A!&EqOy56eDd#M49L- z%&VeTq!LlKMxvRmXl66Qs6`lY>e`>>;Guo>yW0|dfLX-@qD9NjEUU;j zzx!p9tv#gY7qGq1U){+D9uO67)ysg?I&FnmqoZh96fKVzUg#xi*5PLFa^=dHKasXa zfYJs4szRx#fRGzz+GInFmtNdMyml)B$saBbFfcqjoOk>`Z2+Lk46BNHS?2a?^+%zF zNldYf@8!90?p<|eVCwz9&n&+VjBHSjRfVkXR#X_56(AKJ(R@-9Q(PQeEWJIl@YmFW z^$Xw<;QWUG<-rxM;}KaQta&F_Smxv#Q!{U;=6`8>;ctQ4K(KBm6#oVwAD-v6Lzcxz zr5Ds1k0_-mIKhW8|!p$<;OEbg&tmJf#T$K+*{|#OjWx?yO lNC~i3jAa44+IKG>{{)@p^p + + + + + + + + + + + + + + + + + diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/JavaDecompilerPlugin.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/JavaDecompilerPlugin.java new file mode 100644 index 0000000..223b082 --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/JavaDecompilerPlugin.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse; + +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IFileEditorMapping; +import org.eclipse.ui.internal.WorkbenchPlugin; +import org.eclipse.ui.internal.registry.EditorDescriptor; +import org.eclipse.ui.internal.registry.EditorRegistry; +import org.eclipse.ui.internal.registry.FileEditorMapping; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + * + * @project Java Decompiler Eclipse Plugin + * @version 0.1.4 + */ +@SuppressWarnings({ "restriction", "deprecation" }) +public class JavaDecompilerPlugin extends AbstractUIPlugin { + // The plug-in IDs + public static final String PLUGIN_ID = "jd.ide.eclipse"; + private static final String EDITOR_ID = PLUGIN_ID + ".editors.JDClassFileEditor"; + + // Versions + public static final String VERSION_JD_ECLIPSE = "2.0.0"; + public static final String VERSION_JD_CORE = "1.0.7"; + + // Preferences + public static final String PREF_ESCAPE_UNICODE_CHARACTERS = PLUGIN_ID + ".prefs.EscapeUnicodeCharacters"; + public static final String PREF_REALIGN_LINE_NUMBERS = PLUGIN_ID + ".prefs.RealignLineNumbers"; + public static final String PREF_SHOW_LINE_NUMBERS = PLUGIN_ID + ".prefs.ShowLineNumbers"; + public static final String PREF_SHOW_METADATA = PLUGIN_ID + ".prefs.ShowMetadata"; + + // URLs + public static final String URL_JDECLIPSE = "https://github.com/java-decompiler/jd-eclipse"; + + // The shared instance + private static JavaDecompilerPlugin plugin; + + + /** + * The constructor + */ + public JavaDecompilerPlugin() {} + + /** + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + + // Setup ".class" file associations + Display.getDefault().syncExec(new SetupClassFileAssociationRunnable()); + } + + /* + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin.savePluginPreferences(); + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * @return the shared instance + */ + public static JavaDecompilerPlugin getDefault() { + return plugin; + } + + protected static class SetupClassFileAssociationRunnable implements Runnable { + public void run() { + EditorRegistry registry = (EditorRegistry)WorkbenchPlugin.getDefault().getEditorRegistry(); + + IFileEditorMapping[] mappings = registry.getFileEditorMappings(); + IFileEditorMapping c = null; + IFileEditorMapping cws = null; + + // Search Class file editor mappings + for (IFileEditorMapping mapping : mappings) { + if (mapping.getExtension().equals("class")) { + // ... Helios 3.6, Indigo 3.7, Juno 4.2, Kepler 4.3, ... + c = mapping; + } else if (mapping.getExtension().equals("class without source")) { + // Juno 4.2, Kepler 4.3, ... + cws = mapping; + } + } + + if ((c != null) && (cws != null)) { + // Search JD editor descriptor on "class" extension + for (IEditorDescriptor descriptor : c.getEditors()) { + if (descriptor.getId().equals(EDITOR_ID)) { + // Remove JD editor on "class" extension + ((FileEditorMapping)c).removeEditor((EditorDescriptor)descriptor); + + // Set JD as default editor on "class without source" extension + registry.setDefaultEditor("." + cws.getExtension(), descriptor.getId()); + break; + } + } + + // Restore the default editor for "class" extension + IEditorDescriptor defaultClassFileEditor = registry.findEditor(JavaUI.ID_CF_EDITOR); + + if (defaultClassFileEditor != null) { + registry.setDefaultEditor("." + c.getExtension(), JavaUI.ID_CF_EDITOR); + } + + registry.setFileEditorMappings((FileEditorMapping[]) mappings); + registry.saveAssociations(); + } + } + } +} \ No newline at end of file diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/editors/JDClassFileEditor.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/editors/JDClassFileEditor.java new file mode 100644 index 0000000..b0d94e6 --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/editors/JDClassFileEditor.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse.editors; + +import java.io.File; +import java.lang.reflect.Method; +import java.net.URI; +import java.util.Map; + +import org.jd.ide.eclipse.JavaDecompilerPlugin; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.IBuffer; +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.internal.core.BufferManager; +import org.eclipse.jdt.internal.core.ClassFile; +import org.eclipse.jdt.internal.core.PackageFragment; +import org.eclipse.jdt.internal.core.PackageFragmentRoot; +import org.eclipse.jdt.internal.ui.javaeditor.ClassFileEditor; +import org.eclipse.jdt.internal.ui.javaeditor.IClassFileEditorInput; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.ide.FileStoreEditorInput; +import org.eclipse.ui.ide.ResourceUtil; + + +/** + * JDClassFileEditor + * + * @project Java Decompiler Eclipse Plugin + * @version 0.1.4 + * @see org.eclipse.jdt.internal.ui.javaeditor.ClassFileEditor + */ +@SuppressWarnings("restriction") +public class JDClassFileEditor extends ClassFileEditor implements IPropertyChangeListener { + public JDClassFileEditor() { + JavaDecompilerPlugin + .getDefault() + .getPreferenceStore() + .addPropertyChangeListener(this); + } + + @Override + protected void doSetInput(IEditorInput input) throws CoreException { + if (input instanceof IFileEditorInput) { + IFile file = ((IFileEditorInput)input).getFile(); + + if (file instanceof IClassFile) { + IClassFile classFile = (IClassFile)file; + cleanupBuffer(classFile); + setupSourceMapper(classFile); + } + } else if (input instanceof IClassFileEditorInput) { + IClassFileEditorInput classFileEditorInput = (IClassFileEditorInput)input; + IClassFile classFile = classFileEditorInput.getClassFile(); + cleanupBuffer(classFile); + setupSourceMapper(classFile); + } + + super.doSetInput(input); + } + + protected static void cleanupBuffer(IClassFile file) { + IBuffer buffer = BufferManager.getDefaultBufferManager().getBuffer(file); + + if (buffer != null) { + try { + // Remove the buffer + Method method = BufferManager.class.getDeclaredMethod("removeBuffer", new Class[] {IBuffer.class}); + method.setAccessible(true); + method.invoke(BufferManager.getDefaultBufferManager(), new Object[] {buffer}); + } catch (Exception e) { + JavaDecompilerPlugin.getDefault().getLog().log(new Status( + Status.ERROR, JavaDecompilerPlugin.PLUGIN_ID, + 0, e.getMessage(), e)); + } + } + } + + @SuppressWarnings("rawtypes") + protected void setupSourceMapper(IClassFile classFile) { + try { + // Search package fragment root and classPath + IJavaElement packageFragment = classFile.getParent(); + IJavaElement packageFragmentRoot = packageFragment.getParent(); + + if (packageFragmentRoot instanceof PackageFragmentRoot) { + // Setup a new source mapper. + PackageFragmentRoot root = (PackageFragmentRoot)packageFragmentRoot; + + // Location of the archive file containing classes. + IPath basePath = root.getPath(); + File baseFile = basePath.makeAbsolute().toFile(); + + if (!baseFile.exists()) { + IResource resource = root.getCorrespondingResource(); + basePath = resource.getLocation(); + baseFile = basePath.makeAbsolute().toFile(); + } + + // Class path + String classPath = classFile.getElementName(); + String packageName = packageFragment.getElementName(); + if ((packageName != null) && (packageName.length() > 0)) { + classPath = packageName.replace('.', '/') + '/' + classPath; + } + + // Location of the archive file containing source. + IPath sourcePath = root.getSourceAttachmentPath(); + if (sourcePath == null) { + sourcePath = basePath; + } + + // Location of the package fragment root within the zip + // (empty specifies the default root). + IPath sourceAttachmentRootPath = root.getSourceAttachmentRootPath(); + String sourceRootPath; + + if (sourceAttachmentRootPath == null) { + sourceRootPath = null; + } else { + sourceRootPath = sourceAttachmentRootPath.toString(); + if ((sourceRootPath != null) && (sourceRootPath.length() == 0)) + sourceRootPath = null; + } + + // Options + Map options = root.getJavaProject().getOptions(true); + + root.setSourceMapper(new JDSourceMapper(baseFile, sourcePath, sourceRootPath, options)); + } + } catch (CoreException e) { + JavaDecompilerPlugin.getDefault().getLog().log(new Status( + Status.ERROR, JavaDecompilerPlugin.PLUGIN_ID, + 0, e.getMessage(), e)); + } + } + + @Override public boolean isEditable() { return false; } + @Override public boolean isDirty() { return false; } + @Override public boolean isEditorInputReadOnly() { return false; } + + @Override + public void dispose() { + JavaDecompilerPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this); + } + + /** + * Refresh decompiled source code. + * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) + */ + public void propertyChange(PropertyChangeEvent event) { + if (getSourceViewer() != null) { + setInput(getEditorInput()); + } + } +} diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/editors/JDSourceMapper.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/editors/JDSourceMapper.java new file mode 100644 index 0000000..b3339ed --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/editors/JDSourceMapper.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse.editors; + +import java.io.File; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.jd.core.v1.ClassFileToJavaSourceDecompiler; +import org.jd.core.v1.api.loader.Loader; +import org.jd.ide.eclipse.JavaDecompilerPlugin; +import org.jd.ide.eclipse.util.loader.DirectoryLoader; +import org.jd.ide.eclipse.util.loader.ZipLoader; +import org.jd.ide.eclipse.util.printer.LineNumberStringBuilderPrinter; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.internal.core.SourceMapper; +import org.eclipse.jface.preference.IPreferenceStore; + + +/** + * JDSourceMapper + * + * @project Java Decompiler Eclipse Plugin + * @version 0.1.4 + * @see org.eclipse.jdt.internal.core.SourceMapper + */ +@SuppressWarnings("restriction") +public class JDSourceMapper extends SourceMapper { + private final static String JAVA_CLASS_SUFFIX = ".class"; + private final static String JAVA_SOURCE_SUFFIX = ".java"; + private final static int JAVA_SOURCE_SUFFIX_LENGTH = 5; + + private final static ClassFileToJavaSourceDecompiler DECOMPILER = new ClassFileToJavaSourceDecompiler(); + + private File basePath; + + private LineNumberStringBuilderPrinter printer = new LineNumberStringBuilderPrinter(); + + @SuppressWarnings("rawtypes") + public JDSourceMapper(File basePath, IPath sourcePath, String sourceRootPath, Map options) { + super(sourcePath, sourceRootPath, options); + this.basePath = basePath; + } + + @Override + @SuppressWarnings("rawtypes") + public char[] findSource(String javaSourcePath) { + char[] source = null; + + // Search source file + if (this.rootPaths == null) { + source = super.findSource(javaSourcePath); + } else { + Iterator iterator = this.rootPaths.iterator(); + + while (iterator.hasNext() && (source == null)) { + String sourcesRootPath = (String)iterator.next(); + source = super.findSource(sourcesRootPath + IPath.SEPARATOR + javaSourcePath); + } + } + + if ((source == null) && javaSourcePath.toLowerCase().endsWith(JAVA_SOURCE_SUFFIX)) { + String internalTypeName = javaSourcePath.substring(0, javaSourcePath.length()-JAVA_SOURCE_SUFFIX_LENGTH); + + // Decompile class file + try { + source = decompile(this.basePath.getAbsolutePath(), internalTypeName); + } catch (Exception e) { + JavaDecompilerPlugin.getDefault().getLog().log(new Status( + Status.ERROR, JavaDecompilerPlugin.PLUGIN_ID, + 0, e.getMessage(), e)); + } + } + + return source; + } + + /** + * @param basePath Path to the root of the classpath, either a + * path to a directory or a path to a jar file. + * @param internalClassName internal name of the class. + * @return Decompiled class text. + */ + protected char[] decompile(String basePath, String internalTypeName) throws Exception { + // Load preferences + IPreferenceStore store = JavaDecompilerPlugin.getDefault().getPreferenceStore(); + + boolean realignmentLineNumber = store.getBoolean(JavaDecompilerPlugin.PREF_REALIGN_LINE_NUMBERS); + boolean unicodeEscape = store.getBoolean(JavaDecompilerPlugin.PREF_ESCAPE_UNICODE_CHARACTERS); + boolean showLineNumbers = store.getBoolean(JavaDecompilerPlugin.PREF_SHOW_LINE_NUMBERS); + boolean showMetaData = store.getBoolean(JavaDecompilerPlugin.PREF_SHOW_METADATA); + + Map configuration = new HashMap<>(); + configuration.put("realignLineNumbers", realignmentLineNumber); + + // Initialize loader + Loader loader; + File base = new File(basePath); + + if (base.isFile()) { + if (basePath.toLowerCase().endsWith(".jar") || basePath.toLowerCase().endsWith(".zip")) { + loader = new ZipLoader(base); + } else { + JavaDecompilerPlugin.getDefault().getLog().log(new Status( + Status.ERROR, JavaDecompilerPlugin.PLUGIN_ID, + "Unexpected container type file: " + basePath)); + return null; + } + } else { + loader = new DirectoryLoader(base); + } + + // Initialize printer + printer.setRealignmentLineNumber(realignmentLineNumber); + printer.setUnicodeEscape(unicodeEscape); + printer.setShowLineNumbers(showLineNumbers); + + // Decompile class file + DECOMPILER.decompile(loader, printer, internalTypeName, configuration); + + StringBuilder stringBuffer = printer.getStringBuffer(); + + // Metadata + if (showMetaData) { + // Add location + stringBuffer.append("\n\n/* Location: "); + String classPath = internalTypeName + JAVA_CLASS_SUFFIX; + String location = base.isFile() ? base.getPath() + "!/" + classPath : new File(base, classPath).getPath(); + // Escape "\ u" sequence to prevent "Invalid unicode" errors + stringBuffer.append(location.replaceAll("(^|[^\\\\])\\\\u", "\\\\\\\\u")); + // Add Java compiler version + int majorVersion = printer.getMajorVersion(); + if (majorVersion >= 45) { + stringBuffer.append("\n * Java compiler version: "); + + if (majorVersion >= 49) { + stringBuffer.append(majorVersion - (49 - 5)); + } else { + stringBuffer.append(majorVersion - (45 - 1)); + } + + stringBuffer.append(" ("); + stringBuffer.append(majorVersion); + stringBuffer.append('.'); + stringBuffer.append(printer.getMinorVersion()); + stringBuffer.append(')'); + } + // Add JD-Core version + stringBuffer.append("\n * JD-Core Version: "); + stringBuffer.append(JavaDecompilerPlugin.VERSION_JD_CORE); + stringBuffer.append("\n */"); + } + + return stringBuffer.toString().toCharArray(); + } +} diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/preferences/PreferenceInitializer.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/preferences/PreferenceInitializer.java new file mode 100644 index 0000000..2806c75 --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/preferences/PreferenceInitializer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse.preferences; + +import org.jd.ide.eclipse.JavaDecompilerPlugin; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; + +/** + * Class used to initialize default preference values. + * + * @project Java Decompiler Eclipse Plugin + * @version 0.1.3 + */ +public class PreferenceInitializer extends AbstractPreferenceInitializer { + /** + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences() + */ + public void initializeDefaultPreferences() { + IPreferenceStore store = JavaDecompilerPlugin.getDefault().getPreferenceStore(); + store.setDefault(JavaDecompilerPlugin.PREF_ESCAPE_UNICODE_CHARACTERS, false); + store.setDefault(JavaDecompilerPlugin.PREF_REALIGN_LINE_NUMBERS, true); + store.setDefault(JavaDecompilerPlugin.PREF_SHOW_LINE_NUMBERS, true); + store.setDefault(JavaDecompilerPlugin.PREF_SHOW_METADATA, true); + } +} diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/preferences/PreferencePage.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/preferences/PreferencePage.java new file mode 100644 index 0000000..7a092a8 --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/preferences/PreferencePage.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse.preferences; + +import org.jd.ide.eclipse.JavaDecompilerPlugin; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +/** + * PreferencePage + * + * @project Java Decompiler Eclipse Plugin + * @version 0.1.3 + */ +public class PreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { + public PreferencePage() { + super(SWT.NONE); + setDescription("JD-Eclipse preference page"); + } + + /** + * Creates the field editors. Field editors are abstractions of + * the common GUI blocks needed to manipulate various types + * of preferences. Each field editor knows how to save and + * restore itself. + */ + public void createFieldEditors() { + Composite fieldEditorParent = getFieldEditorParent(); + + new Label(fieldEditorParent, SWT.NONE); + + addField(new BooleanFieldEditor( + JavaDecompilerPlugin.PREF_ESCAPE_UNICODE_CHARACTERS, + "Escape unicode characters", fieldEditorParent)); + addField(new BooleanFieldEditor( + JavaDecompilerPlugin.PREF_REALIGN_LINE_NUMBERS, + "Realign line numbers", fieldEditorParent)); + addField(new BooleanFieldEditor( + JavaDecompilerPlugin.PREF_SHOW_LINE_NUMBERS, + "Show original line numbers", fieldEditorParent)); + addField(new BooleanFieldEditor( + JavaDecompilerPlugin.PREF_SHOW_METADATA, + "Show metadata", fieldEditorParent)); + } + + /** + * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + public void init(IWorkbench workbench) { + setPreferenceStore(JavaDecompilerPlugin.getDefault().getPreferenceStore()); + } +} \ No newline at end of file diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/startup/JDStartupClass.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/startup/JDStartupClass.java new file mode 100644 index 0000000..28b18bf --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/startup/JDStartupClass.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse.startup; + +import org.eclipse.ui.IStartup; + +/** + * JDStartupClass + * + * @project Java Decompiler Eclipse Plugin + * @version 0.1.4 + */ +public class JDStartupClass implements IStartup { + public void earlyStartup() {} +} diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/loader/DirectoryLoader.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/loader/DirectoryLoader.java new file mode 100644 index 0000000..9f184cd --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/loader/DirectoryLoader.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse.util.loader; + +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.loader.LoaderException; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class DirectoryLoader implements Loader { + protected File root; + + public DirectoryLoader(File root) throws LoaderException { + this.root = root; + } + + @Override + public byte[] load(String internalName) throws LoaderException { + File file = new File(root, internalName + ".class"); + + try (FileInputStream in=new FileInputStream(file); ByteArrayOutputStream out=new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int read = in.read(buffer); + + while (read > 0) { + out.write(buffer, 0, read); + read = in.read(buffer); + } + + return out.toByteArray(); + } catch (IOException e) { + throw new LoaderException(e); + } + } + + @Override + public boolean canLoad(String internalName) { + return new File(root, internalName + ".class").exists(); + } +} diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/loader/ZipLoader.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/loader/ZipLoader.java new file mode 100644 index 0000000..dab834d --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/loader/ZipLoader.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse.util.loader; + +import org.jd.core.v1.api.loader.Loader; +import org.jd.core.v1.api.loader.LoaderException; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class ZipLoader implements Loader { + protected HashMap map = new HashMap<>(); + + public ZipLoader(File zip) throws LoaderException { + byte[] buffer = new byte[1024 * 2]; + + try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zip))) { + ZipEntry ze = zis.getNextEntry(); + + while (ze != null) { + if (ze.isDirectory() == false) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int read = zis.read(buffer); + + while (read > 0) { + out.write(buffer, 0, read); + read = zis.read(buffer); + } + + map.put(ze.getName(), out.toByteArray()); + } + + ze = zis.getNextEntry(); + } + + zis.closeEntry(); + } catch (IOException e) { + throw new LoaderException(e); + } + } + + @Override + public byte[] load(String internalName) throws LoaderException { + return map.get(internalName + ".class"); + } + + @Override + public boolean canLoad(String internalName) { + return map.containsKey(internalName + ".class"); + } +} diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/printer/LineNumberStringBuilderPrinter.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/printer/LineNumberStringBuilderPrinter.java new file mode 100644 index 0000000..1930949 --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/printer/LineNumberStringBuilderPrinter.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse.util.printer; + +public class LineNumberStringBuilderPrinter extends StringBuilderPrinter { + protected boolean showLineNumbers = false; + + protected int maxLineNumber = 0; + protected int digitCount = 0; + + protected String lineNumberBeginPrefix; + protected String lineNumberEndPrefix; + protected String unknownLineNumberPrefix; + + public void setShowLineNumbers(boolean showLineNumbers) { this.showLineNumbers = showLineNumbers; } + + protected int printDigit(int dcv, int lineNumber, int divisor, int left) { + if (digitCount >= dcv) { + if (lineNumber < divisor) { + stringBuffer.append(' '); + } else { + int e = (lineNumber-left) / divisor; + stringBuffer.append((char)('0' + e)); + left += e*divisor; + } + } + + return left; + } + + // --- Printer --- // + @Override + public void start(int maxLineNumber, int majorVersion, int minorVersion) { + super.start(maxLineNumber, majorVersion, minorVersion); + + if (showLineNumbers) { + this.maxLineNumber = maxLineNumber; + + if (maxLineNumber > 0) { + digitCount = 1; + unknownLineNumberPrefix = " "; + int maximum = 9; + + while (maximum < maxLineNumber) { + digitCount++; + unknownLineNumberPrefix += ' '; + maximum = maximum*10 + 9; + } + + lineNumberBeginPrefix = "/* "; + lineNumberEndPrefix = " */ "; + } else { + unknownLineNumberPrefix = ""; + lineNumberBeginPrefix = ""; + lineNumberEndPrefix = ""; + } + } else { + this.maxLineNumber = 0; + unknownLineNumberPrefix = ""; + lineNumberBeginPrefix = ""; + lineNumberEndPrefix = ""; + } + } + + @Override public void startLine(int lineNumber) { + if (maxLineNumber > 0) { + stringBuffer.append(lineNumberBeginPrefix); + + if (lineNumber == UNKNOWN_LINE_NUMBER) { + stringBuffer.append(unknownLineNumberPrefix); + } else { + int left = 0; + + left = printDigit(5, lineNumber, 10000, left); + left = printDigit(4, lineNumber, 1000, left); + left = printDigit(3, lineNumber, 100, left); + left = printDigit(2, lineNumber, 10, left); + stringBuffer.append((char)('0' + (lineNumber-left))); + } + + stringBuffer.append(lineNumberEndPrefix); + } + + for (int i=0; i 0) { + if (maxLineNumber > 0) { + stringBuffer.append(lineNumberBeginPrefix); + stringBuffer.append(unknownLineNumberPrefix); + stringBuffer.append(lineNumberEndPrefix); + } + + stringBuffer.append(NEWLINE); + } + } + } +} diff --git a/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/printer/StringBuilderPrinter.java b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/printer/StringBuilderPrinter.java new file mode 100644 index 0000000..118720c --- /dev/null +++ b/org.jd.ide.eclipse.plugin/src/org/jd/ide/eclipse/util/printer/StringBuilderPrinter.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2008, 2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.ide.eclipse.util.printer; + +import org.jd.core.v1.api.printer.Printer; + +public class StringBuilderPrinter implements Printer { + protected static final String TAB = " "; + protected static final String NEWLINE = "\n"; + + protected StringBuilder stringBuffer = new StringBuilder(10*1024); + + protected boolean unicodeEscape = true; + protected boolean realignmentLineNumber = false; + + protected int majorVersion = 0; + protected int minorVersion = 0; + protected int indentationCount; + + public void setUnicodeEscape(boolean unicodeEscape) { this.unicodeEscape = unicodeEscape; } + public void setRealignmentLineNumber(boolean realignmentLineNumber) { this.realignmentLineNumber = realignmentLineNumber; } + + public int getMajorVersion() { return majorVersion; } + public int getMinorVersion() { return minorVersion; } + public StringBuilder getStringBuffer() { return stringBuffer; } + + protected void escape(String s) { + if (unicodeEscape && (s != null)) { + int length = s.length(); + + for (int i=0; i> 3))); + stringBuffer.append((char) ('0' + (c & 0x7))); + } else if (c > 127) { + // Write octal format + stringBuffer.append("\\u"); + + int z = (c >> 12); + stringBuffer.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + z = ((c >> 8) & 0xF); + stringBuffer.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + z = ((c >> 4) & 0xF); + stringBuffer.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + z = (c & 0xF); + stringBuffer.append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + } else { + stringBuffer.append(c); + } + } + } else { + stringBuffer.append(s); + } + } + + // --- Printer --- // + @Override + public void start(int maxLineNumber, int majorVersion, int minorVersion) { + this.stringBuffer.setLength(0); + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + this.indentationCount = 0; + } + + @Override public void end() {} + + @Override public void printText(String text) { escape(text); } + @Override public void printNumericConstant(String constant) { escape(constant); } + @Override public void printStringConstant(String constant, String ownerInternalName) { escape(constant); } + @Override public void printKeyword(String keyword) { stringBuffer.append(keyword); } + + @Override public void printDeclaration(int type, String internalTypeName, String name, String descriptor) { escape(name); } + @Override public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) { escape(name); } + + @Override public void indent() { indentationCount++; } + @Override public void unindent() { if (indentationCount > 0) indentationCount--; } + + @Override public void startLine(int lineNumber) { for (int i=0; i 0) stringBuffer.append(NEWLINE); } + + @Override public void startMarker(int type) {} + @Override public void endMarker(int type) {} +} diff --git a/org.jd.ide.eclipse.site/.project b/org.jd.ide.eclipse.site/.project new file mode 100644 index 0000000..7862459 --- /dev/null +++ b/org.jd.ide.eclipse.site/.project @@ -0,0 +1,17 @@ + + + jd.ide.eclipse.site + + + + + + org.eclipse.pde.UpdateSiteBuilder + + + + + + org.eclipse.pde.UpdateSiteNature + + diff --git a/org.jd.ide.eclipse.site/site.xml b/org.jd.ide.eclipse.site/site.xml new file mode 100644 index 0000000..91c5031 --- /dev/null +++ b/org.jd.ide.eclipse.site/site.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/settings.gradle b/settings.gradle index ea0e698..65c50a0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include 'jd.ide.eclipse.plugin', 'jd.ide.eclipse.feature' +include 'org.jd.ide.eclipse.plugin', 'org.jd.ide.eclipse.feature'