Merge branch 'master' of https://github.com/Konloch/bytecode-viewer
This commit is contained in:
commit
80a3e8b7f0
10 changed files with 408 additions and 442 deletions
6
pom.xml
6
pom.xml
|
@ -31,8 +31,8 @@
|
|||
<darklaf.version>2.7.3</darklaf.version>
|
||||
<darklaf-extensions-rsta.version>0.3.4</darklaf-extensions-rsta.version>
|
||||
<decompiler-fernflower.version>5.2.1.Final</decompiler-fernflower.version>
|
||||
<dex2jar.version>v45</dex2jar.version>
|
||||
<fernflower.version>b803ad9</fernflower.version>
|
||||
<dex2jar.version>v46</dex2jar.version>
|
||||
<fernflower.version>5a2b2cc</fernflower.version>
|
||||
<gson.version>2.9.0</gson.version>
|
||||
<guava.version>31.0.1-jre</guava.version>
|
||||
<imgscalr-lib.version>4.2</imgscalr-lib.version>
|
||||
|
@ -44,7 +44,7 @@
|
|||
<objenesis.version>3.2</objenesis.version>
|
||||
<paged-data.version>0.2.0</paged-data.version>
|
||||
<procyon.version>0.6.0</procyon.version>
|
||||
<rsyntaxtextarea.version>3.1.6</rsyntaxtextarea.version>
|
||||
<rsyntaxtextarea.version>3.2.0</rsyntaxtextarea.version>
|
||||
<semantic-version.version>2.1.1</semantic-version.version>
|
||||
<slf4j.version>1.7.36</slf4j.version>
|
||||
<smali.version>2.5.2</smali.version>
|
||||
|
|
|
@ -117,7 +117,7 @@ public class InstructionPrinter {
|
|||
info.add("}");
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
public String printInstruction(AbstractInsnNode ain)
|
||||
{
|
||||
String line = "";
|
||||
|
@ -136,15 +136,15 @@ public class InstructionPrinter {
|
|||
} else if (ain instanceof JumpInsnNode) {
|
||||
line = printJumpInsnNode((JumpInsnNode) ain);
|
||||
} else if (ain instanceof LineNumberNode) {
|
||||
line = printLineNumberNode();
|
||||
line = printLineNumberNode((LineNumberNode) ain);
|
||||
} else if (ain instanceof LabelNode) {
|
||||
if (firstLabel
|
||||
&& BytecodeViewer.viewer.appendBracketsToLabels
|
||||
.isSelected())
|
||||
info.add("}");
|
||||
|
||||
|
||||
line = printLabelnode((LabelNode) ain);
|
||||
|
||||
|
||||
if (BytecodeViewer.viewer.appendBracketsToLabels.isSelected()) {
|
||||
if (!firstLabel)
|
||||
firstLabel = true;
|
||||
|
@ -168,7 +168,7 @@ public class InstructionPrinter {
|
|||
line += "UNADDED OPCODE: " + nameOpcode(ain.getOpcode()) + " "
|
||||
+ ain;
|
||||
}
|
||||
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
|
@ -245,8 +245,8 @@ public class InstructionPrinter {
|
|||
+ resolveLabel(jin.label);
|
||||
}
|
||||
|
||||
protected String printLineNumberNode() {
|
||||
return "";
|
||||
protected String printLineNumberNode(LineNumberNode lnn) {
|
||||
return "// line " + lnn.line;
|
||||
}
|
||||
|
||||
protected String printLabelnode(LabelNode label) {
|
||||
|
|
|
@ -1,29 +1,43 @@
|
|||
package the.bytecode.club.bytecodeviewer.decompilers.impl;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Random;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import me.konloch.kontainer.io.DiskReader;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.benf.cfr.reader.api.CfrDriver;
|
||||
import org.benf.cfr.reader.api.ClassFileSource;
|
||||
import org.benf.cfr.reader.api.OutputSinkFactory;
|
||||
import org.benf.cfr.reader.api.SinkReturns;
|
||||
import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
|
||||
import org.benf.cfr.reader.state.ClassFileSourceImpl;
|
||||
import org.benf.cfr.reader.util.getopt.Options;
|
||||
import org.benf.cfr.reader.util.getopt.OptionsImpl;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||
import the.bytecode.club.bytecodeviewer.decompilers.InternalDecompiler;
|
||||
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
|
||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.fs;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.nl;
|
||||
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.CFR;
|
||||
import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR;
|
||||
|
||||
|
@ -48,313 +62,193 @@ import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERR
|
|||
/**
|
||||
* CFR Java Wrapper
|
||||
*
|
||||
* @author Konloch
|
||||
* @author GraxCode
|
||||
* Taken mostly out of Threadtear.
|
||||
*/
|
||||
public class CFRDecompiler extends InternalDecompiler {
|
||||
|
||||
public class CFRDecompiler extends InternalDecompiler
|
||||
{
|
||||
private static final String CLASS_SUFFIX = ".class";
|
||||
|
||||
private static final String[] WINDOWS_IS_GREAT = new String[]
|
||||
{
|
||||
"CON",
|
||||
"PRN",
|
||||
"AUX",
|
||||
"NUL",
|
||||
"COM1",
|
||||
"COM2",
|
||||
"COM3",
|
||||
"COM4",
|
||||
"COM5",
|
||||
"COM6",
|
||||
"COM7",
|
||||
"COM8",
|
||||
"COM9",
|
||||
"LPT1",
|
||||
"LPT2",
|
||||
"LPT3",
|
||||
"LPT4",
|
||||
"LPT5",
|
||||
"LPT6",
|
||||
"LPT7",
|
||||
"LPT8",
|
||||
"LPT9"
|
||||
};
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] content) {
|
||||
return decompile(cn, cn.name, content);
|
||||
}
|
||||
|
||||
public static String windowsFun(String base) {
|
||||
for (String s : WINDOWS_IS_GREAT) {
|
||||
if (base.contains(s.toLowerCase())) {
|
||||
base = base.replace(s.toLowerCase(), "BCV");
|
||||
}
|
||||
private String decompile(ClassNode cn, String name, byte[] content) {
|
||||
try {
|
||||
String classPath = name + (name.endsWith(CLASS_SUFFIX) ? "" : CLASS_SUFFIX);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Consumer<SinkReturns.Decompiled> dumpDecompiled = d -> builder.append(d.getJava());
|
||||
|
||||
Options options = generateOptions();
|
||||
ClassFileSource source = new BCVDataSource(options, cn, classPath, content);
|
||||
CfrDriver driver = new CfrDriver.Builder()
|
||||
.withClassFileSource(source)
|
||||
.withBuiltOptions(options)
|
||||
.withOutputSink(new BCVOutputSinkFactory(dumpDecompiled))
|
||||
.build();
|
||||
driver.analyse(Collections.singletonList(name));
|
||||
|
||||
return builder.toString();
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
t.printStackTrace(pw);
|
||||
return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + sw;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decompileClassNode(ClassNode cn, byte[] b) {
|
||||
String fileStart = tempDirectory + fs.toLowerCase();
|
||||
public void decompileToZip(String sourceJar, String outJar) {
|
||||
try (JarFile jfile = new JarFile(new File(sourceJar));
|
||||
FileOutputStream dest = new FileOutputStream(outJar);
|
||||
BufferedOutputStream buffDest = new BufferedOutputStream(dest);
|
||||
ZipOutputStream out = new ZipOutputStream(buffDest)) {
|
||||
byte[] data = new byte[1024];
|
||||
|
||||
String exception = "";
|
||||
//final File tempClass = new File(windowsFun(MiscUtils.getUniqueName(fileStart, ".class") + ".class"));
|
||||
final File tempClass = new File(MiscUtils.getUniqueName(fileStart, ".class") + ".class");
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(tempClass)) {
|
||||
fos.write(b);
|
||||
} catch (final IOException e) {
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
String fuckery = fuckery(fileStart);
|
||||
|
||||
/*if (!BytecodeViewer.fatJar) {
|
||||
try {
|
||||
ProcessBuilder pb = new ProcessBuilder(ArrayUtils.addAll(
|
||||
new String[]{BytecodeViewer.getJavaCommand(), "-jar", Resources.findLibrary("cfr")},
|
||||
generateMainMethod(tempClass.getAbsolutePath(), fuckery)
|
||||
));
|
||||
BytecodeViewer.sm.stopBlocking();
|
||||
Process p = pb.start();
|
||||
BytecodeViewer.createdProcesses.add(p);
|
||||
p.waitFor();
|
||||
} catch (Exception e) {
|
||||
BytecodeViewer.handleException(e);
|
||||
} finally {
|
||||
BytecodeViewer.sm.setBlocking();
|
||||
}
|
||||
} else {
|
||||
org.benf.cfr.reader.Main.main(generateMainMethod(tempClass.getAbsolutePath(), fuckery));
|
||||
}*/
|
||||
|
||||
try {
|
||||
org.benf.cfr.reader.Main.main(generateMainMethod(tempClass.getAbsolutePath(), fuckery));
|
||||
} catch (StackOverflowError | Exception e) {
|
||||
StringWriter exceptionWriter = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
||||
e.printStackTrace();
|
||||
exception = exceptionWriter.toString();
|
||||
}
|
||||
|
||||
tempClass.delete();
|
||||
File file = new File(fuckery);
|
||||
|
||||
if (file.exists())
|
||||
return findFile(MiscUtils.listFiles(file));
|
||||
|
||||
return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + exception;
|
||||
}
|
||||
|
||||
Random r = new Random();
|
||||
File f;
|
||||
|
||||
public String fuckery(String start) {
|
||||
while (true) {
|
||||
f = new File(start + r.nextInt(Integer.MAX_VALUE));
|
||||
if (!f.exists())
|
||||
return f.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public String findFile(File[] fA) {
|
||||
for (File f : fA) {
|
||||
if (f.isDirectory())
|
||||
return findFile(MiscUtils.listFiles(f));
|
||||
else {
|
||||
String s;
|
||||
try {
|
||||
s = DiskReader.loadAsString(f.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
StringWriter exceptionWriter = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(exceptionWriter));
|
||||
e.printStackTrace();
|
||||
|
||||
return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR +
|
||||
nl + nl + exceptionWriter;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return "CFR error!" +
|
||||
nl + nl + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR;
|
||||
}
|
||||
|
||||
public String[] generateMainMethod(String filePath, String outputPath) {
|
||||
return new String[]{
|
||||
filePath,
|
||||
"--outputdir",
|
||||
outputPath,
|
||||
"--decodeenumswitch",
|
||||
String.valueOf(BytecodeViewer.viewer.decodeEnumSwitch
|
||||
.isSelected()),
|
||||
"--sugarenums",
|
||||
String.valueOf(BytecodeViewer.viewer.sugarEnums.isSelected()),
|
||||
"--decodestringswitch",
|
||||
String.valueOf(BytecodeViewer.viewer.decodeStringSwitch
|
||||
.isSelected()),
|
||||
"--arrayiter",
|
||||
String.valueOf(BytecodeViewer.viewer.arrayiter.isSelected()),
|
||||
"--collectioniter",
|
||||
String.valueOf(BytecodeViewer.viewer.collectioniter
|
||||
.isSelected()),
|
||||
"--innerclasses",
|
||||
String.valueOf(BytecodeViewer.viewer.innerClasses.isSelected()),
|
||||
"--removeboilerplate",
|
||||
String.valueOf(BytecodeViewer.viewer.removeBoilerPlate
|
||||
.isSelected()),
|
||||
"--removeinnerclasssynthetics",
|
||||
String.valueOf(BytecodeViewer.viewer.removeInnerClassSynthetics
|
||||
.isSelected()),
|
||||
"--decodelambdas",
|
||||
String.valueOf(BytecodeViewer.viewer.decodeLambdas.isSelected()),
|
||||
"--hidebridgemethods",
|
||||
String.valueOf(BytecodeViewer.viewer.hideBridgeMethods
|
||||
.isSelected()),
|
||||
"--liftconstructorinit",
|
||||
String.valueOf(BytecodeViewer.viewer.liftConstructorInit
|
||||
.isSelected()),
|
||||
"--removedeadmethods",
|
||||
String.valueOf(BytecodeViewer.viewer.removeDeadMethods
|
||||
.isSelected()),
|
||||
"--removebadgenerics",
|
||||
String.valueOf(BytecodeViewer.viewer.removeBadGenerics
|
||||
.isSelected()),
|
||||
"--sugarasserts",
|
||||
String.valueOf(BytecodeViewer.viewer.sugarAsserts.isSelected()),
|
||||
"--sugarboxing",
|
||||
String.valueOf(BytecodeViewer.viewer.sugarBoxing.isSelected()),
|
||||
"--showversion",
|
||||
String.valueOf(BytecodeViewer.viewer.showVersion.isSelected()),
|
||||
"--decodefinally",
|
||||
String.valueOf(BytecodeViewer.viewer.decodeFinally.isSelected()),
|
||||
"--tidymonitors",
|
||||
String.valueOf(BytecodeViewer.viewer.tidyMonitors.isSelected()),
|
||||
"--lenient",
|
||||
String.valueOf(BytecodeViewer.viewer.lenient.isSelected()),
|
||||
"--dumpclasspath",
|
||||
String.valueOf(BytecodeViewer.viewer.dumpClassPath.isSelected()),
|
||||
"--comments",
|
||||
String.valueOf(BytecodeViewer.viewer.comments.isSelected()),
|
||||
"--forcetopsort",
|
||||
String.valueOf(BytecodeViewer.viewer.forceTopSort.isSelected()),
|
||||
"--forcetopsortaggress",
|
||||
String.valueOf(BytecodeViewer.viewer.forceTopSortAggress
|
||||
.isSelected()),
|
||||
"--stringbuffer",
|
||||
String.valueOf(BytecodeViewer.viewer.stringBuffer.isSelected()),
|
||||
"--stringbuilder",
|
||||
String.valueOf(BytecodeViewer.viewer.stringBuilder.isSelected()),
|
||||
"--silent",
|
||||
String.valueOf(BytecodeViewer.viewer.silent.isSelected()),
|
||||
"--recover",
|
||||
String.valueOf(BytecodeViewer.viewer.recover.isSelected()),
|
||||
"--eclipse",
|
||||
String.valueOf(BytecodeViewer.viewer.eclipse.isSelected()),
|
||||
"--override",
|
||||
String.valueOf(BytecodeViewer.viewer.override.isSelected()),
|
||||
"--showinferrable",
|
||||
String.valueOf(BytecodeViewer.viewer.showInferrable
|
||||
.isSelected()),
|
||||
"--aexagg",
|
||||
String.valueOf(BytecodeViewer.viewer.aexagg.isSelected()),
|
||||
"--forcecondpropagate",
|
||||
String.valueOf(BytecodeViewer.viewer.forceCondPropagate
|
||||
.isSelected()),
|
||||
"--hideutf",
|
||||
String.valueOf(BytecodeViewer.viewer.hideUTF.isSelected()),
|
||||
"--hidelongstrings",
|
||||
String.valueOf(BytecodeViewer.viewer.hideLongStrings
|
||||
.isSelected()),
|
||||
"--commentmonitors",
|
||||
String.valueOf(BytecodeViewer.viewer.commentMonitor
|
||||
.isSelected()),
|
||||
"--allowcorrecting",
|
||||
String.valueOf(BytecodeViewer.viewer.allowCorrecting
|
||||
.isSelected()),
|
||||
"--labelledblocks",
|
||||
String.valueOf(BytecodeViewer.viewer.labelledBlocks
|
||||
.isSelected()),
|
||||
"--j14classobj",
|
||||
String.valueOf(BytecodeViewer.viewer.j14ClassOBJ.isSelected()),
|
||||
"--hidelangimports",
|
||||
String.valueOf(BytecodeViewer.viewer.hideLangImports
|
||||
.isSelected()),
|
||||
"--recovertypeclash",
|
||||
String.valueOf(BytecodeViewer.viewer.recoveryTypeClash
|
||||
.isSelected()),
|
||||
"--recovertypehints",
|
||||
String.valueOf(BytecodeViewer.viewer.recoveryTypehInts
|
||||
.isSelected()),
|
||||
"--forcereturningifs",
|
||||
String.valueOf(BytecodeViewer.viewer.forceTurningIFs
|
||||
.isSelected()),
|
||||
"--forloopaggcapture",
|
||||
String.valueOf(BytecodeViewer.viewer.forLoopAGGCapture
|
||||
.isSelected()),};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decompileToZip(String sourceJar, String zipName) {
|
||||
File tempZip = new File(sourceJar);
|
||||
|
||||
String fileStart = tempDirectory + fs;
|
||||
String fuckery = fuckery(fileStart);
|
||||
|
||||
org.benf.cfr.reader.Main.main(generateMainMethod(tempZip.getAbsolutePath(), fuckery));
|
||||
|
||||
File fuck = new File(fuckery);
|
||||
|
||||
try {
|
||||
zip(fuck, new File(zipName));
|
||||
} catch (IOException e) {
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
|
||||
fuck.delete();
|
||||
}
|
||||
|
||||
public void zip(File directory, File zipFile) throws IOException {
|
||||
java.net.URI base = directory.toURI();
|
||||
Deque<File> queue = new LinkedList<>();
|
||||
queue.push(directory);
|
||||
try (OutputStream out = new FileOutputStream(zipFile);
|
||||
ZipOutputStream zout = new ZipOutputStream(out)) {
|
||||
while (!queue.isEmpty()) {
|
||||
directory = queue.pop();
|
||||
for (File kid : MiscUtils.listFiles(directory)) {
|
||||
String name = base.relativize(kid.toURI()).getPath();
|
||||
if (kid.isDirectory()) {
|
||||
queue.push(kid);
|
||||
name = name.endsWith("/") ? name : name + "/";
|
||||
zout.putNextEntry(new ZipEntry(name));
|
||||
} else {
|
||||
zout.putNextEntry(new ZipEntry(name));
|
||||
copy(kid, zout);
|
||||
zout.closeEntry();
|
||||
Enumeration<JarEntry> ent = jfile.entries();
|
||||
Set<JarEntry> history = new HashSet<>();
|
||||
while (ent.hasMoreElements()) {
|
||||
JarEntry entry = ent.nextElement();
|
||||
if (entry.getName().endsWith(CLASS_SUFFIX)) {
|
||||
JarEntry etn = new JarEntry(entry.getName().replace(CLASS_SUFFIX, ".java"));
|
||||
if (history.add(etn)) {
|
||||
out.putNextEntry(etn);
|
||||
try {
|
||||
IOUtils.write(decompile(null, entry.getName(),
|
||||
IOUtils.toByteArray(jfile.getInputStream(entry))),
|
||||
out, StandardCharsets.UTF_8);
|
||||
} finally {
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
JarEntry etn = new JarEntry(entry.getName());
|
||||
if (history.add(etn)) continue;
|
||||
history.add(etn);
|
||||
out.putNextEntry(etn);
|
||||
try (InputStream in = jfile.getInputStream(entry)) {
|
||||
if (in != null) {
|
||||
int count;
|
||||
while ((count = in.read(data, 0, 1024)) != -1) {
|
||||
out.write(data, 0, count);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
out.closeEntry();
|
||||
}
|
||||
} catch (ZipException ze) {
|
||||
// some jars contain duplicate pom.xml entries: ignore it
|
||||
if (!ze.getMessage().contains("duplicate")) {
|
||||
throw ze;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (StackOverflowError | Exception e) {
|
||||
BytecodeViewer.handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void copy(InputStream in, OutputStream out)
|
||||
throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
while (true) {
|
||||
int readCount = in.read(buffer);
|
||||
if (readCount < 0) {
|
||||
break;
|
||||
public Options generateOptions() {
|
||||
Map<String, String> options = new HashMap<>();
|
||||
options.put("decodeenumswitch", String.valueOf(BytecodeViewer.viewer.decodeEnumSwitch.isSelected()));
|
||||
options.put("sugarenums", String.valueOf(BytecodeViewer.viewer.sugarEnums.isSelected()));
|
||||
options.put("decodestringswitch", String.valueOf(BytecodeViewer.viewer.decodeStringSwitch.isSelected()));
|
||||
options.put("arrayiter", String.valueOf(BytecodeViewer.viewer.arrayiter.isSelected()));
|
||||
options.put("collectioniter", String.valueOf(BytecodeViewer.viewer.collectioniter.isSelected()));
|
||||
options.put("innerclasses", String.valueOf(BytecodeViewer.viewer.innerClasses.isSelected()));
|
||||
options.put("removeboilerplate", String.valueOf(BytecodeViewer.viewer.removeBoilerPlate.isSelected()));
|
||||
options.put("removeinnerclasssynthetics",
|
||||
String.valueOf(BytecodeViewer.viewer.removeInnerClassSynthetics.isSelected()));
|
||||
options.put("decodelambdas", String.valueOf(BytecodeViewer.viewer.decodeLambdas.isSelected()));
|
||||
options.put("hidebridgemethods", String.valueOf(BytecodeViewer.viewer.hideBridgeMethods.isSelected()));
|
||||
options.put("liftconstructorinit", String.valueOf(BytecodeViewer.viewer.liftConstructorInit.isSelected()));
|
||||
options.put("removebadgenerics", String.valueOf(BytecodeViewer.viewer.removeBadGenerics.isSelected()));
|
||||
options.put("sugarasserts", String.valueOf(BytecodeViewer.viewer.sugarAsserts.isSelected()));
|
||||
options.put("sugarboxing", String.valueOf(BytecodeViewer.viewer.sugarBoxing.isSelected()));
|
||||
options.put("showversion", String.valueOf(BytecodeViewer.viewer.showVersion.isSelected()));
|
||||
options.put("decodefinally", String.valueOf(BytecodeViewer.viewer.decodeFinally.isSelected()));
|
||||
options.put("tidymonitors", String.valueOf(BytecodeViewer.viewer.tidyMonitors.isSelected()));
|
||||
options.put("lenient", String.valueOf(BytecodeViewer.viewer.lenient.isSelected()));
|
||||
options.put("dumpclasspath", String.valueOf(BytecodeViewer.viewer.dumpClassPath.isSelected()));
|
||||
options.put("comments", String.valueOf(BytecodeViewer.viewer.comments.isSelected()));
|
||||
options.put("forcetopsort", String.valueOf(BytecodeViewer.viewer.forceTopSort.isSelected()));
|
||||
options.put("forcetopsortaggress", String.valueOf(BytecodeViewer.viewer.forceTopSortAggress.isSelected()));
|
||||
options.put("stringbuffer", String.valueOf(BytecodeViewer.viewer.stringBuffer.isSelected()));
|
||||
options.put("stringbuilder", String.valueOf(BytecodeViewer.viewer.stringBuilder.isSelected()));
|
||||
options.put("silent", String.valueOf(BytecodeViewer.viewer.silent.isSelected()));
|
||||
options.put("recover", String.valueOf(BytecodeViewer.viewer.recover.isSelected()));
|
||||
options.put("eclipse", String.valueOf(BytecodeViewer.viewer.eclipse.isSelected()));
|
||||
options.put("override", String.valueOf(BytecodeViewer.viewer.override.isSelected()));
|
||||
options.put("showinferrable", String.valueOf(BytecodeViewer.viewer.showInferrable.isSelected()));
|
||||
options.put("aexagg", String.valueOf(BytecodeViewer.viewer.aexagg.isSelected()));
|
||||
options.put("hideutf", String.valueOf(BytecodeViewer.viewer.hideUTF.isSelected()));
|
||||
options.put("hidelongstrings", String.valueOf(BytecodeViewer.viewer.hideLongStrings.isSelected()));
|
||||
options.put("commentmonitors", String.valueOf(BytecodeViewer.viewer.commentMonitor.isSelected()));
|
||||
options.put("allowcorrecting", String.valueOf(BytecodeViewer.viewer.allowCorrecting.isSelected()));
|
||||
options.put("labelledblocks", String.valueOf(BytecodeViewer.viewer.labelledBlocks.isSelected()));
|
||||
options.put("j14classobj", String.valueOf(BytecodeViewer.viewer.j14ClassOBJ.isSelected()));
|
||||
options.put("hidelangimports", String.valueOf(BytecodeViewer.viewer.hideLangImports.isSelected()));
|
||||
options.put("recovertypehints", String.valueOf(BytecodeViewer.viewer.recoveryTypehInts.isSelected()));
|
||||
options.put("forcereturningifs", String.valueOf(BytecodeViewer.viewer.forceTurningIFs.isSelected()));
|
||||
options.put("forloopaggcapture", String.valueOf(BytecodeViewer.viewer.forLoopAGGCapture.isSelected()));
|
||||
return new OptionsImpl(options);
|
||||
}
|
||||
|
||||
private static class BCVDataSource extends ClassFileSourceImpl {
|
||||
|
||||
private final ResourceContainer container;
|
||||
private final String classFilePath;
|
||||
private final byte[] content;
|
||||
|
||||
private BCVDataSource(Options options, ClassNode cn, String classFilePath, byte[] content) {
|
||||
super(options);
|
||||
this.container = BytecodeViewer.getResourceContainers().stream()
|
||||
.filter(rc -> rc.resourceClasses.containsValue(cn))
|
||||
.findFirst().orElse(null);
|
||||
this.classFilePath = classFilePath;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<byte[], String> getClassFileContent(String classFilePath) throws IOException {
|
||||
if (classFilePath.equals(this.classFilePath) && content != null) return Pair.make(content, classFilePath);
|
||||
if (container == null) return super.getClassFileContent(classFilePath);
|
||||
byte[] data = container.resourceClassBytes.get(classFilePath);
|
||||
if (data == null) return super.getClassFileContent(classFilePath);
|
||||
return Pair.make(data, classFilePath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class BCVOutputSinkFactory implements OutputSinkFactory {
|
||||
|
||||
private final Consumer<SinkReturns.Decompiled> dumpDecompiled;
|
||||
|
||||
private BCVOutputSinkFactory(Consumer<SinkReturns.Decompiled> dumpDecompiled) {
|
||||
this.dumpDecompiled = dumpDecompiled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SinkClass> getSupportedSinks(SinkType sinkType, Collection<SinkClass> available) {
|
||||
return Collections.singletonList(SinkClass.DECOMPILED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Sink<T> getSink(SinkType sinkType, SinkClass sinkClass) {
|
||||
if (sinkType == SinkType.JAVA && sinkClass == SinkClass.DECOMPILED) {
|
||||
return x -> dumpDecompiled.accept((SinkReturns.Decompiled) x);
|
||||
}
|
||||
out.write(buffer, 0, readCount);
|
||||
return ignore -> {
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void copy(File file, OutputStream out) throws IOException {
|
||||
try (InputStream in = new FileInputStream(file)) {
|
||||
copy(in, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public class SearchableJTextArea extends JTextArea
|
|||
private final JScrollPane scrollPane = new JScrollPane();
|
||||
private final JPanel searchPanel = new JPanel(new BorderLayout());
|
||||
private final JTextField searchInput = new JTextField();
|
||||
private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Exact", TranslatedComponents.EXACT);
|
||||
private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE);
|
||||
|
||||
public SearchableJTextArea()
|
||||
{
|
||||
|
|
|
@ -55,7 +55,7 @@ public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
|||
private final RTextScrollPane scrollPane = new RTextScrollPane(this);
|
||||
private final JPanel searchPanel = new JPanel(new BorderLayout());
|
||||
private final JTextField searchInput = new JTextField();
|
||||
private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Exact", TranslatedComponents.EXACT);
|
||||
private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE);
|
||||
private final JLabel titleHeader = new JLabel("");
|
||||
private final Color darkScrollBackground = new Color(0x3c3f41);
|
||||
private final Color darkScrollForeground = new Color(0x575859);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.*;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
|
@ -71,7 +70,8 @@ import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
|
|||
public class ResourceListPane extends TranslatedVisibleComponent implements FileDrop.Listener
|
||||
{
|
||||
public final JPopupMenu rightClickMenu = new JPopupMenu();
|
||||
public final JCheckBox exact = new TranslatedJCheckBox("Exact", TranslatedComponents.EXACT);
|
||||
public final JCheckBox exact = new TranslatedJCheckBox("Exact path", TranslatedComponents.EXACT_PATH);
|
||||
public final JCheckBox caseSensitive = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE);
|
||||
public final JButton open = new JButton("+");
|
||||
public final JButton close = new JButton("-");
|
||||
public final ResourceTreeNode treeRoot = new ResourceTreeNode("Loaded Files:");
|
||||
|
@ -104,7 +104,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
|||
|
||||
tree.setRootVisible(false);
|
||||
tree.setShowsRootHandles(true);
|
||||
quickSearch.setForeground(Color.gray);
|
||||
quickSearch.setForeground(quickSearch.getDisabledTextColor());
|
||||
|
||||
attachTreeListeners();
|
||||
attachQuickSearchListeners();
|
||||
|
@ -118,7 +118,12 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
|||
|
||||
quickSearchPanel.setLayout(new BorderLayout());
|
||||
quickSearchPanel.add(quickSearch, BorderLayout.NORTH);
|
||||
exactPanel.add(exact, BorderLayout.WEST);
|
||||
|
||||
JPanel btns = new JPanel(new FlowLayout());
|
||||
btns.add(exact);
|
||||
btns.add(caseSensitive);
|
||||
exactPanel.add(btns, BorderLayout.WEST);
|
||||
|
||||
buttonPanel.add(open, BorderLayout.EAST);
|
||||
buttonPanel.add(close, BorderLayout.WEST);
|
||||
exactPanel.add(buttonPanel, BorderLayout.EAST);
|
||||
|
@ -519,7 +524,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
|||
if (quickSearch.getText().equals(TranslatedStrings.QUICK_FILE_SEARCH_NO_FILE_EXTENSION.toString()))
|
||||
{
|
||||
quickSearch.setText("");
|
||||
quickSearch.setForeground(Color.black);
|
||||
quickSearch.setForeground(quickSearch.getSelectedTextColor());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,7 +534,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
|||
if (quickSearch.getText().isEmpty())
|
||||
{
|
||||
quickSearch.setText(TranslatedStrings.QUICK_FILE_SEARCH_NO_FILE_EXTENSION.toString());
|
||||
quickSearch.setForeground(Color.gray);
|
||||
quickSearch.setForeground(quickSearch.getDisabledTextColor());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
|
||||
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.Enumeration;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
|
||||
/***************************************************************************
|
||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||
|
@ -29,118 +29,103 @@ import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
|||
* @author Konloch
|
||||
* @since 6/22/2021
|
||||
*/
|
||||
public class SearchKeyAdapter extends KeyAdapter
|
||||
{
|
||||
private final ResourceListPane resourceListPane;
|
||||
|
||||
public SearchKeyAdapter(ResourceListPane resourceListPane) {this.resourceListPane = resourceListPane;}
|
||||
|
||||
@Override
|
||||
public void keyPressed(final KeyEvent ke)
|
||||
{
|
||||
//only trigger on enter
|
||||
if (ke.getKeyCode() != KeyEvent.VK_ENTER)
|
||||
return;
|
||||
|
||||
final String qt = resourceListPane.quickSearch.getText();
|
||||
resourceListPane.quickSearch.setText("");
|
||||
|
||||
if (qt.isEmpty()) //NOPE
|
||||
return;
|
||||
|
||||
String[] path;
|
||||
int found = 0;
|
||||
|
||||
if (qt.contains("."))
|
||||
{
|
||||
path = qt.split("\\.");
|
||||
}
|
||||
else
|
||||
{
|
||||
path = new String[]{qt};
|
||||
}
|
||||
|
||||
ResourceTreeNode curNode = resourceListPane.treeRoot;
|
||||
if (resourceListPane.exact.isSelected())
|
||||
{
|
||||
pathLoop:
|
||||
for (int i = 0; i < path.length; i++)
|
||||
{
|
||||
final String pathName = path[i];
|
||||
final boolean isLast = i == path.length - 1;
|
||||
|
||||
for (int c = 0; c < curNode.getChildCount(); c++)
|
||||
{
|
||||
final ResourceTreeNode child = (ResourceTreeNode) curNode.getChildAt(c);
|
||||
System.out.println(pathName + ":" + child.getUserObject());
|
||||
|
||||
if (child.getUserObject().equals(pathName))
|
||||
{
|
||||
curNode = child;
|
||||
if (isLast)
|
||||
{
|
||||
System.out.println("Found! " + curNode);
|
||||
found++;
|
||||
final TreePath pathn = new TreePath(curNode.getPath());
|
||||
resourceListPane.tree.setSelectionPath(pathn);
|
||||
resourceListPane.tree.makeVisible(pathn);
|
||||
resourceListPane.tree.scrollPathToVisible(pathn);
|
||||
resourceListPane.openPath(pathn); //auto open
|
||||
break pathLoop;
|
||||
}
|
||||
continue pathLoop;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Could not find " + pathName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<TreeNode> enums = curNode.depthFirstEnumeration();
|
||||
while (enums != null && enums.hasMoreElements())
|
||||
{
|
||||
ResourceTreeNode node = (ResourceTreeNode) enums.nextElement();
|
||||
if (node.isLeaf())
|
||||
{
|
||||
if (((String) (node.getUserObject())).toLowerCase().contains(path[path.length - 1].toLowerCase()))
|
||||
{
|
||||
TreeNode[] pathArray = node.getPath();
|
||||
int k = 0;
|
||||
StringBuilder fullPath = new StringBuilder();
|
||||
while (pathArray != null
|
||||
&& k < pathArray.length)
|
||||
{
|
||||
ResourceTreeNode n = (ResourceTreeNode) pathArray[k];
|
||||
String s = (String) (n.getUserObject());
|
||||
fullPath.append(s);
|
||||
if (k++ != pathArray.length - 1)
|
||||
{
|
||||
fullPath.append(".");
|
||||
}
|
||||
}
|
||||
String fullPathString = fullPath.toString();
|
||||
if (fullPathString.toLowerCase().contains(qt.toLowerCase()))
|
||||
{
|
||||
System.out.println("Found! " + node);
|
||||
found++;
|
||||
if (found >= 30)
|
||||
{ //TODO probably make this a setting, no real reason it's 30
|
||||
BytecodeViewer.showMessage("Uh oh, there could be more results but you've"
|
||||
+ " triggered the 30 classes at once limit. Try refining your search.");
|
||||
return;
|
||||
}
|
||||
final TreePath pathn = new TreePath(node.getPath());
|
||||
resourceListPane.tree.setSelectionPath(pathn.getParentPath());
|
||||
resourceListPane.tree.setSelectionPath(pathn);
|
||||
resourceListPane.tree.makeVisible(pathn);
|
||||
resourceListPane.tree.scrollPathToVisible(pathn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public class SearchKeyAdapter extends KeyAdapter {
|
||||
private final ResourceListPane resourceListPane;
|
||||
|
||||
public SearchKeyAdapter(ResourceListPane resourceListPane) {
|
||||
this.resourceListPane = resourceListPane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(final KeyEvent ke) {
|
||||
//only trigger on enter
|
||||
if (ke.getKeyCode() != KeyEvent.VK_ENTER)
|
||||
return;
|
||||
|
||||
final String qt = resourceListPane.quickSearch.getText();
|
||||
|
||||
if (qt.trim().isEmpty()) //NOPE
|
||||
return;
|
||||
|
||||
String[] path;
|
||||
if (qt.contains(".")) {
|
||||
path = qt.split("\\.");
|
||||
} else {
|
||||
path = new String[]{qt};
|
||||
}
|
||||
|
||||
ResourceTreeNode curNode = resourceListPane.treeRoot;
|
||||
boolean caseSensitive = resourceListPane.caseSensitive.isSelected();
|
||||
|
||||
boolean success = false;
|
||||
if (resourceListPane.exact.isSelected()) {
|
||||
pathLoop:
|
||||
for (int i = 0; i < path.length; i++) {
|
||||
final String pathName = path[i];
|
||||
final boolean isLast = i == path.length - 1;
|
||||
|
||||
for (int c = 0; c < curNode.getChildCount(); c++) {
|
||||
final ResourceTreeNode child = (ResourceTreeNode) curNode.getChildAt(c);
|
||||
Object userObject = child.getUserObject();
|
||||
if (caseSensitive ? userObject.equals(pathName) : userObject.toString().equalsIgnoreCase(pathName)) {
|
||||
curNode = child;
|
||||
if (isLast) {
|
||||
final TreePath pathn = new TreePath(curNode.getPath());
|
||||
resourceListPane.tree.setSelectionPath(pathn);
|
||||
resourceListPane.tree.makeVisible(pathn);
|
||||
resourceListPane.tree.scrollPathToVisible(pathn);
|
||||
resourceListPane.openPath(pathn); //auto open
|
||||
success = true;
|
||||
break pathLoop;
|
||||
}
|
||||
continue pathLoop;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Could not find " + pathName);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<TreeNode> enums = curNode.depthFirstEnumeration();
|
||||
while (enums != null && enums.hasMoreElements()) {
|
||||
ResourceTreeNode node = (ResourceTreeNode) enums.nextElement();
|
||||
if (node.isLeaf()) {
|
||||
String userObject = (String) (node.getUserObject());
|
||||
String lastElem = path[path.length - 1];
|
||||
|
||||
if (caseSensitive ? userObject.contains(lastElem) : userObject.toLowerCase().contains(lastElem.toLowerCase())) {
|
||||
TreeNode[] pathArray = node.getPath();
|
||||
int k = 0;
|
||||
StringBuilder fullPath = new StringBuilder();
|
||||
while (pathArray != null
|
||||
&& k < pathArray.length) {
|
||||
ResourceTreeNode n = (ResourceTreeNode) pathArray[k];
|
||||
String s = (String) (n.getUserObject());
|
||||
fullPath.append(s);
|
||||
if (k++ != pathArray.length - 1) {
|
||||
fullPath.append(".");
|
||||
}
|
||||
}
|
||||
String fullPathString = fullPath.toString();
|
||||
|
||||
if (caseSensitive ? fullPathString.contains(qt) : fullPathString.toLowerCase().contains(qt.toLowerCase())) {
|
||||
final TreePath pathn = new TreePath(node.getPath());
|
||||
resourceListPane.tree.setSelectionPath(pathn.getParentPath());
|
||||
resourceListPane.tree.setSelectionPath(pathn);
|
||||
resourceListPane.tree.makeVisible(pathn);
|
||||
resourceListPane.tree.scrollPathToVisible(pathn);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package the.bytecode.club.bytecodeviewer.gui.resourcesearch;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.searching.SearchPanel;
|
||||
import the.bytecode.club.bytecodeviewer.searching.impl.FieldCallSearch;
|
||||
import the.bytecode.club.bytecodeviewer.searching.impl.LDCSearch;
|
||||
import the.bytecode.club.bytecodeviewer.searching.impl.MethodCallSearch;
|
||||
import the.bytecode.club.bytecodeviewer.searching.impl.RegexSearch;
|
||||
import the.bytecode.club.bytecodeviewer.searching.impl.*;
|
||||
|
||||
/***************************************************************************
|
||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||
|
@ -34,6 +31,7 @@ public enum SearchType
|
|||
Regex(new RegexSearch()),
|
||||
MethodCall(new MethodCallSearch()),
|
||||
FieldCall(new FieldCallSearch()),
|
||||
MemberWithAnnotation(new MemberWithAnnotationSearch())
|
||||
;
|
||||
|
||||
public final SearchPanel panel;
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package the.bytecode.club.bytecodeviewer.searching.impl;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
||||
import the.bytecode.club.bytecodeviewer.searching.EnterKeyEvent;
|
||||
import the.bytecode.club.bytecodeviewer.searching.LDCSearchTreeNodeResult;
|
||||
import the.bytecode.club.bytecodeviewer.searching.SearchPanel;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedComponents;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJLabel;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
/***************************************************************************
|
||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
|
||||
* *
|
||||
* 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/>. *
|
||||
***************************************************************************/
|
||||
|
||||
/**
|
||||
* Annotation Searching
|
||||
*
|
||||
* @author GraxCode
|
||||
*/
|
||||
|
||||
public class MemberWithAnnotationSearch implements SearchPanel {
|
||||
JTextField annotation;
|
||||
JPanel myPanel = null;
|
||||
|
||||
public MemberWithAnnotationSearch() {
|
||||
annotation = new JTextField("");
|
||||
annotation.addKeyListener(EnterKeyEvent.SINGLETON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
if (myPanel == null) {
|
||||
myPanel = new JPanel(new GridLayout(1, 2));
|
||||
myPanel.add(new TranslatedJLabel("Annotation name: ", TranslatedComponents.ANNOTATION_NAME));
|
||||
myPanel.add(annotation);
|
||||
}
|
||||
|
||||
return myPanel;
|
||||
}
|
||||
|
||||
public void search(final ResourceContainer container, final String resourceWorkingName, final ClassNode node, boolean caseSensitive) {
|
||||
final String srchText = annotation.getText().trim();
|
||||
|
||||
if (srchText.isEmpty()) return;
|
||||
|
||||
node.fields.stream().filter(fn -> hasAnnotation(srchText, fn.invisibleAnnotations, fn.visibleAnnotations)).forEach(fn -> BytecodeViewer.viewer.searchBoxPane.treeRoot.add(new LDCSearchTreeNodeResult(container, resourceWorkingName, node, null, fn, fn.name + " " + fn.desc, "")));
|
||||
node.methods.stream().filter(mn -> hasAnnotation(srchText, mn.invisibleAnnotations, mn.visibleAnnotations)).forEach(mn -> BytecodeViewer.viewer.searchBoxPane.treeRoot.add(new LDCSearchTreeNodeResult(container, resourceWorkingName, node, mn, null, mn.name + mn.desc, "")));
|
||||
}
|
||||
|
||||
public static boolean hasAnnotation(String annotation, List<AnnotationNode>... annoLists) {
|
||||
if (annoLists == null) return false;
|
||||
for (List<AnnotationNode> annos : annoLists) {
|
||||
if (annos == null) continue;
|
||||
if (annos.stream().anyMatch(ant -> {
|
||||
String internalName = Type.getType(ant.desc).getInternalName();
|
||||
return internalName.equals(annotation) || internalName.endsWith('/' + annotation) || ant.desc.endsWith('/' + annotation.replace('.', '$'));
|
||||
// in case dot is used for inner class annotations
|
||||
})) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -251,8 +251,9 @@ public enum TranslatedComponents
|
|||
RESULTS,
|
||||
REFRESH,
|
||||
MIN_SDK_VERSION,
|
||||
|
||||
;
|
||||
ANNOTATION_NAME,
|
||||
MATCH_CASE,
|
||||
EXACT_PATH;
|
||||
|
||||
private final TranslatedComponentReference componentReference;
|
||||
|
||||
|
|
Loading…
Reference in a new issue