-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathjar_utils.mjs
executable file
·88 lines (70 loc) · 2.55 KB
/
jar_utils.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
* Utilities to deal with class files since java-class-tools is a bit barebone.
*/
import JSZip from "npm:jszip";
import { Modifier } from "npm:java-class-tools";
import * as enigma from "./enigma_mappings.mjs";
import * as java from "./java.mjs"
const TEXT_DECODER = new TextDecoder();
export async function load_file(path) {
return new JarFile(await JSZip.loadAsync(Deno.readFileSync(path), {base64: false, checkCRC32: false}));
}
export class JarFile {
classes = [];
constructor(zip) {
this.jar = zip;
}
/**
* Loads the given class file from this JAR file.
*
* @param {enigma.Class|string} clazz the class to load
* @returns
*/
async load_class(clazz) {
if (clazz instanceof enigma.Class) {
clazz = clazz.toString();
}
if (this.classes[clazz])
return this.classes[clazz];
const path = clazz + ".class";
const file = this.jar.files[path];
return this.classes[clazz] = new ClassFile(java.CLASS_FILE_READER.read(await file.async("uint8array")));
}
}
export class ClassFile {
_methods = undefined;
constructor(class_file) {
this.class_file = class_file;
}
find_method(name, descriptor) {
if (!this._methods) {
this._methods = this.class_file.methods.map(class_method => {
const name = TEXT_DECODER.decode(new Uint8Array(this.class_file.constant_pool[class_method.name_index].bytes));
const raw_descriptor = TEXT_DECODER.decode(new Uint8Array(this.class_file.constant_pool[class_method.descriptor_index].bytes));
const descriptor = java.parse_function_descriptor(raw_descriptor);
return new ClassMethod(this, name, descriptor, class_method);
});
}
return this._methods.find(class_method => name === class_method.name && descriptor.equals(class_method.descriptor));
}
find_method_from_enigma(method) {
return this.find_method(method.intermediary, method.descriptor);
}
}
export class ClassMethod {
constructor(owner, name, descriptor, raw) {
this.owner = owner;
this.name = name;
this.descriptor = descriptor;
this.raw = raw;
}
is_static() {
return (this.raw.access_flags & Modifier.STATIC) > 0;
}
attribute_names() {
return this.raw.attributes.map(attr => {
const name = TEXT_DECODER.decode(new Uint8Array(this.owner.class_file.constant_pool[attr.attribute_name_index].bytes));
return name;
})
}
}