Compare commits

...

15 Commits

Author SHA1 Message Date
Konloch
edadceba64
Merge pull request #521 from Bl3nd/go-to-enhancement
Some checks failed
Build BCV / build (11) (push) Has been cancelled
Build BCV / build (17) (push) Has been cancelled
Build BCV / build (21) (push) Has been cancelled
Build BCV / build (8) (push) Has been cancelled
A small update to parsing
2024-10-07 17:09:51 -07:00
Cody
9860c9d63c
Merge branch 'Konloch:master' into go-to-enhancement 2024-10-07 17:28:30 -06:00
Cody
f560fa5b26 Update a few try-catch's to catch all exceptions. 2024-10-07 17:27:35 -06:00
Cody
d485b9b34b Remove error strip markers if you click on an empty line. 2024-10-07 17:25:12 -06:00
Konloch
3f1fd5a3f3 Merge branch 'master' of https://github.com/Konloch/bytecode-viewer 2024-10-06 23:20:38 -06:00
Konloch
879b5e64b5 Fix NPE 2024-10-06 23:20:05 -06:00
Konloch
14c7ed2e57
Merge pull request #517 from Bl3nd/go-to-enhancement
[Parser] Add examples of what each visitor visits among other things
2024-10-05 17:15:36 -07:00
Cody
29d29e14ac Add ability to open class files even when they don't have a package 2024-10-05 17:48:36 -06:00
Konloch
471ae44864 saveAsJar Should Throw Exceptions 2024-10-05 00:21:07 -06:00
Konloch
cf92749337 Syntax Cleanup 2024-10-05 00:11:44 -06:00
Cody
336d60ba06 Add the possibility that a class does not have a package. 2024-10-03 22:15:38 -06:00
Cody
340bec4fe8 Attempt at making the code more understandable and a few other things.
- Added examples on what visitor visits
- Moved away from the line, columnStart and columnEnd variables for each visitor, instead we use the Value class.
- Added a few more values we parse.
2024-10-02 21:24:15 -06:00
Cody
82789aa38e Make methods look for the same method that has the same signature rather than owner. 2024-10-02 21:18:37 -06:00
Cody
a9cbd661ca Update JavaParser version 2024-10-02 21:16:58 -06:00
Cody
ec47a2d6ed Switch from using StaticJavaParser to JavaParser so we can handle if the parse was successful. 2024-10-02 21:16:16 -06:00

AI 샘플 코드 생성 중입니다

Loading...
20 changed files with 2374 additions and 1768 deletions

View File

@ -51,7 +51,7 @@
<treelayout.version>1.0.3</treelayout.version>
<webp-imageio.version>a8f700b</webp-imageio.version>
<xpp3.version>1.1.4c</xpp3.version>
<java-parser.version>3.26.1</java-parser.version>
<java-parser.version>3.26.2</java-parser.version>
<taskmanager.version>1.0.1</taskmanager.version>
<google-java-format.version>1.7</google-java-format.version> <!-- Newer versions require Java 11+ -->
<disk-lib.version>1.2.0</disk-lib.version>

View File

