Skip to content

Commit 3f56263

Browse files
committed
Fix multiply-nested inner classes for Fernflower, also optimize
1 parent 3aad2a6 commit 3f56263

File tree

2 files changed

+22
-48
lines changed

2 files changed

+22
-48
lines changed

src/main/java/the/bytecode/club/jda/JDA.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import org.objectweb.asm.ClassReader;
55
import org.objectweb.asm.ClassWriter;
66
import org.objectweb.asm.tree.ClassNode;
7-
import org.objectweb.asm.tree.InnerClassNode;
87
import the.bytecode.club.jda.api.ExceptionUI;
98
import the.bytecode.club.jda.api.Plugin;
109
import the.bytecode.club.jda.api.PluginLoader;
@@ -197,18 +196,14 @@ public static byte[] getFileBytes(String containerName, String name) {
197196
public static byte[] getClassBytes(String containerName, ClassNode cn) {
198197
byte[] bytes = getFileBytes(containerName, getClassfileName(cn));
199198
if (cn.version < 49)
200-
bytes = fixBytes(bytes);
199+
bytes = fixBytes(bytes); // this is inefficient!
201200
return bytes;
202201
}
203202

204203
public static final String HACK_PREFIX = "\0JDA-hack";
205204

206205
public static File getClassFileProxy(ClassNode cn) {
207-
return new File('/' + HACK_PREFIX, cn.name + ".class");
208-
}
209-
210-
public static File getClassFileProxy(InnerClassNode cn) {
211-
return new File('/' + HACK_PREFIX, cn.name + ".class");
206+
return new File('/' + HACK_PREFIX, getClassfileName(cn));
212207
}
213208

214209
public static String getClassfileName(ClassNode cn) {

src/main/java/the/bytecode/club/jda/decompilers/FernflowerDecompiler.java

Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,21 @@
11
package the.bytecode.club.jda.decompilers;
22

3-
import org.apache.commons.io.FileUtils;
43
import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler;
5-
import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler;
64
import org.jetbrains.java.decompiler.main.decompiler.PrintStreamLogger;
75
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
86
import org.objectweb.asm.tree.ClassNode;
97
import org.objectweb.asm.tree.InnerClassNode;
108
import the.bytecode.club.jda.JDA;
11-
import the.bytecode.club.jda.JarUtils;
129
import the.bytecode.club.jda.settings.JDADecompilerSettings.SettingsEntry;
1310
import the.bytecode.club.jda.settings.Setting;
1411

15-
import java.io.File;
16-
import java.nio.file.Files;
17-
import java.nio.file.Path;
18-
import java.util.HashMap;
19-
import java.util.Map;
12+
import java.io.IOException;
13+
import java.util.*;
2014
import java.util.concurrent.atomic.AtomicReference;
2115
import java.util.jar.Manifest;
2216

2317
import static org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences.*;
2418

25-
/**
26-
* A FernFlower wrapper with all the options (except 2)
27-
*
28-
* @author Konloch
29-
* @author WaterWolf
30-
*/
31-
3219
public final class FernflowerDecompiler extends JDADecompiler {
3320
public FernflowerDecompiler() {
3421
settings.registerSetting(new SettingsEntry(REMOVE_BRIDGE, "Hide Bridge Methods", false));
@@ -76,12 +63,9 @@ public String decompileClassNode(String containerName, final ClassNode cn) {
7663
ClassNode requestedCn = JDA.getClassNode(containerName, JDA.extractProxyClassName(externalPath));
7764
if (requestedCn == null) {
7865
System.err.println("Couldn't load " + externalPath);
79-
return new byte[0];
66+
throw new IOException(containerName + "$" + cn + " is missing");
8067
}
81-
byte[] bytes = JDA.getClassBytes(containerName, requestedCn);
82-
byte[] clone = new byte[bytes.length];
83-
System.arraycopy(bytes, 0, clone, 0, bytes.length);
84-
return clone;
68+
return JDA.getClassBytes(containerName, requestedCn);
8569
}, new IResultSaver() {
8670
@Override
8771
public void saveFolder(String s) {
@@ -124,15 +108,23 @@ public void closeArchive(String s, String s1) {
124108
}
125109
}, options, new PrintStreamLogger(System.out));
126110

127-
baseDecompiler.addSpace(JDA.getClassFileProxy(cn), true);
128-
for (InnerClassNode innerCn : cn.innerClasses)
129-
baseDecompiler.addSpace(JDA.getClassFileProxy(innerCn), true);
130-
baseDecompiler.decompileContext();
131-
while (true) {
132-
if (result.get() != null) {
133-
break;
111+
// DFS for inner classes
112+
Set<ClassNode> visited = new HashSet<>(); // necessary apparently...
113+
ArrayDeque<ClassNode> fifo = new ArrayDeque<>();
114+
fifo.add(cn);
115+
while (!fifo.isEmpty()) {
116+
ClassNode curCn = fifo.pop();
117+
visited.add(curCn);
118+
baseDecompiler.addSpace(JDA.getClassFileProxy(curCn), true);
119+
for (InnerClassNode innerClass : curCn.innerClasses) {
120+
ClassNode innerCn = JDA.getClassNode(containerName, innerClass.name);
121+
if (innerCn != null && !visited.contains(innerCn)) {
122+
fifo.add(innerCn);
123+
}
134124
}
135125
}
126+
127+
baseDecompiler.decompileContext();
136128
return result.get();
137129
} catch (Exception e) {
138130
return parseException(e);
@@ -141,20 +133,7 @@ public void closeArchive(String s, String s1) {
141133

142134
@Override
143135
public void decompileToZip(String zipName) {
144-
try {
145-
Path outputDir = Files.createTempDirectory("fernflower_output");
146-
Path tempJar = Files.createTempFile("fernflower_input", ".jar");
147-
File output = new File(zipName);
148-
JarUtils.saveAsJar(JDA.getLoadedBytes(), tempJar.toAbsolutePath().toString());
149-
ConsoleDecompiler decompiler = new ConsoleDecompiler(outputDir.toFile(), generateFernflowerArgs());
150-
decompiler.addSpace(tempJar.toFile(), true);
151-
decompiler.decompileContext();
152-
Files.move(outputDir.toFile().listFiles()[0].toPath(), output.toPath());
153-
Files.delete(tempJar);
154-
FileUtils.deleteDirectory(outputDir.toFile());
155-
} catch (Exception e) {
156-
handleException(e);
157-
}
136+
throw new UnsupportedOperationException();
158137
}
159138

160139
private Map<String, Object> generateFernflowerArgs() {

0 commit comments

Comments
 (0)