Skip to content

Commit fe9a1f0

Browse files
committed
Merge jadxecute code into new version
1 parent 0f298b7 commit fe9a1f0

File tree

9 files changed

+1663
-0
lines changed

9 files changed

+1663
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
package jadx.gui.plugins.jadxecute;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collections;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.Objects;
8+
import java.util.Set;
9+
import java.util.function.Consumer;
10+
import java.util.stream.Collectors;
11+
12+
import org.slf4j.Logger;
13+
import org.slf4j.LoggerFactory;
14+
15+
import jadx.api.JavaNode;
16+
import jadx.api.data.ICodeComment;
17+
import jadx.api.data.impl.JadxCodeComment;
18+
import jadx.api.data.impl.JadxCodeData;
19+
import jadx.api.data.impl.JadxCodeRef;
20+
import jadx.api.data.impl.JadxNodeRef;
21+
import jadx.gui.treemodel.JClass;
22+
import jadx.gui.ui.MainWindow;
23+
import jadx.gui.ui.codearea.CodeArea;
24+
import jadx.gui.settings.JadxProject;
25+
26+
import jadx.api.JavaVariable;
27+
import jadx.core.utils.exceptions.JadxRuntimeException;
28+
import jadx.gui.jobs.TaskStatus;
29+
import jadx.gui.treemodel.JMethod;
30+
import jadx.gui.treemodel.JNode;
31+
import jadx.gui.treemodel.JPackage;
32+
import jadx.gui.ui.TabbedPane;
33+
import jadx.gui.ui.codearea.ClassCodeContentPanel;
34+
import jadx.gui.ui.panel.ContentPanel;
35+
import jadx.gui.utils.CacheObject;
36+
import jadx.gui.utils.JNodeCache;
37+
38+
public class AddCommentHelper {
39+
private static final Logger LOG = LoggerFactory.getLogger(AddCommentHelper.class);
40+
41+
private MainWindow mainWindow;
42+
private CacheObject cache;
43+
private String newCommentString;
44+
private JavaNode node;
45+
private boolean updateComment;
46+
47+
public AddCommentHelper(MainWindow mainWindow, JavaNode node) {
48+
this.mainWindow = mainWindow;
49+
this.cache = mainWindow.getCacheObject();
50+
this.node = node;
51+
}
52+
53+
// To be implemented
54+
/*
55+
public String addVariableComment(String newCommentString, JavaVariable javaVariable) {
56+
this.newCommentString = newCommentString;
57+
58+
ICodeComment blankComment = new JadxCodeComment(JadxNodeRef.forJavaNode(node), JadxCodeRef.forVar(javaVariable), "");
59+
if (blankComment == null) {
60+
return "Failed to add comment";
61+
}
62+
63+
ICodeComment existComment = searchForExistComment(blankComment);
64+
if (existComment != null) {
65+
this.updateComment = true;
66+
apply(existComment, javaVariable);
67+
} else {
68+
this.updateComment = false;
69+
apply(blankComment, javaVariable);
70+
}
71+
72+
return "Added comment in " + node.getFullName() + " for variable " + javaVariable.getName();
73+
}
74+
*/
75+
76+
public String addInstructionComment(String newCommentString, int commentSmaliOffset) {
77+
this.newCommentString = newCommentString;
78+
79+
ICodeComment blankComment = new JadxCodeComment(JadxNodeRef.forJavaNode(node), JadxCodeRef.forInsn(commentSmaliOffset), "");
80+
if (blankComment == null) {
81+
return "Failed to add comment";
82+
}
83+
84+
ICodeComment existComment = searchForExistComment(blankComment);
85+
if (existComment != null) {
86+
this.updateComment = true;
87+
apply(existComment, commentSmaliOffset);
88+
} else {
89+
this.updateComment = false;
90+
apply(blankComment, commentSmaliOffset);
91+
}
92+
93+
return "Added comment in " + node.getFullName() + " at offset " + commentSmaliOffset;
94+
}
95+
96+
private void apply(ICodeComment comment, int commentOffset) {
97+
if (newCommentString.isEmpty()) {
98+
if (updateComment) {
99+
updateCommentsData(list -> list.removeIf(c -> c == comment));
100+
}
101+
return;
102+
}
103+
104+
ICodeComment newComment = new JadxCodeComment(JadxNodeRef.forJavaNode(node), JadxCodeRef.forInsn(commentOffset), newCommentString);
105+
if (updateComment) {
106+
updateCommentsData(list -> {
107+
list.remove(comment);
108+
list.add(newComment);
109+
});
110+
} else {
111+
updateCommentsData(list -> list.add(newComment));
112+
}
113+
}
114+
115+
private void apply(ICodeComment comment, JavaVariable javaVariable) {
116+
if (newCommentString.isEmpty()) {
117+
if (updateComment) {
118+
updateCommentsData(list -> list.removeIf(c -> c == comment));
119+
}
120+
return;
121+
}
122+
123+
ICodeComment newComment = new JadxCodeComment(JadxNodeRef.forJavaNode(node), JadxCodeRef.forVar(javaVariable), newCommentString);
124+
if (updateComment) {
125+
updateCommentsData(list -> {
126+
list.remove(comment);
127+
list.add(newComment);
128+
});
129+
} else {
130+
updateCommentsData(list -> list.add(newComment));
131+
}
132+
}
133+
134+
private ICodeComment searchForExistComment(ICodeComment blankComment) {
135+
try {
136+
JadxProject project = mainWindow.getProject();
137+
JadxCodeData codeData = project.getCodeData();
138+
if (codeData == null || codeData.getComments().isEmpty()) {
139+
return null;
140+
}
141+
for (ICodeComment comment : codeData.getComments()) {
142+
if (Objects.equals(comment.getNodeRef(), blankComment.getNodeRef())
143+
&& Objects.equals(comment.getCodeRef(), blankComment.getCodeRef())) {
144+
return comment;
145+
}
146+
}
147+
} catch (Exception e) {
148+
LOG.error("Error searching for exists comment", e);
149+
}
150+
return null;
151+
}
152+
153+
private String updateCommentsData(Consumer<List<ICodeComment>> updater) {
154+
JadxProject project = mainWindow.getProject();
155+
JadxCodeData codeData = project.getCodeData();
156+
157+
try {
158+
if (codeData == null) {
159+
codeData = new JadxCodeData();
160+
}
161+
List<ICodeComment> list = new ArrayList<>(codeData.getComments());
162+
163+
updater.accept(list);
164+
Collections.sort(list);
165+
codeData.setComments(list);
166+
project.setCodeData(codeData);
167+
mainWindow.getWrapper().reloadCodeData();
168+
} catch (Exception e) {
169+
LOG.error("Comment action failed", e);
170+
}
171+
try {
172+
refreshState();
173+
} catch (Exception e) {
174+
LOG.error("Failed to reload code", e);
175+
}
176+
177+
String retval = "";
178+
179+
for (ICodeComment comment : codeData.getComments()) {
180+
retval += comment.getComment() + "\n";
181+
}
182+
return retval;
183+
}
184+
185+
private void refreshState() {
186+
mainWindow.getWrapper().reInitRenameVisitor();
187+
188+
JNodeCache nodeCache = cache.getNodeCache();
189+
JavaNode javaNode = node;
190+
191+
List<JavaNode> toUpdate = new ArrayList<>();
192+
if (javaNode != null) {
193+
toUpdate.add(javaNode);
194+
if (node instanceof JMethod) {
195+
toUpdate.addAll(((JMethod) node).getJavaMethod().getOverrideRelatedMethods());
196+
}
197+
} else {
198+
throw new JadxRuntimeException("Unexpected node type: " + node);
199+
}
200+
Set<JClass> updatedTopClasses = toUpdate
201+
.stream()
202+
.map(JavaNode::getTopParentClass)
203+
.map(nodeCache::makeFrom)
204+
.filter(Objects::nonNull)
205+
.collect(Collectors.toSet());
206+
207+
LOG.debug("Classes to update: {}", updatedTopClasses);
208+
209+
refreshTabs(mainWindow.getTabbedPane(), updatedTopClasses);
210+
211+
if (!updatedTopClasses.isEmpty()) {
212+
mainWindow.getBackgroundExecutor().execute("Refreshing",
213+
() -> refreshClasses(updatedTopClasses),
214+
(status) -> {
215+
if (status == TaskStatus.CANCEL_BY_MEMORY) {
216+
mainWindow.showHeapUsageBar();
217+
}
218+
if (node instanceof JPackage) {
219+
mainWindow.getTreeRoot().update();
220+
}
221+
mainWindow.reloadTree();
222+
});
223+
}
224+
}
225+
226+
private void refreshClasses(Set<JClass> updatedTopClasses) {
227+
if (updatedTopClasses.size() < 10) {
228+
// small batch => reload
229+
LOG.debug("Classes to reload: {}", updatedTopClasses.size());
230+
for (JClass cls : updatedTopClasses) {
231+
try {
232+
cls.reload(cache);
233+
} catch (Exception e) {
234+
LOG.error("Failed to reload class: {}", cls.getFullName(), e);
235+
}
236+
}
237+
} else {
238+
// big batch => unload
239+
LOG.debug("Classes to unload: {}", updatedTopClasses.size());
240+
for (JClass cls : updatedTopClasses) {
241+
try {
242+
cls.unload(cache);
243+
} catch (Exception e) {
244+
LOG.error("Failed to unload class: {}", cls.getFullName(), e);
245+
}
246+
}
247+
}
248+
}
249+
250+
private void refreshTabs(TabbedPane tabbedPane, Set<JClass> updatedClasses) {
251+
for (Map.Entry<JNode, ContentPanel> entry : tabbedPane.getOpenTabs().entrySet()) {
252+
JClass rootClass = entry.getKey().getRootClass();
253+
if (updatedClasses.remove(rootClass)) {
254+
ClassCodeContentPanel contentPanel = (ClassCodeContentPanel) entry.getValue();
255+
CodeArea codeArea = (CodeArea) contentPanel.getJavaCodePanel().getCodeArea();
256+
codeArea.refreshClass();
257+
}
258+
}
259+
}
260+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package jadx.gui.plugins.jadxecute;
2+
3+
public class ErrorHighlightingLinter {
4+
5+
}

0 commit comments

Comments
 (0)