capacitor-dex-editor 0.0.78 → 0.0.79
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/cpp/jni_bridge.cpp +150 -94
- package/package.json +1 -1
|
@@ -121,112 +121,168 @@ Java_com_aetherlink_dexeditor_CppDex_listClasses(JNIEnv* env, jclass, jbyteArray
|
|
|
121
121
|
return string_to_jstring(env, result.dump());
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
dex::DexParser parser;
|
|
133
|
-
if (!parser.parse(data)) {
|
|
134
|
-
json error = {{"error", "Failed to parse DEX"}};
|
|
135
|
-
return string_to_jstring(env, error.dump());
|
|
124
|
+
// Helper: Safe ASCII lowercase (UTF-8 safe - only converts ASCII a-z)
|
|
125
|
+
static std::string safe_tolower_ascii(const std::string& s) {
|
|
126
|
+
std::string result = s;
|
|
127
|
+
for (char& c : result) {
|
|
128
|
+
if (c >= 'A' && c <= 'Z') {
|
|
129
|
+
c = c + ('a' - 'A');
|
|
130
|
+
}
|
|
136
131
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
std::transform(q_lower.begin(), q_lower.end(), q_lower.begin(), ::tolower);
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Helper: Safe string contains check (UTF-8 safe)
|
|
136
|
+
static bool safe_contains(const std::string& haystack, const std::string& needle, bool caseSensitive) {
|
|
137
|
+
if (caseSensitive) {
|
|
138
|
+
return haystack.find(needle) != std::string::npos;
|
|
145
139
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
140
|
+
// Only lowercase ASCII for case-insensitive search
|
|
141
|
+
std::string h_lower = safe_tolower_ascii(haystack);
|
|
142
|
+
std::string n_lower = safe_tolower_ascii(needle);
|
|
143
|
+
return h_lower.find(n_lower) != std::string::npos;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Helper: Sanitize string for JSON (replace invalid UTF-8 sequences)
|
|
147
|
+
static std::string sanitize_utf8(const std::string& s) {
|
|
148
|
+
std::string result;
|
|
149
|
+
result.reserve(s.size());
|
|
150
|
+
size_t i = 0;
|
|
151
|
+
while (i < s.size()) {
|
|
152
|
+
unsigned char c = s[i];
|
|
153
|
+
if (c < 0x80) {
|
|
154
|
+
// ASCII
|
|
155
|
+
result += c;
|
|
156
|
+
i++;
|
|
157
|
+
} else if ((c & 0xE0) == 0xC0 && i + 1 < s.size()) {
|
|
158
|
+
// 2-byte UTF-8
|
|
159
|
+
if ((s[i+1] & 0xC0) == 0x80) {
|
|
160
|
+
result += s[i];
|
|
161
|
+
result += s[i+1];
|
|
162
|
+
i += 2;
|
|
163
|
+
} else {
|
|
164
|
+
result += '?';
|
|
165
|
+
i++;
|
|
160
166
|
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
} else if ((c & 0xF0) == 0xE0 && i + 2 < s.size()) {
|
|
168
|
+
// 3-byte UTF-8
|
|
169
|
+
if ((s[i+1] & 0xC0) == 0x80 && (s[i+2] & 0xC0) == 0x80) {
|
|
170
|
+
result += s[i];
|
|
171
|
+
result += s[i+1];
|
|
172
|
+
result += s[i+2];
|
|
173
|
+
i += 3;
|
|
174
|
+
} else {
|
|
175
|
+
result += '?';
|
|
176
|
+
i++;
|
|
171
177
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
178
|
+
} else if ((c & 0xF8) == 0xF0 && i + 3 < s.size()) {
|
|
179
|
+
// 4-byte UTF-8
|
|
180
|
+
if ((s[i+1] & 0xC0) == 0x80 && (s[i+2] & 0xC0) == 0x80 && (s[i+3] & 0xC0) == 0x80) {
|
|
181
|
+
result += s[i];
|
|
182
|
+
result += s[i+1];
|
|
183
|
+
result += s[i+2];
|
|
184
|
+
result += s[i+3];
|
|
185
|
+
i += 4;
|
|
186
|
+
} else {
|
|
187
|
+
result += '?';
|
|
188
|
+
i++;
|
|
176
189
|
}
|
|
190
|
+
} else {
|
|
191
|
+
// Invalid UTF-8, replace with ?
|
|
192
|
+
result += '?';
|
|
193
|
+
i++;
|
|
177
194
|
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
195
|
+
}
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
JNIEXPORT jstring JNICALL
|
|
200
|
+
Java_com_aetherlink_dexeditor_CppDex_searchInDex(JNIEnv* env, jclass, jbyteArray dexBytes,
|
|
201
|
+
jstring query, jstring searchType,
|
|
202
|
+
jboolean caseSensitive, jint maxResults) {
|
|
203
|
+
try {
|
|
204
|
+
auto data = jbyteArray_to_vector(env, dexBytes);
|
|
205
|
+
std::string q = jstring_to_string(env, query);
|
|
206
|
+
std::string type = jstring_to_string(env, searchType);
|
|
207
|
+
|
|
208
|
+
dex::DexParser parser;
|
|
209
|
+
if (!parser.parse(data)) {
|
|
210
|
+
json error = {{"error", "Failed to parse DEX"}};
|
|
211
|
+
return string_to_jstring(env, error.dump());
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
json results = json::array();
|
|
215
|
+
int count = 0;
|
|
216
|
+
|
|
217
|
+
if (type == "string") {
|
|
218
|
+
for (const auto& s : parser.strings()) {
|
|
219
|
+
if (count >= maxResults) break;
|
|
220
|
+
|
|
221
|
+
if (safe_contains(s, q, caseSensitive)) {
|
|
222
|
+
// Sanitize string for JSON
|
|
223
|
+
results.push_back({{"type", "string"}, {"value", sanitize_utf8(s)}});
|
|
224
|
+
count++;
|
|
225
|
+
}
|
|
187
226
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
{"
|
|
195
|
-
|
|
196
|
-
|
|
227
|
+
} else if (type == "class") {
|
|
228
|
+
for (const auto& cls : parser.classes()) {
|
|
229
|
+
if (count >= maxResults) break;
|
|
230
|
+
std::string class_name = parser.get_class_name(cls.class_idx);
|
|
231
|
+
|
|
232
|
+
if (safe_contains(class_name, q, caseSensitive)) {
|
|
233
|
+
results.push_back({{"type", "class"}, {"name", sanitize_utf8(class_name)}});
|
|
234
|
+
count++;
|
|
235
|
+
}
|
|
197
236
|
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
237
|
+
} else if (type == "method") {
|
|
238
|
+
auto methods = parser.get_methods();
|
|
239
|
+
for (const auto& m : methods) {
|
|
240
|
+
if (count >= maxResults) break;
|
|
241
|
+
|
|
242
|
+
if (safe_contains(m.method_name, q, caseSensitive)) {
|
|
243
|
+
results.push_back({
|
|
244
|
+
{"type", "method"},
|
|
245
|
+
{"class", sanitize_utf8(m.class_name)},
|
|
246
|
+
{"name", sanitize_utf8(m.method_name)},
|
|
247
|
+
{"prototype", sanitize_utf8(m.prototype)}
|
|
248
|
+
});
|
|
249
|
+
count++;
|
|
250
|
+
}
|
|
208
251
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
{
|
|
216
|
-
|
|
217
|
-
|
|
252
|
+
} else if (type == "field") {
|
|
253
|
+
auto fields = parser.get_fields();
|
|
254
|
+
for (const auto& f : fields) {
|
|
255
|
+
if (count >= maxResults) break;
|
|
256
|
+
|
|
257
|
+
if (safe_contains(f.field_name, q, caseSensitive)) {
|
|
258
|
+
results.push_back({
|
|
259
|
+
{"type", "field"},
|
|
260
|
+
{"class", sanitize_utf8(f.class_name)},
|
|
261
|
+
{"name", sanitize_utf8(f.field_name)},
|
|
262
|
+
{"fieldType", sanitize_utf8(f.type_name)}
|
|
263
|
+
});
|
|
264
|
+
count++;
|
|
265
|
+
}
|
|
218
266
|
}
|
|
219
267
|
}
|
|
268
|
+
|
|
269
|
+
json result = {
|
|
270
|
+
{"query", sanitize_utf8(q)},
|
|
271
|
+
{"searchType", type},
|
|
272
|
+
{"results", results},
|
|
273
|
+
{"count", results.size()}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
return string_to_jstring(env, result.dump());
|
|
277
|
+
} catch (const std::exception& e) {
|
|
278
|
+
LOGE("searchInDex exception: %s", e.what());
|
|
279
|
+
json error = {{"error", std::string("Search failed: ") + e.what()}};
|
|
280
|
+
return string_to_jstring(env, error.dump());
|
|
281
|
+
} catch (...) {
|
|
282
|
+
LOGE("searchInDex unknown exception");
|
|
283
|
+
json error = {{"error", "Search failed: unknown error"}};
|
|
284
|
+
return string_to_jstring(env, error.dump());
|
|
220
285
|
}
|
|
221
|
-
|
|
222
|
-
json result = {
|
|
223
|
-
{"query", q},
|
|
224
|
-
{"searchType", type},
|
|
225
|
-
{"results", results},
|
|
226
|
-
{"count", results.size()}
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
return string_to_jstring(env, result.dump());
|
|
230
286
|
}
|
|
231
287
|
|
|
232
288
|
JNIEXPORT jstring JNICALL
|