Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# Include .class files as test sources
!*.class
!*.class
*-autoloads.el
*-pkg.el
*.elc
64 changes: 37 additions & 27 deletions jdecomp.el
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
;; Keywords: decompile, java, languages, tools
;; Package-Requires: ((emacs "24.5"))
;; URL: https://github.com/xiongtx/jdecomp
;; Version: 0.2.0
;; Version: 0.2.1

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -47,9 +47,9 @@
"Type of Java decompiler to use."
:group 'jdecomp
:type '(radio
(const :tag "CFR" 'cfr)
(const :tag "Fernflower" 'fernflower)
(const :tag "Procyon" 'procyon)))
(const :tag "CFR" cfr)
(const :tag "Fernflower" fernflower)
(const :tag "Procyon" procyon)))

(defcustom jdecomp-decompiler-paths nil
"Alist of Java decompiler types and their paths."
Expand All @@ -63,6 +63,11 @@
:options '(cfr fernflower procyon)
:type '(alist :key-type symbol :value-type (repeat string)))

(defcustom jdecomp-java-program "java"
"Path to the Java executable."
:group 'jdecomp
:type 'string)


;;;; Utilities

Expand Down Expand Up @@ -173,10 +178,10 @@ Optional parameter DECOMPILER-TYPE defaults to
`jdecomp-decompiler-type'."
(condition-case nil
(cl-ecase decompiler-type
('cfr #'jdecomp--cfr-command)
('fernflower #'jdecomp--fernflower-command)
('procyon #'jdecomp--procyon-command))
(error (user-error "%s is not a known decompiler" decompiler-type))))
(cfr #'jdecomp--cfr-command)
(fernflower #'jdecomp--fernflower-command)
(procyon #'jdecomp--procyon-command))
(user-error "%s is not a known decompiler" decompiler-type)))

(cl-defun jdecomp--ensure-decompiler (&optional (decompiler-type jdecomp-decompiler-type))
"Ensure that the decompiler for DECOMPILER-TYPE is available.
Expand All @@ -185,10 +190,10 @@ Optional parameter DECOMPILER-TYPE defaults to
`jdecomp-decompiler-type'."
(unless (condition-case nil
(cl-ecase decompiler-type
('cfr (jdecomp--jar-p (jdecomp--decompiler-path 'cfr)))
('fernflower (jdecomp--jar-p (jdecomp--decompiler-path 'fernflower)))
('procyon (jdecomp--jar-p (jdecomp--decompiler-path 'procyon))))
(error (user-error "%s is not a known decompiler" decompiler-type)))
(cfr (jdecomp--jar-p (jdecomp--decompiler-path 'cfr)))
(fernflower (jdecomp--jar-p (jdecomp--decompiler-path 'fernflower)))
(procyon (jdecomp--jar-p (jdecomp--decompiler-path 'procyon))))
(user-error "%s is not a known decompiler" decompiler-type))
(user-error "%s decompiler is not available" decompiler-type)))

(defun jdecomp--cfr-command (file &optional jar)
Expand All @@ -201,7 +206,7 @@ applicable."
(jdecomp--ensure-decompiler 'cfr)
(with-output-to-string
(let ((classpath (or jar (file-name-directory file) default-directory)))
(apply #'call-process "java" nil standard-output nil
(apply #'call-process jdecomp-java-program nil standard-output nil
`("-jar" ,(expand-file-name (jdecomp--decompiler-path 'cfr))
"--extraclasspath" ,classpath
,@(jdecomp--decompiler-options 'cfr)
Expand All @@ -219,18 +224,23 @@ was extracted from a JAR with `jdecomp--extract-to-file'."
(let* ((classpath (or (file-name-directory file) default-directory))
(destination (if extracted-p
(file-name-directory file)
(jdecomp--make-temp-file (concat "jdecomp" (file-name-sans-extension file)) t))))
;; The java-decompiler.jar is not executable
;; See: http://stackoverflow.com/a/39868281/864684
(apply #'call-process "java" nil nil nil
`("-cp" ,(expand-file-name (jdecomp--decompiler-path 'fernflower))
"org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler"
"-cp" ,classpath
,@(jdecomp--decompiler-options 'fernflower)
,file
,destination))
(insert-file-contents (cl-first (jdecomp--java-files destination)))
(buffer-string))))
(jdecomp--make-temp-file (concat "jdecomp" (file-name-sans-extension file)) t)))
(process-out (with-temp-buffer
;; The java-decompiler.jar is not executable
;; See: http://stackoverflow.com/a/39868281/864684
(apply #'call-process jdecomp-java-program nil (current-buffer) nil
`("-cp" ,(expand-file-name (jdecomp--decompiler-path 'fernflower))
"org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler"
"-cp" ,classpath
,@(jdecomp--decompiler-options 'fernflower)
,file
,destination))
(buffer-string))))
(if-let (decompiled-file (cl-first (jdecomp--java-files destination)))
(progn
(insert-file-contents decompiled-file)
(buffer-string))
(error "Failed to decompile %s\n%s" file process-out)))))

(defun jdecomp--fernflower-decompile-file-in-jar (file jar)
"Decompile FILE with Fernflower and return result as string.
Expand Down Expand Up @@ -262,7 +272,7 @@ Optional parameter EXTRACTED-P, when non-nil, indicates that FILE
was extracted from a JAR with `jdecomp--extract-to-file'."
(jdecomp--ensure-decompiler 'procyon)
(with-output-to-string
(apply #'call-process "java" nil standard-output nil
(apply #'call-process jdecomp-java-program nil standard-output nil
`("-jar" ,(expand-file-name (jdecomp--decompiler-path 'procyon))
,@(jdecomp--decompiler-options 'procyon)
,file))))
Expand Down Expand Up @@ -332,7 +342,7 @@ Optional parameter JAR is the name of the JAR archive FILE is
in."
;; Check that FILE is a class file
(unless (jdecomp--classfile-p file)
(user-error (format "%s is not a Java class file" file)))
(user-error "%s is not a Java class file" file))

(let ((result (funcall (jdecomp--decompile-command) file jar))
(buf (get-buffer-create (jdecomp--decompiled-buffer-name file))))
Expand Down