mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-25 10:58:42 +00:00
Version 1 (#83)
* replace jq-promises with native Promises * updates to use native promises and async await * Fix variable errors, remove extra parameters and correct export declaratons * refactor launch request to use async/await * fix running debugger on custom ADB port * remove unused files * move socket_ended check to ensure we don't loop reading 0 bytes * refactor logcat code and ensure disconnect status is passed on to webview * Fix warnings * Clean up util and remove unused functions * convert Debugger into a class * update jsconfig target to es2018 and enable checkJS * more updates to use async/await and more readable refactoring. - added type definitions and debugger classes - improved expression evaluation - refactored expressions into parsing, evaluation and variable assignment - fixed invoking methods with parameters - added support for static method invokes - improved exception display reliability - refactored launch into smaller functions - refactored utils into smaller modules - removed redundant code - converted JDWP functions to classes * set version 1.0.0 and update dependencies * add changelog notes
This commit is contained in:
53
src/utils/char-decode.js
Normal file
53
src/utils/char-decode.js
Normal file
@@ -0,0 +1,53 @@
|
||||
const BACKSLASH_ESCAPE_MAP = {
|
||||
b: '\b',
|
||||
f: '\f',
|
||||
r: '\r',
|
||||
n: '\n',
|
||||
t: '\t',
|
||||
v: '\v',
|
||||
'0': '\0',
|
||||
'\\': '\\',
|
||||
};
|
||||
|
||||
/**
|
||||
* De-escape backslash escaped characters
|
||||
* @param {string} c
|
||||
*/
|
||||
function decode_char(c) {
|
||||
switch(true) {
|
||||
case /^\\u[0-9a-fA-F]{4}$/.test(c):
|
||||
// unicode escape
|
||||
return String.fromCharCode(parseInt(c.slice(2),16));
|
||||
|
||||
case /^\\.$/.test(c):
|
||||
// backslash escape
|
||||
const char = BACKSLASH_ESCAPE_MAP[c[1]];
|
||||
return char || c[1];
|
||||
|
||||
case c.length === 1:
|
||||
return c;
|
||||
}
|
||||
throw new Error('Invalid character value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Java string literal to a raw string
|
||||
* @param {string} s
|
||||
*/
|
||||
function decodeJavaStringLiteral(s) {
|
||||
return s.slice(1, -1).replace(/\\u[0-9a-fA-F]{4}|\\./g, decode_char);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Java char literal to a raw character
|
||||
* @param {string} s
|
||||
*/
|
||||
function decodeJavaCharLiteral(s) {
|
||||
return decode_char(s.slice(1, -1));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
decode_char,
|
||||
decodeJavaCharLiteral,
|
||||
decodeJavaStringLiteral,
|
||||
}
|
||||
103
src/utils/nbc.js
Normal file
103
src/utils/nbc.js
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
// arbitrary precision helper class for 64 bit numbers
|
||||
const NumberBaseConverter = {
|
||||
// Adds two arrays for the given base (10 or 16), returning the result.
|
||||
add(x, y, base) {
|
||||
const z = [], n = Math.max(x.length, y.length);
|
||||
let carry = 0;
|
||||
for (let i = 0; i < n || carry; i++) {
|
||||
const xi = i < x.length ? x[i] : 0;
|
||||
const yi = i < y.length ? y[i] : 0;
|
||||
const zi = carry + xi + yi;
|
||||
z.push(zi % base);
|
||||
carry = Math.floor(zi / base);
|
||||
}
|
||||
return z;
|
||||
},
|
||||
// Returns a*x, where x is an array of decimal digits and a is an ordinary
|
||||
// JavaScript number. base is the number base of the array x.
|
||||
multiplyByNumber(num, x, base) {
|
||||
if (num < 0) {
|
||||
return null;
|
||||
}
|
||||
if (num == 0) {
|
||||
return [];
|
||||
}
|
||||
let result = [], power = x;
|
||||
for(;;) {
|
||||
if (num & 1) {
|
||||
result = this.add(result, power, base);
|
||||
}
|
||||
num = num >> 1;
|
||||
if (num === 0) {
|
||||
return result;
|
||||
}
|
||||
power = this.add(power, power, base);
|
||||
}
|
||||
},
|
||||
twosComplement(str, base) {
|
||||
const invdigits = str.split('').map(c => base - 1 - parseInt(c,base)).reverse();
|
||||
const negdigits = this.add(invdigits, [1], base).slice(0,str.length);
|
||||
return negdigits.reverse().map(d => d.toString(base)).join('');
|
||||
},
|
||||
convertBase(str, fromBase, toBase) {
|
||||
if (fromBase === 10 && /[eE]/.test(str)) {
|
||||
// convert exponents to a string of zeros
|
||||
const s = str.split(/[eE]/);
|
||||
str = s[0] + '0'.repeat(parseInt(s[1],10)); // works for 0/+ve exponent,-ve throws
|
||||
}
|
||||
const digits = str.split('').map(d => parseInt(d,fromBase)).reverse();
|
||||
let outArray = [], power = [1];
|
||||
for (let i = 0; i < digits.length; i++) {
|
||||
if (digits[i]) {
|
||||
outArray = this.add(outArray, this.multiplyByNumber(digits[i], power, toBase), toBase);
|
||||
}
|
||||
power = this.multiplyByNumber(fromBase, power, toBase);
|
||||
}
|
||||
return outArray.reverse().map(d => d.toString(toBase)).join('');
|
||||
},
|
||||
decToHex(decstr, minlen) {
|
||||
let res;
|
||||
const isneg = decstr[0] === '-';
|
||||
if (isneg) {
|
||||
decstr = decstr.slice(1);
|
||||
}
|
||||
decstr = decstr.match(/^0*(.+)$/)[1]; // strip leading zeros
|
||||
if (decstr.length < 16 && !/[eE]/.test(decstr)) { // 16 = Math.pow(2,52).toString(10).length
|
||||
// less than 52 bits - just use parseInt
|
||||
res = parseInt(decstr, 10).toString(16);
|
||||
} else {
|
||||
res = NumberBaseConverter.convertBase(decstr, 10, 16);
|
||||
}
|
||||
if (isneg) {
|
||||
res = NumberBaseConverter.twosComplement(res, 16);
|
||||
if (/^[0-7]/.test(res)) res = 'f'+res; //msb must be set for -ve numbers
|
||||
} else if (/^[^0-7]/.test(res)) {
|
||||
res = '0' + res; // msb must not be set for +ve numbers
|
||||
}
|
||||
if (minlen && res.length < minlen) {
|
||||
res = (isneg?'f':'0').repeat(minlen - res.length) + res;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
hexToDec(hexstr, signed) {
|
||||
const isneg = /^[^0-7]/.test(hexstr);
|
||||
if (hexstr.match(/^0*(.+)$/)[1].length*4 < 52) {
|
||||
// less than 52 bits - just use parseInt
|
||||
let res = parseInt(hexstr, 16);
|
||||
if (signed && isneg) {
|
||||
res = -res;
|
||||
}
|
||||
return res.toString(10);
|
||||
}
|
||||
if (isneg) {
|
||||
hexstr = NumberBaseConverter.twosComplement(hexstr, 16);
|
||||
}
|
||||
const res = (isneg ? '-' : '') + NumberBaseConverter.convertBase(hexstr, 16, 10);
|
||||
return res;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
NumberBaseConverter,
|
||||
}
|
||||
51
src/utils/print.js
Normal file
51
src/utils/print.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Set of callbacks to be called when any message is output to the console
|
||||
* @type {Set<Function>}
|
||||
* */
|
||||
const messagePrintCallbacks = new Set();
|
||||
|
||||
function callMessagePrintCallbacks(args) {
|
||||
messagePrintCallbacks.forEach(cb => cb(...args));
|
||||
}
|
||||
|
||||
/**
|
||||
* print a debug message to the console
|
||||
* @param {...any} args
|
||||
*/
|
||||
function D(...args) {
|
||||
console.log(...args);
|
||||
callMessagePrintCallbacks(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* print an error message to the console
|
||||
* @param {...any} args
|
||||
*/
|
||||
function E(...args) {
|
||||
console.error(...args);
|
||||
callMessagePrintCallbacks(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* print a warning message to the console
|
||||
* @param {...any} args
|
||||
*/
|
||||
function W(...args) {
|
||||
console.warn(...args);
|
||||
callMessagePrintCallbacks(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback to be called when any message is output
|
||||
* @param {Function} cb
|
||||
*/
|
||||
function onMessagePrint(cb) {
|
||||
messagePrintCallbacks.add(cb);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
D,
|
||||
E,
|
||||
W,
|
||||
onMessagePrint,
|
||||
}
|
||||
21
src/utils/source-file.js
Normal file
21
src/utils/source-file.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Returns true if the string has an extension we recognise as a source file
|
||||
* @param {string} s
|
||||
*/
|
||||
function hasValidSourceFileExtension(s) {
|
||||
return /\.(java|kt)$/i.test(s);
|
||||
}
|
||||
|
||||
function splitSourcePath(filepath) {
|
||||
const m = filepath.match(/^\/([^/]+(?:\/[^/]+)*)?\/([^./]+)\.(java|kt)$/);
|
||||
return {
|
||||
pkg: m[1].replace(/\/+/g, '.'),
|
||||
type: m[2],
|
||||
qtype: `${m[1]}/${m[2]}`,
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hasValidSourceFileExtension,
|
||||
splitSourcePath,
|
||||
}
|
||||
11
src/utils/thread.js
Normal file
11
src/utils/thread.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Returns a Promise which resolves after the specified period.
|
||||
* @param {number} ms wait time in milliseconds
|
||||
*/
|
||||
function sleep(ms) {
|
||||
return new Promise(r => setTimeout(r, ms));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sleep,
|
||||
}
|
||||
Reference in New Issue
Block a user