@ -27,6 +27,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
/**
* Whenever a key is pressed on the swing UI it should get logged here
@ -121,8 +122,18 @@ public class GlobalHotKeys
BytecodeViewer.updateBusyStatus(true);
Thread jarExport = new Thread(() ->
{
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
BytecodeViewer.updateBusyStatus(false);
try
{
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
}
catch (IOException ex)
{
BytecodeViewer.handleException(ex);
}
finally
{
BytecodeViewer.updateBusyStatus(false);
}
}, "Jar Export");
jarExport.start();
}

View File

@ -42,8 +42,8 @@ public class Settings
{
public static boolean firstBoot = true; //stays true after settings load on first boot
public static boolean hasSetLanguageAsSystemLanguage = false;
private static List<String> recentPlugins;
private static List<String> recentFiles;
private static List<String> recentPlugins = new ArrayList<>();
private static List<String> recentFiles = new ArrayList<>();
//decompilers will automatically delete their temp files, useful to turn off if you want to quickly debug a decompilers results
public static boolean DECOMPILERS_AUTOMATICALLY_CLEANUP = true;
@ -53,15 +53,18 @@ public class Settings
{
try
{
File filesFile = new File(getBCVDirectory() + FS + "recentfiles.bcv");
File pluginsFile = new File(getBCVDirectory() + FS + "recentplugins.bcv");
if (new File(FILES_NAME).exists())
recentFiles = gson.fromJson(DiskReader.readString(FILES_NAME), new TypeToken<ArrayList<String>>() {}.getType());
else
recentFiles = Arrays.asList(DiskReader.readArray(getBCVDirectory() + FS + "recentfiles.bcv"));
else if (filesFile.exists())
recentFiles = Arrays.asList(DiskReader.readArray(filesFile));
if (new File(PLUGINS_NAME).exists())
recentPlugins = gson.fromJson(DiskReader.readString(PLUGINS_NAME), new TypeToken<ArrayList<String>>() {}.getType());
else
recentPlugins = Arrays.asList(DiskReader.readArray(getBCVDirectory() + FS + "recentplugins.bcv"));
else if (pluginsFile.exists())
recentPlugins = Arrays.asList(DiskReader.readArray(pluginsFile));
MiscUtils.deduplicateAndTrim(recentFiles, maxRecentFiles);
MiscUtils.deduplicateAndTrim(recentPlugins, maxRecentFiles);

View File

@ -127,7 +127,7 @@ public class GoToAction extends AbstractAction
}
else
{
methods.stream().filter(classMethodLocation -> classMethodLocation.owner.equals(method.owner)).forEach(classMethodLocation ->
methods.stream().filter(classMethodLocation -> classMethodLocation.signature.equals(method.signature)).forEach(classMethodLocation ->
{
if (classMethodLocation.decRef.equalsIgnoreCase("declaration"))
{
@ -211,7 +211,9 @@ public class GoToAction extends AbstractAction
if (packagePath.startsWith("java") || packagePath.startsWith("javax") || packagePath.startsWith("com.sun"))
return null;
String resourceName = packagePath + "/" + classMethodLocation.owner;
String resourceName = classMethodLocation.owner;
if (!packagePath.isEmpty())
resourceName = packagePath + "/" + classMethodLocation.owner;
if (resourceContainer.resourceClasses.containsKey(resourceName))
{
@ -229,7 +231,11 @@ public class GoToAction extends AbstractAction
if (packagePath.startsWith("java") || packagePath.startsWith("javax") || packagePath.startsWith("com.sun"))
return null;
String resourceName = packagePath + "/" + lexeme;
String resourceName = lexeme;
if (!packagePath.isEmpty())
{
resourceName = packagePath + "/" + lexeme;
}
if (resourceContainer.resourceClasses.containsKey(resourceName))
{

View File

@ -51,6 +51,7 @@ public class BytecodeViewPanel extends JPanel
public BytecodeViewPanel(int panelIndex, ClassViewer viewer)
{
super(new BorderLayout());
this.panelIndex = panelIndex;
this.viewer = viewer;
}
@ -63,7 +64,7 @@ public class BytecodeViewPanel extends JPanel
if (viewer.resource == null)
add(new JLabel("ERROR: Resource Viewer Missing Resource"));
//TODO remove when bcel support is added
//TODO remove when bcel support is added
else if (viewer.resource.getResourceClassNode() == null)
add(new JLabel("ERROR: Resource Viewer Missing ClassNode"));
}

View File

@ -513,6 +513,7 @@ public class BytecodeViewPanelUpdater implements Runnable
if (token == null)
{
highlighterEx.clearMarkOccurrencesHighlights();
errorStripe.refreshMarkers();
return;
}
}

View File

@ -1,6 +1,6 @@
package the.bytecode.club.bytecodeviewer.resources.classcontainer;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.*;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
@ -10,7 +10,7 @@ import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeS
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.*;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.MyVoidVisitor;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.MyVoidVisitor;
import java.io.IOException;
import java.util.ArrayList;
@ -56,9 +56,21 @@ public class ClassFileContainer
{
if (shouldParse())
{
TypeSolver typeSolver = new CombinedTypeSolver(new ReflectionTypeSolver(false), new JarTypeSolver(path));
StaticJavaParser.getParserConfiguration().setSymbolResolver(new JavaSymbolSolver(typeSolver));
CompilationUnit compilationUnit = StaticJavaParser.parse(this.content);
TypeSolver typeSolver = new CombinedTypeSolver(new ReflectionTypeSolver(true), new JarTypeSolver(path));
JavaParser parser = new JavaParser();
parser.getParserConfiguration().setSymbolResolver(new JavaSymbolSolver(typeSolver));
ParseResult<CompilationUnit> parse = parser.parse(this.content);
if (!parse.isSuccessful())
{
System.err.println("Failed to parse: " + this.getName());
parse.getProblems().forEach(System.out::println);
return false;
}
CompilationUnit compilationUnit = parse.getResult().orElse(null);
if (compilationUnit == null)
return false;
compilationUnit.accept(new MyVoidVisitor(this, compilationUnit), null);
return true;
}
@ -67,11 +79,6 @@ public class ClassFileContainer
{
throw new RuntimeException(e);
}
catch (Exception e)
{
System.err.println("Parsing error: " + className);
e.printStackTrace();
}
return false;
}
@ -88,7 +95,10 @@ public class ClassFileContainer
public String getName()
{
return this.className.substring(this.className.lastIndexOf('/') + 1, this.className.lastIndexOf('.'));
if (this.className.contains("/"))
return this.className.substring(this.className.lastIndexOf('/') + 1, this.className.lastIndexOf('.'));
else
return this.className.substring(0, this.className.lastIndexOf('.'));
}
public String getDecompiler()

View File

@ -0,0 +1,122 @@
package the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors;
import com.github.javaparser.Range;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.expr.*;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.Value;
import static the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.*;
/**
* Created by Bl3nd.
* Date: 10/1/2024
*/
class ArrayParser
{
static void parseAccess(CompilationUnit compilationUnit, ArrayAccessExpr expr, ClassFileContainer container)
{
Expression valueExp = expr.getName();
if (valueExp instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) valueExp;
CallableDeclaration<?> method = findMethodForExpression(expr, compilationUnit);
if (method == null)
{
method = findConstructorForExpression(expr, compilationUnit);
}
if (method == null)
{
System.err.println("ArrayAccess1 - Method not found");
return;
}
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value nameValue = new Value(nameExpr.getName(), range);
putResolvedValues(container, "reference", method, nameExpr, nameValue);
}
Expression indexExp = expr.getIndex();
if (indexExp instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) indexExp;
CallableDeclaration<?> method = findMethodForExpression(expr, compilationUnit);
if (method == null)
method = findConstructorForExpression(expr, compilationUnit);
if (method == null)
{
System.err.println("ArrayAccess2 - Method not found");
return;
}
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value indexValue = new Value(nameExpr.getName(), range);
putResolvedValues(container, "reference", method, nameExpr, indexValue);
}
}
static void parseCreation(CompilationUnit compilationUnit, ArrayCreationExpr expr,
ClassFileContainer container)
{
expr.getLevels().forEach(level -> {
Expression dimensionExpr = level.getDimension().orElse(null);
if (dimensionExpr instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) dimensionExpr;
CallableDeclaration<?> method = findMethodForExpression(expr, compilationUnit);
if (method == null)
method = findConstructorForExpression(expr, compilationUnit);
if (method == null)
{
System.err.println("ArrayCreation - Method not found");
return;
}
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value dimensionValue = new Value(nameExpr.getName(), range);
putResolvedValues(container, "reference", method, nameExpr, dimensionValue);
}
});
}
static void parseInitializer(CompilationUnit compilationUnit, ArrayInitializerExpr expr,
ClassFileContainer container)
{
expr.getValues().forEach(value -> {
if (value instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) value;
CallableDeclaration<?> method = findMethodForExpression(expr, compilationUnit);
if (method == null)
method = findConstructorForExpression(expr, compilationUnit);
if (method == null)
{
System.err.println("ArrayInitializer - Method not found");
return;
}
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value valueValue = new Value(nameExpr.getName(), range);
putResolvedValues(container, "reference", method, nameExpr, valueValue);
}
});
}
}

