Skip to content

Commit 30d7152

Browse files
committed
Map all apk resource IDs (big performance boost)
1 parent 2ebfacc commit 30d7152

File tree

1 file changed

+21
-18
lines changed

1 file changed

+21
-18
lines changed

lib/apk_installer.dart

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ extension on String {
4545
return (matches.isNotEmpty) ? matches.first.group(group)! : null;
4646
}
4747

48+
Map<K, V> foldToMap<K,V>(String regexp, K Function(RegExpMatch match) key, V Function(RegExpMatch match, V? prev) value) {
49+
Map<K,V> map = {};
50+
for (var m in RegExp(regexp).allMatches(this)) map.update(key(m), (v) => value(m, v), ifAbsent: () => value(m, null));
51+
return map;
52+
}
53+
4854
Map<K, V> toMap<K,V>(String regexp, K Function(RegExpMatch match) key, V Function(RegExpMatch match) value) {
4955
return {for (var m in RegExp(regexp).allMatches(this)) key(m) : value(m)};
5056
}
@@ -100,7 +106,7 @@ class ApkReader {
100106
//I just put '&& true' there so I could conveniently switch it off
101107
static bool DEBUG = !kReleaseMode && true;
102108
static String TEST_FILE = /*r'C:\Users\Alex\Downloads\com.atono.dropticket.apk'*/ '';
103-
static late Future<String> resourceDump;
109+
static late Future<Map<String, Resource>> resourceDump;
104110
static late Future<Map<int, String>> stringDump;
105111
static late Future<Archive> apkArchive;
106112

@@ -137,24 +143,18 @@ class ApkReader {
137143
.replaceAllMapped(RegExp('([cC]olor=[\'"])(type([0-9])+/([0-9]*))'), (m) => m.group(1)!+'#'+(int.parse(m.group(4)!).toRadixString(16).padLeft(8, '0')) )
138144
.replaceAllMapped(RegExp('([\\s\\n]android:fillType=[\'"])([0-9]*)'), (m) => m.group(1)!+ (fillType[m.group(2)!] ?? "winding") );
139145
}
140-
141-
//TODO use a map to avoid searching for values twice
146+
142147
static Future<Resource?> getResources(String resId) async {
143-
String resources = await resourceDump;
144-
ResType? type;
148+
Map<String, Resource> resources = await resourceDump;
145149
if (DEBUG) log("checking RES-ID: $resId");
146-
Iterable<dynamic>? resCodes = resources.findAllAnd('(^|\\s|\\n)*$resId[\\s]+.*\\st=0x0*([^\\s\\n]*).*\\sd=0x0*([^\\s\\n]*)[\\s|\\n]', (m) =>
147-
((type ??= getResType(m.group(2)!)) == ResType.FILE) ? int.parse(m.group(3)!, radix: 16) : m.group(3)! );
148-
if (resCodes.isNotEmpty) {
149-
if (DEBUG) log("found RES-VALUES: $resCodes of RES-TYPE: $type for RES-ID: $resId");
150-
//Fix 'type' not resolved in release mode because of the lazy nature of the 'map' function
151-
resCodes.first;
152-
if (type == ResType.COLOR) return Resource(resCodes.map((e)=>e), type!);
153-
//resCodes as Iterable<int>;
150+
var resource = resources[resId];
151+
if (resource != null) {
152+
if (DEBUG) log("found RES-VALUES: ${resource.values} of RES-TYPE: ${resource.type} for RES-ID: $resId");
153+
if (resource.type == ResType.COLOR) return resource;
154154
Map<int, String> strings = await stringDump;
155-
Iterable<String> files = strings.getAll(resCodes.map((e) => e));
156-
if (DEBUG) log("found RES-FILES: $files of RES-TYPE: $type for RES-ID: $resId");
157-
return files.isNotEmpty ? Resource(files, type!) : null;
155+
Iterable<String> files = strings.getAll(resource.values.map((e) => int.parse(e, radix: 16)));
156+
if (DEBUG) log("found RES-FILES: $files of RES-TYPE: ${resource.type} for RES-ID: $resId");
157+
return files.isNotEmpty ? Resource(files, resource.type) : null;
158158
}
159159
else return null;
160160
}
@@ -242,9 +242,12 @@ class ApkReader {
242242
data = pData;
243243
TEST_FILE = data.fileName;
244244
//resourceDump = Process.run('${Env.TOOLS_DIR}\\aapt.exe', ['dump', 'resources', TEST_FILE]).then<String>((p) => p.stdout.toString());
245-
resourceDump = Process.run('${Env.TOOLS_DIR}\\aapt.exe', ['dump', 'resources', TEST_FILE]).then<String>((p) => p.stdout.toString());
245+
resourceDump = Process.run('${Env.TOOLS_DIR}\\aapt.exe', ['dump', 'resources', TEST_FILE]).then((p) =>
246+
p.stdout.toString().foldToMap(r'(^|\n)\s*resource (0x[0-9a-zA-Z]*)[\s]+.*\st=0x0*([^\s\n]*).*\sd=0x0*([^\s\n]*)[\s|\n]', (m) => m.group(2)!,
247+
(m,old) => Resource((old != null) ? ((old.values as ListQueue<String>)..addAll([m.group(4)!])) : ListQueue<String>.from([m.group(4)!]), old?.type ?? getResType(m.group(3)!)) )
248+
);
246249
//strings.findAll('(^|\\n|\\s)*String\\s+#(${resCodes.join("|")})\\s*:\\s*([^\\s\\n]*)', 3);
247-
stringDump = Process.run('${Env.TOOLS_DIR}\\aapt.exe', ['dump', 'strings', TEST_FILE]).then<Map<int,String>>((p) =>
250+
stringDump = Process.run('${Env.TOOLS_DIR}\\aapt.exe', ['dump', 'strings', TEST_FILE]).then((p) =>
248251
p.stdout.toString().toMap(r'(^|\n|\s)*String\s+#([0-9]*)\s*:\s*([^\s\n]*)', (m) => int.parse(m.group(2)!), (m) => m.group(3)!)
249252
);
250253
initArchive();

0 commit comments

Comments
 (0)