-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge jadxecute code into new version
- Loading branch information
1 parent
0f298b7
commit fe9a1f0
Showing
9 changed files
with
1,663 additions
and
0 deletions.
There are no files selected for viewing
260 changes: 260 additions & 0 deletions
260
jadx-with-jadxecute/jadx-gui/src/main/java/jadx/gui/plugins/jadxecute/AddCommentHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,260 @@ | ||
package jadx.gui.plugins.jadxecute; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
import java.util.function.Consumer; | ||
import java.util.stream.Collectors; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import jadx.api.JavaNode; | ||
import jadx.api.data.ICodeComment; | ||
import jadx.api.data.impl.JadxCodeComment; | ||
import jadx.api.data.impl.JadxCodeData; | ||
import jadx.api.data.impl.JadxCodeRef; | ||
import jadx.api.data.impl.JadxNodeRef; | ||
import jadx.gui.treemodel.JClass; | ||
import jadx.gui.ui.MainWindow; | ||
import jadx.gui.ui.codearea.CodeArea; | ||
import jadx.gui.settings.JadxProject; | ||
|
||
import jadx.api.JavaVariable; | ||
import jadx.core.utils.exceptions.JadxRuntimeException; | ||
import jadx.gui.jobs.TaskStatus; | ||
import jadx.gui.treemodel.JMethod; | ||
import jadx.gui.treemodel.JNode; | ||
import jadx.gui.treemodel.JPackage; | ||
import jadx.gui.ui.TabbedPane; | ||
import jadx.gui.ui.codearea.ClassCodeContentPanel; | ||
import jadx.gui.ui.panel.ContentPanel; | ||
import jadx.gui.utils.CacheObject; | ||
import jadx.gui.utils.JNodeCache; | ||
|
||
public class AddCommentHelper { | ||
private static final Logger LOG = LoggerFactory.getLogger(AddCommentHelper.class); | ||
|
||
private MainWindow mainWindow; | ||
private CacheObject cache; | ||
private String newCommentString; | ||
private JavaNode node; | ||
private boolean updateComment; | ||
|
||
public AddCommentHelper(MainWindow mainWindow, JavaNode node) { | ||
this.mainWindow = mainWindow; | ||
this.cache = mainWindow.getCacheObject(); | ||
this.node = node; | ||
} | ||
|
||
// To be implemented | ||
/* | ||
public String addVariableComment(String newCommentString, JavaVariable javaVariable) { | ||
this.newCommentString = newCommentString; | ||
ICodeComment blankComment = new JadxCodeComment(JadxNodeRef.forJavaNode(node), JadxCodeRef.forVar(javaVariable), ""); | ||
if (blankComment == null) { | ||
return "Failed to add comment"; | ||
} | ||
ICodeComment existComment = searchForExistComment(blankComment); | ||
if (existComment != null) { | ||
this.updateComment = true; | ||
apply(existComment, javaVariable); | ||
} else { | ||
this.updateComment = false; | ||
apply(blankComment, javaVariable); | ||
} | ||
return "Added comment in " + node.getFullName() + " for variable " + javaVariable.getName(); | ||
} | ||
*/ | ||
|
||
public String addInstructionComment(String newCommentString, int commentSmaliOffset) { | ||
this.newCommentString = newCommentString; | ||
|
||
ICodeComment blankComment = new JadxCodeComment(JadxNodeRef.forJavaNode(node), JadxCodeRef.forInsn(commentSmaliOffset), ""); | ||
if (blankComment == null) { | ||
return "Failed to add comment"; | ||
} | ||
|
||
ICodeComment existComment = searchForExistComment(blankComment); | ||
if (existComment != null) { | ||
this.updateComment = true; | ||
apply(existComment, commentSmaliOffset); | ||
} else { | ||
this.updateComment = false; | ||
apply(blankComment, commentSmaliOffset); | ||
} | ||
|
||
return "Added comment in " + node.getFullName() + " at offset " + commentSmaliOffset; | ||
} | ||
|
||
private void apply(ICodeComment comment, int commentOffset) { | ||
if (newCommentString.isEmpty()) { | ||
if (updateComment) { | ||
updateCommentsData(list -> list.removeIf(c -> c == comment)); | ||
} | ||
return; | ||
} | ||
|
||
ICodeComment newComment = new JadxCodeComment(JadxNodeRef.forJavaNode(node), JadxCodeRef.forInsn(commentOffset), newCommentString); | ||
if (updateComment) { | ||
updateCommentsData(list -> { | ||
list.remove(comment); | ||
list.add(newComment); | ||
}); | ||
} else { | ||
updateCommentsData(list -> list.add(newComment)); | ||
} | ||
} | ||
|
||
private void apply(ICodeComment comment, JavaVariable javaVariable) { | ||
if (newCommentString.isEmpty()) { | ||
if (updateComment) { | ||
updateCommentsData(list -> list.removeIf(c -> c == comment)); | ||
} | ||
return; | ||
} | ||
|
||
ICodeComment newComment = new JadxCodeComment(JadxNodeRef.forJavaNode(node), JadxCodeRef.forVar(javaVariable), newCommentString); | ||
if (updateComment) { | ||
updateCommentsData(list -> { | ||
list.remove(comment); | ||
list.add(newComment); | ||
}); | ||
} else { | ||
updateCommentsData(list -> list.add(newComment)); | ||
} | ||
} | ||
|
||
private ICodeComment searchForExistComment(ICodeComment blankComment) { | ||
try { | ||
JadxProject project = mainWindow.getProject(); | ||
JadxCodeData codeData = project.getCodeData(); | ||
if (codeData == null || codeData.getComments().isEmpty()) { | ||
return null; | ||
} | ||
for (ICodeComment comment : codeData.getComments()) { | ||
if (Objects.equals(comment.getNodeRef(), blankComment.getNodeRef()) | ||
&& Objects.equals(comment.getCodeRef(), blankComment.getCodeRef())) { | ||
return comment; | ||
} | ||
} | ||
} catch (Exception e) { | ||
LOG.error("Error searching for exists comment", e); | ||
} | ||
return null; | ||
} | ||
|
||
private String updateCommentsData(Consumer<List<ICodeComment>> updater) { | ||
JadxProject project = mainWindow.getProject(); | ||
JadxCodeData codeData = project.getCodeData(); | ||
|
||
try { | ||
if (codeData == null) { | ||
codeData = new JadxCodeData(); | ||
} | ||
List<ICodeComment> list = new ArrayList<>(codeData.getComments()); | ||
|
||
updater.accept(list); | ||
Collections.sort(list); | ||
codeData.setComments(list); | ||
project.setCodeData(codeData); | ||
mainWindow.getWrapper().reloadCodeData(); | ||
} catch (Exception e) { | ||
LOG.error("Comment action failed", e); | ||
} | ||
try { | ||
refreshState(); | ||
} catch (Exception e) { | ||
LOG.error("Failed to reload code", e); | ||
} | ||
|
||
String retval = ""; | ||
|
||
for (ICodeComment comment : codeData.getComments()) { | ||
retval += comment.getComment() + "\n"; | ||
} | ||
return retval; | ||
} | ||
|
||
private void refreshState() { | ||
mainWindow.getWrapper().reInitRenameVisitor(); | ||
|
||
JNodeCache nodeCache = cache.getNodeCache(); | ||
JavaNode javaNode = node; | ||
|
||
List<JavaNode> toUpdate = new ArrayList<>(); | ||
if (javaNode != null) { | ||
toUpdate.add(javaNode); | ||
if (node instanceof JMethod) { | ||
toUpdate.addAll(((JMethod) node).getJavaMethod().getOverrideRelatedMethods()); | ||
} | ||
} else { | ||
throw new JadxRuntimeException("Unexpected node type: " + node); | ||
} | ||
Set<JClass> updatedTopClasses = toUpdate | ||
.stream() | ||
.map(JavaNode::getTopParentClass) | ||
.map(nodeCache::makeFrom) | ||
.filter(Objects::nonNull) | ||
.collect(Collectors.toSet()); | ||
|
||
LOG.debug("Classes to update: {}", updatedTopClasses); | ||
|
||
refreshTabs(mainWindow.getTabbedPane(), updatedTopClasses); | ||
|
||
if (!updatedTopClasses.isEmpty()) { | ||
mainWindow.getBackgroundExecutor().execute("Refreshing", | ||
() -> refreshClasses(updatedTopClasses), | ||
(status) -> { | ||
if (status == TaskStatus.CANCEL_BY_MEMORY) { | ||
mainWindow.showHeapUsageBar(); | ||
} | ||
if (node instanceof JPackage) { | ||
mainWindow.getTreeRoot().update(); | ||
} | ||
mainWindow.reloadTree(); | ||
}); | ||
} | ||
} | ||
|
||
private void refreshClasses(Set<JClass> updatedTopClasses) { | ||
if (updatedTopClasses.size() < 10) { | ||
// small batch => reload | ||
LOG.debug("Classes to reload: {}", updatedTopClasses.size()); | ||
for (JClass cls : updatedTopClasses) { | ||
try { | ||
cls.reload(cache); | ||
} catch (Exception e) { | ||
LOG.error("Failed to reload class: {}", cls.getFullName(), e); | ||
} | ||
} | ||
} else { | ||
// big batch => unload | ||
LOG.debug("Classes to unload: {}", updatedTopClasses.size()); | ||
for (JClass cls : updatedTopClasses) { | ||
try { | ||
cls.unload(cache); | ||
} catch (Exception e) { | ||
LOG.error("Failed to unload class: {}", cls.getFullName(), e); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void refreshTabs(TabbedPane tabbedPane, Set<JClass> updatedClasses) { | ||
for (Map.Entry<JNode, ContentPanel> entry : tabbedPane.getOpenTabs().entrySet()) { | ||
JClass rootClass = entry.getKey().getRootClass(); | ||
if (updatedClasses.remove(rootClass)) { | ||
ClassCodeContentPanel contentPanel = (ClassCodeContentPanel) entry.getValue(); | ||
CodeArea codeArea = (CodeArea) contentPanel.getJavaCodePanel().getCodeArea(); | ||
codeArea.refreshClass(); | ||
} | ||
} | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
...-jadxecute/jadx-gui/src/main/java/jadx/gui/plugins/jadxecute/ErrorHighlightingLinter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package jadx.gui.plugins.jadxecute; | ||
|
||
public class ErrorHighlightingLinter { | ||
|
||
} |
Oops, something went wrong.