View File

@ -0,0 +1,100 @@
package the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors;
import com.github.javaparser.Range;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.expr.AssignExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.SimpleName;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.Value;
import static the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.printException;
import static the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.putResolvedValues;
/**
* Created by Bl3nd.
* Date: 9/29/2024
*/
class AssignParser
{
static void parse(ClassFileContainer container, AssignExpr expr, CallableDeclaration<?> method)
{
if (expr.getValue() instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) expr.getValue();
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value value = new Value(nameExpr.getName(), range);
try
{
putResolvedValues(container, "reference", method, nameExpr, value);
}
catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
if (expr.getTarget() instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) expr.getTarget();
try
{
SimpleName simpleName = nameExpr.getName();
Range range = simpleName.getRange().orElse(null);
if (range == null)
return;
Value target = new Value(nameExpr.getName(), range);
putResolvedValues(container, "reference", method, nameExpr, target);
}
catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
}
static void parseStatic(ClassFileContainer container, AssignExpr expr)
{
if (expr.getValue() instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) expr.getValue();
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value value = new Value(nameExpr.getName(), range);
try
{
putResolvedValues(container, "reference", nameExpr, value);
}
catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
if (expr.getTarget() instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) expr.getTarget();
try
{
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value target = new Value(nameExpr.getName(), range);
putResolvedValues(container, "reference", nameExpr, target);
}
catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
}
}

View File

