Skip to content

Instantly share code, notes, and snippets.

@borkdude
Last active April 10, 2022 16:47
Show Gist options
  • Save borkdude/d02dc3ff1d03d09351e768964983a46b to your computer and use it in GitHub Desktop.
Save borkdude/d02dc3ff1d03d09351e768964983a46b to your computer and use it in GitHub Desktop.
Retrieve the package string from a .class file
(require '[clojure.java.io :as io]
'[clojure.string :as str])
(defn class->package
"Implementation by Marco Marini."
[class-file]
(with-open [dis (java.io.DataInputStream. (io/input-stream class-file))]
;; skip first 8 bytes
(.skipBytes dis 8)
(let [constant-pool-count (.readUnsignedShort dis)
[strings classes]
(loop [counter 1
classes {}
strings {}]
(if (< counter constant-pool-count)
(case (.read dis)
1 (recur (inc counter) classes (assoc strings counter (.readUTF dis)))
(5 6) (do (.skipBytes dis 8)
(recur (+ 2 counter) classes strings))
7 (recur (inc counter) (assoc classes counter (.readUnsignedShort dis)) strings)
(8 16 19 20) (do (.skipBytes dis 2)
(recur (inc counter) classes strings))
15 (do (.skipBytes dis 3) (recur (inc counter) classes strings))
(do (.skipBytes dis 4)
(recur (inc counter) classes strings)))
[strings classes]))]
;; skip access flags
(.skipBytes dis 2)
;; (prn (get @classes (.readUnsignedShort dis)))
(str/join
"."
(butlast
(str/split
(get strings (get classes (.readUnsignedShort dis)))
#"/"))))))
;; echo 'package foo.bar; public class Baz { }' > Baz.java
;; javac Baz.java
;; bb pkg.clj Baz.class
(prn (class->package (first *command-line-args*))) ;;=> "foo.bar"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment