capacitor-dex-editor 0.0.53 → 0.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/assets/colors.json +19 -19
- package/android/src/main/java/com/aetherlink/dexeditor/DexManager.java +45 -53
- package/android/src/main/java/com/android/tools/smali/smali2/Smali.java +102 -0
- package/android/src/main/java/com/android/tools/smali/smali2/SmaliCatchErrFlexLexer.java +54 -0
- package/android/src/main/java/com/android/tools/smali/smali2/SmaliCatchErrParser.java +49 -0
- package/android/src/main/java/com/android/tools/smali/smali2/SmaliCatchErrTreeWalker.java +49 -0
- package/android/src/main/java/com/android/tools/smali/smali2/SyntaxError.java +42 -0
- package/package.json +1 -1
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
|
-
"default": { "day": "#000000", "night": "#
|
|
3
|
-
"string": { "day": "#067D17", "night": "#
|
|
4
|
-
"strEscape": { "day": "#0037A6", "night": "#
|
|
5
|
-
"comment": { "day": "#8C8C8C", "night": "#
|
|
6
|
-
"meta": { "day": "#9E880D", "night": "#
|
|
7
|
-
"number": { "day": "#1750EB", "night": "#
|
|
8
|
-
"keyword": { "day": "#0033B3", "night": "#
|
|
9
|
-
"keyword2": { "day": "#800000", "night": "#
|
|
10
|
-
"constant": { "day": "#871094", "night": "#
|
|
11
|
-
"type": { "day": "#808000", "night": "#
|
|
12
|
-
"label": { "day": "#7050E0", "night": "#
|
|
13
|
-
"variable": { "day": "#1750EB", "night": "#
|
|
14
|
-
"operator": { "day": "#205060", "night": "#
|
|
15
|
-
"propKey": { "day": "#083080", "night": "#
|
|
16
|
-
"propVal": { "day": "#067D17", "night": "#
|
|
17
|
-
"tagName": { "day": "#0030B3", "night": "#
|
|
18
|
-
"attrName": { "day": "#174AD4", "night": "#
|
|
19
|
-
"namespace": { "day": "#871094", "night": "#
|
|
20
|
-
"error": { "day": "#F50000", "night": "#
|
|
2
|
+
"default": { "day": "#000000", "night": "#D4D4D4" },
|
|
3
|
+
"string": { "day": "#067D17", "night": "#CE9178" },
|
|
4
|
+
"strEscape": { "day": "#0037A6", "night": "#D7BA7D" },
|
|
5
|
+
"comment": { "day": "#8C8C8C", "night": "#6A9955" },
|
|
6
|
+
"meta": { "day": "#9E880D", "night": "#DCDCAA" },
|
|
7
|
+
"number": { "day": "#1750EB", "night": "#B5CEA8" },
|
|
8
|
+
"keyword": { "day": "#0033B3", "night": "#569CD6" },
|
|
9
|
+
"keyword2": { "day": "#800000", "night": "#C586C0" },
|
|
10
|
+
"constant": { "day": "#871094", "night": "#9CDCFE" },
|
|
11
|
+
"type": { "day": "#808000", "night": "#4EC9B0" },
|
|
12
|
+
"label": { "day": "#7050E0", "night": "#DCDCAA" },
|
|
13
|
+
"variable": { "day": "#1750EB", "night": "#9CDCFE" },
|
|
14
|
+
"operator": { "day": "#205060", "night": "#D4D4D4" },
|
|
15
|
+
"propKey": { "day": "#083080", "night": "#9CDCFE" },
|
|
16
|
+
"propVal": { "day": "#067D17", "night": "#CE9178" },
|
|
17
|
+
"tagName": { "day": "#0030B3", "night": "#569CD6" },
|
|
18
|
+
"attrName": { "day": "#174AD4", "night": "#9CDCFE" },
|
|
19
|
+
"namespace": { "day": "#871094", "night": "#4EC9B0" },
|
|
20
|
+
"error": { "day": "#F50000", "night": "#F44747" }
|
|
21
21
|
}
|
|
@@ -2232,51 +2232,31 @@ public class DexManager {
|
|
|
2232
2232
|
}
|
|
2233
2233
|
|
|
2234
2234
|
try {
|
|
2235
|
-
//
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
result.put("error", "无法创建临时目录");
|
|
2240
|
-
return result;
|
|
2241
|
-
}
|
|
2242
|
-
|
|
2243
|
-
// 将类名转换为文件路径
|
|
2244
|
-
String classPath = className.replace(".", "/") + ".smali";
|
|
2245
|
-
java.io.File smaliFile = new java.io.File(tempDir, classPath);
|
|
2246
|
-
smaliFile.getParentFile().mkdirs();
|
|
2247
|
-
|
|
2248
|
-
// 写入 smali 文件
|
|
2249
|
-
try (java.io.FileWriter writer = new java.io.FileWriter(smaliFile)) {
|
|
2250
|
-
writer.write(smaliContent);
|
|
2251
|
-
}
|
|
2252
|
-
|
|
2253
|
-
Log.d(TAG, "Smali file written to: " + smaliFile.getAbsolutePath());
|
|
2254
|
-
|
|
2255
|
-
// 使用 smali 库编译 smali 文件为 dex
|
|
2256
|
-
// 注意:这需要 smali 库的支持
|
|
2257
|
-
java.io.File outputDex = new java.io.File(tempDir, "classes_modified.dex");
|
|
2235
|
+
// 使用优化的 smali2.Smali 直接编译成 ClassDef(无需临时文件)
|
|
2236
|
+
reportTitle("编译 Smali");
|
|
2237
|
+
reportMessage("正在编译 " + className + "...");
|
|
2238
|
+
reportProgress(10, 100);
|
|
2258
2239
|
|
|
2259
|
-
// 使用 SmaliOptions 编译
|
|
2260
2240
|
com.android.tools.smali.smali.SmaliOptions options = new com.android.tools.smali.smali.SmaliOptions();
|
|
2261
|
-
options.outputDexFile = outputDex.getAbsolutePath();
|
|
2262
2241
|
options.apiLevel = 30;
|
|
2263
2242
|
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
if (!success) {
|
|
2243
|
+
// 直接编译 Smali 代码为 ClassDef
|
|
2244
|
+
ClassDef newClassDef;
|
|
2245
|
+
try {
|
|
2246
|
+
newClassDef = com.android.tools.smali.smali2.Smali.assemble(smaliContent, options, 35);
|
|
2247
|
+
} catch (Exception e) {
|
|
2270
2248
|
result.put("success", false);
|
|
2271
|
-
result.put("error", "Smali
|
|
2272
|
-
cleanupTempDir(tempDir);
|
|
2249
|
+
result.put("error", "Smali 编译失败: " + e.getMessage());
|
|
2273
2250
|
return result;
|
|
2274
2251
|
}
|
|
2275
2252
|
|
|
2276
|
-
|
|
2253
|
+
reportProgress(30, 100);
|
|
2254
|
+
Log.d(TAG, "Smali compiled successfully to ClassDef");
|
|
2255
|
+
|
|
2256
|
+
// 读取原 APK 中的 DEX 文件
|
|
2257
|
+
reportTitle("合并 DEX");
|
|
2258
|
+
reportMessage("读取原 DEX...");
|
|
2277
2259
|
|
|
2278
|
-
// 将编译后的类合并到原 DEX 文件中
|
|
2279
|
-
// 1. 读取原 APK 中的 DEX 文件
|
|
2280
2260
|
java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(apkPath);
|
|
2281
2261
|
java.util.zip.ZipEntry dexEntry = zipFile.getEntry(dexPath);
|
|
2282
2262
|
|
|
@@ -2284,14 +2264,13 @@ public class DexManager {
|
|
|
2284
2264
|
result.put("success", false);
|
|
2285
2265
|
result.put("error", "DEX 文件未找到: " + dexPath);
|
|
2286
2266
|
zipFile.close();
|
|
2287
|
-
cleanupTempDir(tempDir);
|
|
2288
2267
|
return result;
|
|
2289
2268
|
}
|
|
2290
2269
|
|
|
2291
2270
|
// 读取原 DEX
|
|
2292
2271
|
java.io.InputStream dexInputStream = zipFile.getInputStream(dexEntry);
|
|
2293
2272
|
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
|
|
2294
|
-
byte[] buffer = new byte[
|
|
2273
|
+
byte[] buffer = new byte[16384];
|
|
2295
2274
|
int len;
|
|
2296
2275
|
while ((len = dexInputStream.read(buffer)) != -1) {
|
|
2297
2276
|
baos.write(buffer, 0, len);
|
|
@@ -2299,12 +2278,12 @@ public class DexManager {
|
|
|
2299
2278
|
byte[] originalDexBytes = baos.toByteArray();
|
|
2300
2279
|
dexInputStream.close();
|
|
2301
2280
|
|
|
2302
|
-
// 解析原 DEX
|
|
2281
|
+
// 解析原 DEX
|
|
2303
2282
|
DexBackedDexFile originalDex = new DexBackedDexFile(Opcodes.getDefault(), originalDexBytes);
|
|
2304
|
-
DexBackedDexFile newDex = DexBackedDexFile.fromInputStream(Opcodes.getDefault(),
|
|
2305
|
-
new java.io.BufferedInputStream(new java.io.FileInputStream(outputDex)));
|
|
2306
2283
|
|
|
2307
|
-
|
|
2284
|
+
reportMessage("收集类定义...");
|
|
2285
|
+
reportProgress(40, 100);
|
|
2286
|
+
|
|
2308
2287
|
String targetType = "L" + className.replace(".", "/") + ";";
|
|
2309
2288
|
java.util.List<ClassDef> mergedClasses = new java.util.ArrayList<>();
|
|
2310
2289
|
|
|
@@ -2316,28 +2295,43 @@ public class DexManager {
|
|
|
2316
2295
|
}
|
|
2317
2296
|
|
|
2318
2297
|
// 添加新编译的类
|
|
2319
|
-
|
|
2320
|
-
mergedClasses.add(classDef);
|
|
2321
|
-
}
|
|
2298
|
+
mergedClasses.add(newClassDef);
|
|
2322
2299
|
|
|
2323
2300
|
Log.d(TAG, "Merged " + mergedClasses.size() + " classes");
|
|
2324
2301
|
|
|
2325
|
-
// 创建新的 DEX
|
|
2326
|
-
|
|
2302
|
+
// 创建新的 DEX 文件(使用内存)
|
|
2303
|
+
reportMessage("写入 DEX (" + mergedClasses.size() + " 个类)...");
|
|
2304
|
+
reportProgress(50, 100);
|
|
2305
|
+
|
|
2327
2306
|
DexPool dexPool = new DexPool(Opcodes.getDefault());
|
|
2307
|
+
int totalClasses = mergedClasses.size();
|
|
2308
|
+
int currentClass = 0;
|
|
2328
2309
|
for (ClassDef classDef : mergedClasses) {
|
|
2329
2310
|
dexPool.internClass(classDef);
|
|
2311
|
+
currentClass++;
|
|
2312
|
+
if (currentClass % 100 == 0 || currentClass == totalClasses) {
|
|
2313
|
+
reportProgress(50 + (currentClass * 30 / totalClasses), 100);
|
|
2314
|
+
}
|
|
2330
2315
|
}
|
|
2331
|
-
dexPool.writeTo(new FileDataStore(mergedDexFile));
|
|
2332
2316
|
|
|
2333
|
-
|
|
2317
|
+
// 使用内存写入 DEX(避免临时文件)
|
|
2318
|
+
reportProgress(80, 100);
|
|
2319
|
+
com.android.tools.smali.dexlib2.writer.io.MemoryDataStore memoryStore =
|
|
2320
|
+
new com.android.tools.smali.dexlib2.writer.io.MemoryDataStore();
|
|
2321
|
+
dexPool.writeTo(memoryStore);
|
|
2322
|
+
byte[] newDexBytes = java.util.Arrays.copyOf(memoryStore.getBuffer(), memoryStore.getSize());
|
|
2323
|
+
|
|
2324
|
+
Log.d(TAG, "Merged DEX size: " + newDexBytes.length + " bytes");
|
|
2334
2325
|
|
|
2335
2326
|
zipFile.close();
|
|
2336
2327
|
|
|
2337
2328
|
// MT 风格:直接替换 APK 内的 DEX
|
|
2329
|
+
reportTitle("更新 APK");
|
|
2330
|
+
reportMessage("正在替换 DEX...");
|
|
2331
|
+
reportProgress(85, 100);
|
|
2332
|
+
|
|
2338
2333
|
java.io.File apkFile = new java.io.File(apkPath);
|
|
2339
2334
|
java.io.File tempApkFile = new java.io.File(apkPath + ".tmp");
|
|
2340
|
-
byte[] newDexBytes = readFileBytes(mergedDexFile);
|
|
2341
2335
|
|
|
2342
2336
|
Log.d(TAG, "Replacing DEX in APK (MT style)...");
|
|
2343
2337
|
|
|
@@ -2393,15 +2387,13 @@ public class DexManager {
|
|
|
2393
2387
|
}
|
|
2394
2388
|
|
|
2395
2389
|
Log.d(TAG, "APK updated successfully: " + apkPath);
|
|
2390
|
+
reportProgress(100, 100);
|
|
2396
2391
|
|
|
2397
2392
|
result.put("success", true);
|
|
2398
2393
|
result.put("message", "Smali 编译成功!APK 已更新");
|
|
2399
2394
|
result.put("apkPath", apkPath);
|
|
2400
2395
|
result.put("needSign", true);
|
|
2401
2396
|
|
|
2402
|
-
// 清理临时文件
|
|
2403
|
-
cleanupTempDir(tempDir);
|
|
2404
|
-
|
|
2405
2397
|
} catch (Exception e) {
|
|
2406
2398
|
Log.e(TAG, "Error saving smali: " + e.getMessage(), e);
|
|
2407
2399
|
result.put("success", false);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Based on Dex-Editor-Android by developer-krushna
|
|
3
|
+
* Original Author @MikeAndrson
|
|
4
|
+
*
|
|
5
|
+
* 直接将 Smali 代码编译成 ClassDef,无需临时文件
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
package com.android.tools.smali.smali2;
|
|
9
|
+
|
|
10
|
+
import com.android.tools.smali.dexlib2.Opcodes;
|
|
11
|
+
import com.android.tools.smali.dexlib2.iface.ClassDef;
|
|
12
|
+
import com.android.tools.smali.dexlib2.writer.builder.DexBuilder;
|
|
13
|
+
import com.android.tools.smali.smali.SmaliOptions;
|
|
14
|
+
|
|
15
|
+
import java.io.StringReader;
|
|
16
|
+
import org.antlr.runtime.CommonTokenStream;
|
|
17
|
+
import org.antlr.runtime.tree.CommonTree;
|
|
18
|
+
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
|
19
|
+
|
|
20
|
+
public class Smali {
|
|
21
|
+
|
|
22
|
+
public static ClassDef assemble(String smaliCode, SmaliOptions options, int dexVer)
|
|
23
|
+
throws Exception {
|
|
24
|
+
DexBuilder dexBuilder = new DexBuilder(Opcodes.forDexVersion(dexVer));
|
|
25
|
+
|
|
26
|
+
SmaliCatchErrFlexLexer lexer = new SmaliCatchErrFlexLexer(new StringReader(smaliCode), options.apiLevel);
|
|
27
|
+
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
|
28
|
+
|
|
29
|
+
SmaliCatchErrParser parser = new SmaliCatchErrParser(tokens);
|
|
30
|
+
parser.setVerboseErrors(options.verboseErrors);
|
|
31
|
+
parser.setAllowOdex(options.allowOdexOpcodes);
|
|
32
|
+
parser.setApiLevel(dexVer);
|
|
33
|
+
|
|
34
|
+
SmaliCatchErrParser.smali_file_return result = parser.smali_file();
|
|
35
|
+
|
|
36
|
+
if (lexer.getNumberOfSyntaxErrors() > 0) {
|
|
37
|
+
throw new Exception(lexer.getErrorsString());
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (parser.getNumberOfSyntaxErrors() > 0) {
|
|
41
|
+
throw new Exception(parser.getErrorsString());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
CommonTree t = result.getTree();
|
|
45
|
+
|
|
46
|
+
CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
|
|
47
|
+
treeStream.setTokenStream(tokens);
|
|
48
|
+
|
|
49
|
+
SmaliCatchErrTreeWalker treeWalker = new SmaliCatchErrTreeWalker(treeStream);
|
|
50
|
+
treeWalker.setApiLevel(dexVer);
|
|
51
|
+
treeWalker.setVerboseErrors(options.verboseErrors);
|
|
52
|
+
treeWalker.setDexBuilder(dexBuilder);
|
|
53
|
+
|
|
54
|
+
ClassDef classDef = treeWalker.smali_file();
|
|
55
|
+
|
|
56
|
+
if (treeWalker.getNumberOfSyntaxErrors() > 0) {
|
|
57
|
+
throw new Exception(treeWalker.getErrorsString());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return classDef;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public static ClassDef assemble(String smaliCode, SmaliOptions options) throws Exception {
|
|
64
|
+
DexBuilder dexBuilder = new DexBuilder(Opcodes.forApi(options.apiLevel));
|
|
65
|
+
|
|
66
|
+
SmaliCatchErrFlexLexer lexer = new SmaliCatchErrFlexLexer(new StringReader(smaliCode), options.apiLevel);
|
|
67
|
+
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
|
68
|
+
|
|
69
|
+
SmaliCatchErrParser parser = new SmaliCatchErrParser(tokens);
|
|
70
|
+
parser.setVerboseErrors(options.verboseErrors);
|
|
71
|
+
parser.setAllowOdex(options.allowOdexOpcodes);
|
|
72
|
+
parser.setApiLevel(options.apiLevel);
|
|
73
|
+
|
|
74
|
+
SmaliCatchErrParser.smali_file_return result = parser.smali_file();
|
|
75
|
+
|
|
76
|
+
if (lexer.getNumberOfSyntaxErrors() > 0) {
|
|
77
|
+
throw new Exception(lexer.getErrorsString());
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (parser.getNumberOfSyntaxErrors() > 0) {
|
|
81
|
+
throw new Exception(parser.getErrorsString());
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
CommonTree t = result.getTree();
|
|
85
|
+
|
|
86
|
+
CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
|
|
87
|
+
treeStream.setTokenStream(tokens);
|
|
88
|
+
|
|
89
|
+
SmaliCatchErrTreeWalker treeWalker = new SmaliCatchErrTreeWalker(treeStream);
|
|
90
|
+
treeWalker.setApiLevel(options.apiLevel);
|
|
91
|
+
treeWalker.setVerboseErrors(options.verboseErrors);
|
|
92
|
+
treeWalker.setDexBuilder(dexBuilder);
|
|
93
|
+
|
|
94
|
+
ClassDef classDef = treeWalker.smali_file();
|
|
95
|
+
|
|
96
|
+
if (treeWalker.getNumberOfSyntaxErrors() > 0) {
|
|
97
|
+
throw new Exception(treeWalker.getErrorsString());
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return classDef;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Based on Dex-Editor-Android by developer-krushna
|
|
3
|
+
* Original Author @MikeAndrson
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
package com.android.tools.smali.smali2;
|
|
7
|
+
|
|
8
|
+
import com.android.tools.smali.smali.InvalidToken;
|
|
9
|
+
import com.android.tools.smali.smali.smaliFlexLexer;
|
|
10
|
+
|
|
11
|
+
import java.io.Reader;
|
|
12
|
+
import java.util.ArrayList;
|
|
13
|
+
import java.util.List;
|
|
14
|
+
|
|
15
|
+
public class SmaliCatchErrFlexLexer extends smaliFlexLexer {
|
|
16
|
+
|
|
17
|
+
private StringBuilder errors = new StringBuilder();
|
|
18
|
+
private List<SyntaxError> syntaxErrors = new ArrayList<>();
|
|
19
|
+
|
|
20
|
+
public SmaliCatchErrFlexLexer(Reader reader, int apiLevel) {
|
|
21
|
+
super(reader, apiLevel);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Override
|
|
25
|
+
public String getErrorHeader(InvalidToken invalidToken) {
|
|
26
|
+
errors.append("[")
|
|
27
|
+
.append(invalidToken.getLine())
|
|
28
|
+
.append(",")
|
|
29
|
+
.append(invalidToken.getCharPositionInLine())
|
|
30
|
+
.append("] Error for input '")
|
|
31
|
+
.append(invalidToken.getText())
|
|
32
|
+
.append("': ")
|
|
33
|
+
.append(invalidToken.getMessage())
|
|
34
|
+
.append("\n");
|
|
35
|
+
|
|
36
|
+
syntaxErrors.add(new SyntaxError(
|
|
37
|
+
invalidToken.getLine(),
|
|
38
|
+
invalidToken.getCharPositionInLine(),
|
|
39
|
+
invalidToken.getLine(),
|
|
40
|
+
invalidToken.getCharPositionInLine() + invalidToken.getText().length(),
|
|
41
|
+
invalidToken.getMessage()
|
|
42
|
+
));
|
|
43
|
+
|
|
44
|
+
return super.getErrorHeader(invalidToken);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public String getErrorsString() {
|
|
48
|
+
return errors.toString();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public List<SyntaxError> getErrors() {
|
|
52
|
+
return syntaxErrors;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Based on Dex-Editor-Android by developer-krushna
|
|
3
|
+
* Original Author @MikeAndrson
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
package com.android.tools.smali.smali2;
|
|
7
|
+
|
|
8
|
+
import org.antlr.runtime.CommonTokenStream;
|
|
9
|
+
import org.antlr.runtime.RecognitionException;
|
|
10
|
+
import com.android.tools.smali.smali.smaliParser;
|
|
11
|
+
|
|
12
|
+
import java.util.ArrayList;
|
|
13
|
+
import java.util.List;
|
|
14
|
+
|
|
15
|
+
public class SmaliCatchErrParser extends smaliParser {
|
|
16
|
+
|
|
17
|
+
private StringBuilder errors = new StringBuilder();
|
|
18
|
+
private List<SyntaxError> syntaxErrors = new ArrayList<>();
|
|
19
|
+
|
|
20
|
+
public SmaliCatchErrParser(CommonTokenStream tokens) {
|
|
21
|
+
super(tokens);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Override
|
|
25
|
+
public void emitErrorMessage(String msg) {
|
|
26
|
+
errors.append(msg).append("\n");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public String getErrorsString() {
|
|
30
|
+
return errors.toString();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Override
|
|
34
|
+
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
|
|
35
|
+
syntaxErrors.add(new SyntaxError(
|
|
36
|
+
e.line,
|
|
37
|
+
e.charPositionInLine,
|
|
38
|
+
e.line,
|
|
39
|
+
e.charPositionInLine + (e.token != null ? e.token.getText().length() : 1),
|
|
40
|
+
getErrorMessage(e, tokenNames)
|
|
41
|
+
));
|
|
42
|
+
|
|
43
|
+
super.displayRecognitionError(tokenNames, e);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public List<SyntaxError> getErrors() {
|
|
47
|
+
return syntaxErrors;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Based on Dex-Editor-Android by developer-krushna
|
|
3
|
+
* Original Author @MikeAndrson
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
package com.android.tools.smali.smali2;
|
|
7
|
+
|
|
8
|
+
import org.antlr.runtime.RecognitionException;
|
|
9
|
+
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
|
10
|
+
import com.android.tools.smali.smali.smaliTreeWalker;
|
|
11
|
+
|
|
12
|
+
import java.util.ArrayList;
|
|
13
|
+
import java.util.List;
|
|
14
|
+
|
|
15
|
+
public class SmaliCatchErrTreeWalker extends smaliTreeWalker {
|
|
16
|
+
|
|
17
|
+
private StringBuilder errors = new StringBuilder();
|
|
18
|
+
private List<SyntaxError> syntaxErrors = new ArrayList<>();
|
|
19
|
+
|
|
20
|
+
public SmaliCatchErrTreeWalker(CommonTreeNodeStream treeStream) {
|
|
21
|
+
super(treeStream);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Override
|
|
25
|
+
public void emitErrorMessage(String msg) {
|
|
26
|
+
errors.append(msg);
|
|
27
|
+
errors.append("\n");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public String getErrorsString() {
|
|
31
|
+
return errors.toString();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@Override
|
|
35
|
+
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
|
|
36
|
+
syntaxErrors.add(new SyntaxError(
|
|
37
|
+
e.line,
|
|
38
|
+
e.charPositionInLine,
|
|
39
|
+
e.line,
|
|
40
|
+
e.charPositionInLine + (e.token != null ? e.token.getText().length() : 1),
|
|
41
|
+
getErrorMessage(e, tokenNames)
|
|
42
|
+
));
|
|
43
|
+
super.displayRecognitionError(tokenNames, e);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public List<SyntaxError> getErrors() {
|
|
47
|
+
return syntaxErrors;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Based on Dex-Editor-Android by developer-krushna
|
|
3
|
+
* Original Author @MikeAndrson
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
package com.android.tools.smali.smali2;
|
|
7
|
+
|
|
8
|
+
public class SyntaxError {
|
|
9
|
+
private final int startLine;
|
|
10
|
+
private final int startColumn;
|
|
11
|
+
private final int endLine;
|
|
12
|
+
private final int endColumn;
|
|
13
|
+
private final String message;
|
|
14
|
+
|
|
15
|
+
public SyntaxError(int startLine, int startColumn, int endLine, int endColumn, String message) {
|
|
16
|
+
this.startLine = startLine;
|
|
17
|
+
this.startColumn = startColumn;
|
|
18
|
+
this.endLine = endLine;
|
|
19
|
+
this.endColumn = endColumn;
|
|
20
|
+
this.message = message;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public int getStartLine() {
|
|
24
|
+
return startLine;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public int getStartColumn() {
|
|
28
|
+
return startColumn;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public int getEndLine() {
|
|
32
|
+
return endLine;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public int getEndColumn() {
|
|
36
|
+
return endColumn;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public String getMessage() {
|
|
40
|
+
return message;
|
|
41
|
+
}
|
|
42
|
+
}
|