@ -0,0 +1,54 @@
package the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors;
import com.github.javaparser.Range;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.expr.ConditionalExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.NameExpr;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.Value;
import static the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.*;
/**
* Created by Bl3nd.
* Date: 10/1/2024
*/
class ConditionalParser
{
static void parse(CompilationUnit compilationUnit, ConditionalExpr expr, ClassFileContainer container)
{
CallableDeclaration<?> method = findMethodForExpression(expr, compilationUnit);
if (method == null)
method = findConstructorForExpression(expr, compilationUnit);
if (method == null)
return;
Expression elseExpr = expr.getElseExpr();
if (elseExpr instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) elseExpr;
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value elseValue = new Value(nameExpr.getName(), range);
putResolvedValues(container, "reference", method, nameExpr, elseValue);
}
Expression thenExpr = expr.getThenExpr();
if (thenExpr instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) thenExpr;
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value thenValue = new Value(nameExpr.getName(), range);
putResolvedValues(container, "reference", method, nameExpr, thenValue);
}
}
}

View File

@ -0,0 +1,122 @@
package the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors;
import com.github.javaparser.Range;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer;
import java.util.Objects;
import static the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.*;
/**
* Created by Bl3nd.
* Date: 9/28/2024
*/
class FieldAccessParser
{
static void parse(ClassFileContainer container, FieldAccessExpr expr)
{
Range fieldRange = Objects.requireNonNull(expr.getTokenRange().orElse(null)).getEnd().getRange().orElse(null);
if (fieldRange == null)
return;
Value fieldValue = new Value(expr.getName(), fieldRange);
Expression scope = expr.getScope();
// Ex. Clazz.field -> Clazz
if (scope instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) scope;
Range scopeRange = nameExpr.getRange().orElse(null);
if (scopeRange == null)
return;
Value scopeValue = new Value(nameExpr.getName(), scopeRange);
try
{
putClassResolvedValues(container, expr, nameExpr, scopeValue, fieldValue);
}
catch (UnsolvedSymbolException ignore)
{
try
{
putClassResolvedValues(container, expr, nameExpr, scopeValue, fieldValue);
}
catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
} // Ex. this.field
else if (scope instanceof ThisExpr)
{
ThisExpr thisExpr = (ThisExpr) scope;
try
{
putFieldResolvedValues(container, expr, thisExpr, fieldValue);
} catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
else if (scope instanceof EnclosedExpr)
{
EnclosedExpr enclosedExpr = (EnclosedExpr) scope;
try
{
putFieldResolvedValues(container, expr, enclosedExpr, fieldValue);
} catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
}
static void parseStatic(ClassFileContainer container, FieldAccessExpr expr)
{
Range fieldRange = Objects.requireNonNull(expr.getTokenRange().orElse(null)).getEnd().getRange().orElse(null);
if (fieldRange == null)
return;
Value fieldValue = new Value(expr.getName(), fieldRange);
Expression scope = expr.getScope();
if (scope instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) scope;
Range scopeRange = nameExpr.getRange().orElse(null);
if (scopeRange == null)
return;
Value scopeValue = new Value(nameExpr.getName(), scopeRange);
try
{
putClassResolvedValues(container, expr, nameExpr, scopeValue, fieldValue);
}
catch (UnsolvedSymbolException ignore)
{
try
{
putClassResolvedValues(container, expr, nameExpr, scopeValue, fieldValue);
} catch (UnsolvedSymbolException e) {
printException(expr, e);
}
}
}
else if (scope instanceof ThisExpr)
{
ThisExpr thisExpr = (ThisExpr) scope;
try {
putFieldResolvedValues(container, expr, thisExpr, fieldValue);
} catch (UnsolvedSymbolException e) {
printException(expr, e);
}
}
}
}

View File

@ -0,0 +1,140 @@
package the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors;
import com.github.javaparser.Range;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.Value;
import static the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.*;
/**
* Created by Bl3nd.
* Date: 9/28/2024
*/
class MethodCallParser
{
static void parse(ClassFileContainer container, MethodCallExpr expr, CallableDeclaration<?> method)
{
if (expr.hasScope())
{
Expression scope = expr.getScope().orElse(null);
/*
Ex.
field.method -> field
variable.method -> variable
parameter.method -> parameter
*/
if (scope instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) scope;
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value scopeValue = new Value(nameExpr.getName(), range);
try
{
putResolvedValues(container, "reference", method, nameExpr, scopeValue);
}
catch (UnsolvedSymbolException ignored)
{
try
{
putClassResolvedValues(container, expr, nameExpr, scopeValue);
} catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
}
}
// Ex. method(arg, arg, ...)
expr.getArguments().forEach(argument ->
{
if (argument instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) argument;
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
return;
Value argName = new Value(nameExpr.getName(), range);
try {
putResolvedValues(container, "reference", method, nameExpr, argName);
} catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
});
}
static void parseStatic(ClassFileContainer container, MethodCallExpr expr)
{
if (expr.hasScope())
{
/*
Ex.
field.method -> field
variable.method -> variable
parameter.method -> parameter
*/
Expression scope = expr.getScope().orElse(null);
if (scope instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) scope;
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
{
return;
}
Value scopeValue = new Value(nameExpr.getName(), range);
try {
putResolvedValues(container, "reference", nameExpr, scopeValue);
} catch (UnsolvedSymbolException ignored)
{
try
{
putClassResolvedValues(container, expr, nameExpr, scopeValue);
} catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
}
}
expr.getArguments().forEach(argument ->
{
if (argument instanceof NameExpr)
{
NameExpr nameExpr = (NameExpr) argument;
Range range = nameExpr.getName().getRange().orElse(null);
if (range == null)
{
return;
}
Value argValue = new Value(nameExpr.getName(), range);
try
{
putResolvedValues(container, "reference", nameExpr, argValue);
} catch (UnsolvedSymbolException e)
{
printException(expr, e);
}
}
});
}
}

View File

@ -0,0 +1,36 @@
package the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.expr.SimpleName;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer;
import static the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors.ParserUtil.*;
/**
* Created by Bl3nd.
* Date: 10/1/2024
*/
public class ParameterParser
{
public static void parse(CompilationUnit compilationUnit, Parameter p, ClassFileContainer container)
{
Node node = p.getParentNode().orElse(null);
if (node == null)
return;
String methodName = findMethodOwnerFor(compilationUnit, node);
if (methodName == null) {
System.err.println("Parameter - Method not found");
return;
}
SimpleName name = p.getName();
name.getRange().ifPresent(range -> {
Value parameter = new Value(name, range);
putParameter(container, parameter, methodName, "declaration");
});
}
}

View File

@ -0,0 +1,517 @@
package the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.visitors;
import com.github.javaparser.Range;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.InitializerDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.SimpleName;
import com.github.javaparser.ast.stmt.CatchClause;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.stmt.TryStmt;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import com.github.javaparser.resolution.types.ResolvedType;
import org.jetbrains.annotations.Nullable;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassFieldLocation;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassLocalVariableLocation;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassParameterLocation;
import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassReferenceLocation;
/**
* Created by Bl3nd.
* Date: 9/28/2024
*/
class ParserUtil
{
static class Value
{
final String name;
final int line;
final int columnStart;
final int columnEnd;
public Value(SimpleName simpleName, Range range)
{
this.name = simpleName.getIdentifier();
this.line = range.begin.line;
this.columnStart = range.begin.column;
this.columnEnd = range.end.column;
}
}
/**
* Put resolved value types (field, variable and parameter) that have a method as an owner.
*
* @param container The class container
* @param method The owner method of the type
* @param resolveExpr The {@code NameExpr}
* @param value The value
*/
static void putResolvedValues(ClassFileContainer container, String decRef, CallableDeclaration<?> method,
NameExpr resolveExpr, Value value)
{
ResolvedValueDeclaration vd = resolveExpr.resolve();
if (vd.isField())
{
container.putField(value.name, new ClassFieldLocation(getOwner(container), decRef,
value.line, value.columnStart, value.columnEnd + 1));
}
else if (vd.isVariable())
{
container.putLocalVariable(value.name, new ClassLocalVariableLocation(getOwner(container)
, getMethod(method), decRef, value.line, value.columnStart,
value.columnEnd + 1));
}
else if (vd.isParameter())
{
container.putParameter(value.name, new ClassParameterLocation(getOwner(container),
getMethod(method), decRef, value.line, value.columnStart,
value.columnEnd + 1));
}
}
/**
* Put resolved value types (field, variable and parameter) that are in a static block.
*
* @param container The class container
* @param resolveExpr The {@code NameExpr}
* @param value The value
*/
static void putResolvedValues(ClassFileContainer container, String decRef, NameExpr resolveExpr, Value value)
{
ResolvedValueDeclaration vd = resolveExpr.resolve();
if (vd.isField())
{
container.putField(value.name, new ClassFieldLocation(getOwner(container), decRef,
value.line, value.columnStart, value.columnEnd + 1));
}
else if (vd.isVariable())
{
container.putLocalVariable(value.name, new ClassLocalVariableLocation(getOwner(container)
, "static", decRef, value.line, value.columnStart, value.columnEnd + 1));
}
else if (vd.isParameter())
{
container.putParameter(value.name, new ClassParameterLocation(getOwner(container),
"static", decRef, value.line, value.columnStart, value.columnEnd + 1));
}
}
static void putParameter(ClassFileContainer container, Value parameter, String method, String decRef)
{
container.putParameter(parameter.name, new ClassParameterLocation(getOwner(container), method, decRef,
parameter.line, parameter.columnStart, parameter.columnEnd + 1));
}
static void putLocalVariable(ClassFileContainer container, Value variable, String method, String decRef)
{
container.putLocalVariable(variable.name, new ClassLocalVariableLocation(getOwner(container), method, decRef,
variable.line, variable.columnStart, variable.columnEnd + 1));
}
/**
* Put both the class and field reference.
*
* @param container The class container
* @param visitedExpr The main expression
* @param resolveExpr The expression to resolve
* @param scopeValue The scope value
* @param fieldValue The field value
*/
static void putClassResolvedValues(ClassFileContainer container, Expression visitedExpr, Expression resolveExpr,
Value scopeValue, Value fieldValue)
{
ResolvedType resolvedType = visitedExpr.getSymbolResolver().calculateType(resolveExpr);
if (!resolvedType.isReferenceType())
return;
String qualifiedName = resolvedType.asReferenceType().getQualifiedName();
String className = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
String packageName = "";
if (qualifiedName.contains("."))
packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf('.')).replace('.', '/');
container.putClassReference(className, new ClassReferenceLocation(ParserUtil.getOwner(container), packageName
, fieldValue.name, "reference", scopeValue.line, scopeValue.columnStart, scopeValue.columnEnd + 1));
container.putField(fieldValue.name, new ClassFieldLocation(scopeValue.name, "reference", fieldValue.line,
fieldValue.columnStart, fieldValue.columnEnd + 1));
}
/**
* Put only the class reference.
*
* @param container The class container
* @param visitedExpr The main expression
* @param resolveExpr The expression to resolve
* @param scopeValue The scope value
*/
static void putClassResolvedValues(ClassFileContainer container, Expression visitedExpr,
Expression resolveExpr, Value scopeValue)
{
ResolvedType resolvedType = visitedExpr.getSymbolResolver().calculateType(resolveExpr);
if (!resolvedType.isReferenceType())
return;
ResolvedReferenceType referenceType = resolvedType.asReferenceType();
if (!referenceType.hasName())
return;
String qualifiedName = referenceType.getQualifiedName();
String className = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
String packageName = "";
if (qualifiedName.contains("."))
packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf('.')).replace('.', '/');
container.putClassReference(className, new ClassReferenceLocation(ParserUtil.getOwner(container), packageName
, "", "reference", scopeValue.line, scopeValue.columnStart, scopeValue.columnEnd + 1));
}
/**
* Put only a class field reference.
*
* @param container The class container
* @param visitedExpr The main expression
* @param resolveExpr The expression to resolve
* @param fieldValue The field value
*/
static void putFieldResolvedValues(ClassFileContainer container, Expression visitedExpr,
Expression resolveExpr, Value fieldValue)
{
ResolvedType resolvedType = visitedExpr.getSymbolResolver().calculateType(resolveExpr);
if (!resolvedType.isReferenceType())
return;
String qualifiedName = resolvedType.asReferenceType().getQualifiedName();
String className = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
container.putField(fieldValue.name, new ClassFieldLocation(className, "reference", fieldValue.line,
fieldValue.columnStart, fieldValue.columnEnd + 1));
}
static void printException(Object o, Exception e)
{
System.err.println(o.getClass().getSimpleName() + ": " + e.getMessage());
}
static String getOwner(ClassFileContainer container)
{
return container.getName();
}
static String getMethod(CallableDeclaration<?> method)
{
return method.getDeclarationAsString(false, false);
}
static @Nullable String findMethodOwnerFor(CompilationUnit compilationUnit, Node node)
{
if (node instanceof CallableDeclaration<?>)
{
return ((CallableDeclaration<?>) node).getDeclarationAsString(false, false);
}
else if (node instanceof CatchClause)
{
TryStmt statement = (TryStmt) node.getParentNode().orElse(null);
if (statement == null)
return null;
CallableDeclaration<?> method = findMethodForStatement(statement, compilationUnit);
if (method == null)
{
method = findConstructorForStatement(statement, compilationUnit);
if (method == null)
{
if (findInitializerForStatement(statement, compilationUnit) != null)
return "static";
return null;
}
}
return method.getDeclarationAsString(false, false);
}
else if (node instanceof Statement)
{
CallableDeclaration<?> method = findMethodForStatement((Statement) node, compilationUnit);
if (method == null)
{
method = findConstructorForStatement((Statement) node, compilationUnit);
if (method == null)
{
if (findInitializerForStatement((Statement) node, compilationUnit) != null)
return "static";
return null;
}
}
return method.getDeclarationAsString(false, false);
}
else if (node instanceof Expression)
{
CallableDeclaration<?> method = findMethodForExpression((Expression) node, compilationUnit);
if (method == null)
{
method = findConstructorForExpression((Expression) node, compilationUnit);
if (method == null)
{
if (findInitializerForExpression((Expression) node, compilationUnit) != null)
return "static";
return null;
}
}
return method.getDeclarationAsString(false, false);
}
return null;
}
/**
* Look through the {@link CompilationUnit} for the specific statement within its methods.
*
* @param statement The {@code statement} we are looking for
* @param cu The {@code CompilationUnit}
* @return the method that contains the {@code statement}.
*/
static MethodDeclaration findMethodForStatement(Statement statement, CompilationUnit cu)
{
final boolean[] contains = {false};
final MethodDeclaration[] methodDeclaration = {null};
cu.accept(new VoidVisitorAdapter<Void>()
{
@Override
public void visit(MethodDeclaration n, Void arg)
{
super.visit(n, arg);
if (!n.isAbstract()/* && !contains[0]*/)
{
for (Statement statement1 : n.getBody().get().getStatements())
{
if (statement1.containsWithinRange(statement))
{
contains[0] = true;
methodDeclaration[0] = n;
break;
}
}
}
}
}, null);
if (contains[0])
{
return methodDeclaration[0];
}
return null;
}
/**
* Look through the {@link CompilationUnit} for the specific statement within its methods.
*
* @param expression The {@code expression} we are looking for
* @param cu The {@code CompilationUnit}
* @return the method that contains the {@code expression}.
*/
static MethodDeclaration findMethodForExpression(Expression expression, CompilationUnit cu)
{
final boolean[] contains = {false};
final MethodDeclaration[] methodDeclaration = {null};
cu.accept(new VoidVisitorAdapter<Void>()
{
@Override
public void visit(MethodDeclaration n, Void arg)
{
super.visit(n, arg);
if (!n.isAbstract()/* && !contains[0]*/)
{
for (Statement statement : n.getBody().get().getStatements())
{
if (statement.containsWithinRange(expression))
{
contains[0] = true;
methodDeclaration[0] = n;
break;
}
}
}
}
}, null);
if (contains[0])
{
return methodDeclaration[0];
}
return null;
}
/**
* Look through the {@link CompilationUnit} for the specific statement within its methods.
*
* @param statement The {@code statement} we are looking for
* @param cu The {@code CompilationUnit}
* @return the constructor that contains the {@code statement}.
*/
static ConstructorDeclaration findConstructorForStatement(Statement statement, CompilationUnit cu)
{
final boolean[] contains = {false};
final ConstructorDeclaration[] constructorDeclaration = {null};
cu.accept(new VoidVisitorAdapter<Void>()
{
@Override
public void visit(ConstructorDeclaration n, Void arg)
{
super.visit(n, arg);
if (contains[0])
return;
for (Statement statement1 : n.getBody().getStatements())
{
if (statement1.containsWithinRange(statement))
{
contains[0] = true;
constructorDeclaration[0] = n;
break;
}
}
}
}, null);
if (contains[0])
{
return constructorDeclaration[0];
}
return null;
}
/**
* Look through the {@link CompilationUnit} for the specific statement within its methods.
*
* @param expression The {@code expression} we are looking for
* @param cu The {@code CompilationUnit}
* @return the constructor that contains the {@code expression}.
*/
static ConstructorDeclaration findConstructorForExpression(Expression expression, CompilationUnit cu)
{
final boolean[] contains = {false};
final ConstructorDeclaration[] constructorDeclaration = {null};
cu.accept(new VoidVisitorAdapter<Void>()
{
@Override
public void visit(ConstructorDeclaration n, Void arg)
{
super.visit(n, arg);
if (contains[0])
return;
for (Statement statement1 : n.getBody().getStatements())
{
if (statement1.containsWithinRange(expression))
{
contains[0] = true;
constructorDeclaration[0] = n;
}
}
}
}, null);
if (contains[0])
{
return constructorDeclaration[0];
}
return null;
}
/**
* Look through the {@link CompilationUnit} for the specific statement within its methods.
*
* @param statement The {@code statement} we are looking for
* @param cu The {@code CompilationUnit}
* @return the initializer that contains the {@code statement}.
*/
static InitializerDeclaration findInitializerForStatement(Statement statement, CompilationUnit cu)
{
final boolean[] contains = {false};
final InitializerDeclaration[] initializerDeclaration = {null};
cu.accept(new VoidVisitorAdapter<Void>()
{
@Override
public void visit(InitializerDeclaration n, Void arg)
{
super.visit(n, arg);
if (contains[0])
return;
for (Statement statement : n.getBody().getStatements())
{
if (statement.containsWithinRange(statement))
{
contains[0] = true;
initializerDeclaration[0] = n;
}
}
}
}, null);
if (contains[0])
{
return initializerDeclaration[0];
}
else
{
return null;
}
}
/**
* Look through the {@link CompilationUnit} for the specific statement within its methods.
*
* @param expression The {@code expression} we are looking for
* @param cu The {@code CompilationUnit}
* @return the initializer that contains the {@code expression}.
*/
static InitializerDeclaration findInitializerForExpression(Expression expression, CompilationUnit cu)
{
final boolean[] contains = {false};
final InitializerDeclaration[] initializerDeclaration = {null};
cu.accept(new VoidVisitorAdapter<Void>()
{
@Override
public void visit(InitializerDeclaration n, Void arg)
{
super.visit(n, arg);
if (contains[0])
return;
for (Statement statement : n.getBody().getStatements())
{
if (statement.containsWithinRange(expression))
{
contains[0] = true;
initializerDeclaration[0] = n;
}
}
}
}, null);
if (contains[0])
{
return initializerDeclaration[0];
}
return null;
}
}

