mirror of
https://github.com/rizinorg/jsdec.git
synced 2026-11-08 08:08:12 -10:00
188 lines
5.7 KiB
JavaScript
188 lines
5.7 KiB
JavaScript
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
import JSONex from './JSONex.js';
|
|
import Long from './long.js';
|
|
import Anno from './annotation.js';
|
|
import ColorsAnsi from './colors/ansi.js';
|
|
import ColorsInvalid from './colors/invalid.js';
|
|
|
|
function initializeColors() {
|
|
const config = {};
|
|
if (rizin) {
|
|
const raw = rizin.command("ecj");
|
|
const colors = JSON.parse(raw || "{}");
|
|
if (colors && typeof colors === 'object' && !Array.isArray(colors)) {
|
|
Object.keys(colors).forEach(function(key) {
|
|
config[key] = colors[key];
|
|
});
|
|
}
|
|
}
|
|
return {
|
|
"callname": config['call'] || 'gray',
|
|
"integers": config['num'] || 'cyan',
|
|
"comment": config['comment'] || 'red',
|
|
"labels": config['flag'] || 'green',
|
|
"types": config['func_var_type'] || 'green',
|
|
"macro": config['cjmp'] || 'yellow',
|
|
"flow": config['flow'] || 'magenta',
|
|
"text": config['usrcmt'] || 'yellow',
|
|
};
|
|
}
|
|
//const _autoregex = /(\bif\b|\belse\b|\bwhile\b|\bfor\b|\bdo\b|\breturn\b|[ui]+nt[123468]+\_t|\bvoid\b|\bconst\b|\bsizeof\b|\bfloat\b|\bdouble\b|0x[0-9A-Fa-f]+|\b\d+\b)/g
|
|
|
|
/**
|
|
* Contains the regex used to colorize a given string.
|
|
* @type {Object}
|
|
*/
|
|
const _autotheme = {
|
|
controlflow: /\bif\b|\belse\b|\bwhile\b|\bfor\b|\bdo\b|\breturn\b|\bthrow\b/g,
|
|
definebits: /[ui]+nt[123468]+_t|\bvoid\b|\bconst\b|\bsizeof\b|\bfloat\b|\bdouble\b|\bchar\b|\bwchar_t\b|\bextern\b|\bstruct\b|\bsize_t\b|\btime_t\b|\bboolean\b/g,
|
|
numbers: /0x[0-9a-fA-F]+|\b(?![;[])\d+(?![;m])\b/g,
|
|
string: /("[^"]+")/,
|
|
};
|
|
|
|
const defaulttheme = initializeColors();
|
|
|
|
/**
|
|
* Color types (ansi, nocolor)
|
|
* @type {Object}
|
|
*/
|
|
const Colors = {
|
|
ansi: ColorsAnsi,
|
|
text: ColorsInvalid,
|
|
};
|
|
|
|
var _theme_colors = Colors.text.make(defaulttheme);
|
|
|
|
/**
|
|
* Applies colors to the string given a certain regex
|
|
* @param {String} input - Input string
|
|
* @param {String} type - Color name (ansi, text)
|
|
* @param {String} regex - Regex to apply
|
|
* @return {String} - Result string
|
|
*/
|
|
var _apply_regex = function(input, type, regex) {
|
|
var x = input.split(regex);
|
|
var p = input.match(regex);
|
|
var s = '';
|
|
if (!p) {
|
|
return s;
|
|
}
|
|
var i = 0;
|
|
for (i = 0; i < p.length; i++) {
|
|
if (p[i].length > 0) {
|
|
s += x[i] + _theme_colors[type](p[i]);
|
|
} else {
|
|
s += x[i] + p[i];
|
|
}
|
|
}
|
|
for (; i < x.length; i++) {
|
|
s += x[i];
|
|
}
|
|
return s;
|
|
};
|
|
|
|
/**
|
|
* Colorize the input string via ansi converters
|
|
* @param {String} input - Input string
|
|
* @return {String} - Result string
|
|
*/
|
|
var _colorize_text = function(input) {
|
|
if (!input || input.length < 1) {
|
|
return '';
|
|
}
|
|
if (!Global().evars.honor.color) {
|
|
return input;
|
|
}
|
|
/* control flow (if, else, while, do, etc..) */
|
|
var x = input.split(_autotheme.controlflow);
|
|
if (x.length > 1) {
|
|
input = _apply_regex(input, 'flow', _autotheme.controlflow);
|
|
}
|
|
/* numbers */
|
|
x = input.split(_autotheme.numbers);
|
|
if (x.length == 1 && x == '') {
|
|
input = this.theme.integers(input);
|
|
} else if (x.length > 1) {
|
|
input = _apply_regex(input, 'integers', _autotheme.numbers);
|
|
}
|
|
/* uint32_t, etc.. */
|
|
x = input.split(_autotheme.definebits);
|
|
if (x.length == 1 && x == '') {
|
|
input = this.theme.types(input);
|
|
} else if (input.split(_autotheme.definebits).length > 1) {
|
|
input = _apply_regex(input, 'types', _autotheme.definebits);
|
|
}
|
|
return input;
|
|
};
|
|
|
|
/**
|
|
* Applies all the colors options (theme/colors).
|
|
*/
|
|
var _get_theme = function(evars) {
|
|
if (evars.honor && evars.honor.color) {
|
|
return Colors.ansi.make(defaulttheme);
|
|
}
|
|
return Colors.text.make(defaulttheme);
|
|
};
|
|
|
|
/**
|
|
* Prints the final jsdec output
|
|
* @param useJSON - boolean whether to print as json
|
|
*/
|
|
var _flush_output = function(lines, errors, log) {
|
|
if (Global().evars.extra.annotation && lines) {
|
|
var actx = Anno.context();
|
|
var res = {
|
|
code: "",
|
|
annotations: []
|
|
};
|
|
lines.forEach(function(x) {
|
|
var parsed = Anno.parse(res.code.length, x, actx);
|
|
res.annotations = res.annotations.concat(parsed);
|
|
res.code += x.str + '\n';
|
|
});
|
|
console.log(JSONex.stringify(res));
|
|
} else if (Global().evars.extra.json) {
|
|
var jdata = {};
|
|
if (lines && lines.length > 0) {
|
|
jdata.lines = lines;
|
|
}
|
|
if (errors && errors.length > 0) {
|
|
jdata.errors = errors;
|
|
}
|
|
if (log && log.length > 0) {
|
|
jdata.log = log;
|
|
}
|
|
console.log(JSONex.stringify(jdata));
|
|
} else {
|
|
var prefix = Global().evars.extra.allfunctions ? "// " : "";
|
|
if (lines && lines.length > 0) {
|
|
for (var i = 0; i < lines.length; i++) {
|
|
if (Global().evars.extra.highlights && Global().evars.extra.offset.eq(lines[i].offset || Long.ZERO)) {
|
|
console.log('\u001b[7m' + lines[i].str + '\u001b[49m\u001b[0m');
|
|
} else {
|
|
console.log(lines[i].str);
|
|
}
|
|
}
|
|
}
|
|
if (errors && errors.length > 0) {
|
|
console.log(prefix + errors.join("\n").replace(/\n/g, '\n' + prefix));
|
|
}
|
|
if (log && log.length > 0) {
|
|
console.log(prefix + log.join("\n").replace(/\n/g, '\n' + prefix));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Printer Object
|
|
* @return {Function} - Printer object (to be called via `new Printer()`)
|
|
*/
|
|
export default function() {
|
|
this.theme = _get_theme(Global().evars);
|
|
this.auto = _colorize_text;
|
|
this.flushOutput = _flush_output;
|
|
}
|