View File

@ -31,6 +31,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -109,17 +110,26 @@ public class APKExport implements Exporter
Thread saveThread = new Thread(() ->
{
BytecodeViewer.updateBusyStatus(true);
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
Thread buildAPKThread = new Thread(() ->
try
{
APKTool.buildAPK(new File(input), file, finalContainer);
BytecodeViewer.updateBusyStatus(false);
}, "Process APK");
BytecodeViewer.updateBusyStatus(true);
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
buildAPKThread.start();
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
Thread buildAPKThread = new Thread(() ->
{
APKTool.buildAPK(new File(input), file, finalContainer);
BytecodeViewer.updateBusyStatus(false);
}, "Process APK");
buildAPKThread.start();
}
catch (IOException ex)
{
BytecodeViewer.updateBusyStatus(false);
BytecodeViewer.handleException(ex);
}
}, "Jar Export");
saveThread.start();

View File

@ -29,6 +29,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import static the.bytecode.club.bytecodeviewer.Constants.FS;
import static the.bytecode.club.bytecodeviewer.Constants.TEMP_DIRECTORY;
@ -73,18 +74,27 @@ public class DexExport implements Exporter
Thread saveAsJar = new Thread(() ->
{
BytecodeViewer.updateBusyStatus(true);
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
Thread saveAsDex = new Thread(() ->
try
{
Dex2Jar.saveAsDex(new File(input), outputPath);
BytecodeViewer.updateBusyStatus(true);
final String input = TEMP_DIRECTORY + FS + MiscUtils.getRandomizedName() + ".jar";
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
Thread saveAsDex = new Thread(() ->
{
Dex2Jar.saveAsDex(new File(input), outputPath);
BytecodeViewer.updateBusyStatus(false);
}, "Process DEX");
saveAsDex.start();
}
catch (IOException ex)
{
BytecodeViewer.updateBusyStatus(false);
}, "Process DEX");
saveAsDex.start();
BytecodeViewer.handleException(ex);
}
}, "Jar Export");
saveAsJar.start();

View File

@ -28,6 +28,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
/**
* @author Konloch
@ -65,8 +66,18 @@ public class ZipExport implements Exporter
Thread saveThread = new Thread(() ->
{
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
BytecodeViewer.updateBusyStatus(false);
try
{
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
}
catch (IOException ex)
{
BytecodeViewer.handleException(ex);
}
finally
{
BytecodeViewer.updateBusyStatus(false);
}
}, "Jar Export");
saveThread.start();

View File

@ -405,7 +405,7 @@ public class JarUtils
* @param nodeList The loaded ClassNodes
* @param path the exact jar output path
*/
public static void saveAsJar(List<ClassNode> nodeList, String path)
public static void saveAsJar(List<ClassNode> nodeList, String path) throws IOException
{
try (FileOutputStream fos = new FileOutputStream(path);
JarOutputStream out = new JarOutputStream(fos))
@ -448,9 +448,5 @@ public class JarUtils
fileCollisionPrevention .clear();
}
catch (IOException e)
{
BytecodeViewer.handleException(e);
}
}
}