Improved performance of str/array buffer conversions

This commit is contained in:
n1474335 2023-02-03 17:10:33 +00:00
parent 7a2517fd61
commit 659325c85a
8 changed files with 30 additions and 23 deletions

View File

@ -474,6 +474,7 @@ class Utils {
static strToArrayBuffer(str) {
log.debug(`Converting string[${str?.length}] to array buffer`);
if (!str) return new ArrayBuffer;
const arr = new Uint8Array(str.length);
let i = str.length, b;
while (i--) {
@ -502,9 +503,10 @@ class Utils {
static strToUtf8ArrayBuffer(str) {
log.debug(`Converting string[${str?.length}] to UTF8 array buffer`);
if (!str) return new ArrayBuffer;
const utf8Str = utf8.encode(str);
if (str.length !== utf8Str.length) {
const buffer = new TextEncoder("utf-8").encode(str);
if (str.length !== buffer.length) {
if (isWorkerEnvironment() && self && typeof self.setOption === "function") {
self.setOption("attemptHighlight", false);
} else if (isWebEnvironment()) {
@ -512,7 +514,7 @@ class Utils {
}
}
return Utils.strToArrayBuffer(utf8Str);
return buffer.buffer;
}
@ -627,20 +629,24 @@ class Utils {
static byteArrayToUtf8(byteArray) {
log.debug(`Converting byte array[${byteArray?.length}] to UTF8`);
if (!byteArray || !byteArray.length) return "";
const str = Utils.byteArrayToChars(byteArray);
if (!(byteArray instanceof Uint8Array))
byteArray = new Uint8Array(byteArray);
try {
const utf8Str = utf8.decode(str);
if (str.length !== utf8Str.length) {
const str = new TextDecoder("utf-8", {fatal: true}).decode(byteArray);
if (str.length !== byteArray.length) {
if (isWorkerEnvironment()) {
self.setOption("attemptHighlight", false);
} else if (isWebEnvironment()) {
window.app.options.attemptHighlight = false;
}
}
return utf8Str;
return str;
} catch (err) {
// If it fails, treat it as ANSI
return str;
return Utils.byteArrayToChars(byteArray);
}
}
@ -662,9 +668,10 @@ class Utils {
log.debug(`Converting byte array[${byteArray?.length}] to chars`);
if (!byteArray || !byteArray.length) return "";
let str = "";
// String concatenation appears to be faster than an array join
for (let i = 0; i < byteArray.length;) {
str += String.fromCharCode(byteArray[i++]);
// Maxiumum arg length for fromCharCode is 65535, but the stack may already be fairly deep,
// so don't get too near it.
for (let i = 0; i < byteArray.length; i += 20000) {
str += String.fromCharCode(...(byteArray.slice(i, i+20000)));
}
return str;
}

View File

@ -25,12 +25,12 @@ import OperationError from "../errors/OperationError.mjs";
*/
export function toBase64(data, alphabet="A-Za-z0-9+/=") {
if (!data) return "";
if (typeof data == "string") {
data = Utils.strToArrayBuffer(data);
}
if (data instanceof ArrayBuffer) {
data = new Uint8Array(data);
}
if (typeof data == "string") {
data = Utils.strToByteArray(data);
}
alphabet = Utils.expandAlphRange(alphabet).join("");
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding

View File

@ -84,7 +84,7 @@ class FromBCD extends Operation {
break;
case "Raw":
default:
byteArray = Utils.strToByteArray(input);
byteArray = new Uint8Array(Utils.strToArrayBuffer(input));
byteArray.forEach(b => {
nibbles.push(b >>> 4);
nibbles.push(b & 15);

View File

@ -26,7 +26,7 @@ class FromCharcode extends Operation {
this.description = "Converts unicode character codes back into text.<br><br>e.g. <code>0393 03b5 03b9 03ac 20 03c3 03bf 03c5</code> becomes <code>Γειά σου</code>";
this.infoURL = "https://wikipedia.org/wiki/Plane_(Unicode)";
this.inputType = "string";
this.outputType = "byteArray";
this.outputType = "ArrayBuffer";
this.args = [
{
"name": "Delimiter",
@ -44,7 +44,7 @@ class FromCharcode extends Operation {
/**
* @param {string} input
* @param {Object[]} args
* @returns {byteArray}
* @returns {ArrayBuffer}
*
* @throws {OperationError} if base out of range
*/
@ -77,7 +77,7 @@ class FromCharcode extends Operation {
for (i = 0; i < bites.length; i++) {
latin1 += Utils.chr(parseInt(bites[i], base));
}
return Utils.strToByteArray(latin1);
return Utils.strToArrayBuffer(latin1);
}
}

View File

@ -68,8 +68,8 @@ class HammingDistance extends Operation {
samples[0] = fromHex(samples[0]);
samples[1] = fromHex(samples[1]);
} else {
samples[0] = Utils.strToByteArray(samples[0]);
samples[1] = Utils.strToByteArray(samples[1]);
samples[0] = new Uint8Array(Utils.strToArrayBuffer(samples[0]));
samples[1] = new Uint8Array(Utils.strToArrayBuffer(samples[1]));
}
let dist = 0;

View File

@ -49,7 +49,7 @@ class ParseIPv4Header extends Operation {
if (format === "Hex") {
input = fromHex(input);
} else if (format === "Raw") {
input = Utils.strToByteArray(input);
input = new Uint8Array(Utils.strToArrayBuffer(input));
} else {
throw new OperationError("Unrecognised input format.");
}

View File

@ -71,7 +71,7 @@ class ParseX509Certificate extends Operation {
cert.readCertHex(toHex(fromBase64(input, null, "byteArray"), ""));
break;
case "Raw":
cert.readCertHex(toHex(Utils.strToByteArray(input), ""));
cert.readCertHex(toHex(Utils.strToArrayBuffer(input), ""));
break;
default:
undefinedInputFormat = true;

View File

@ -77,7 +77,7 @@ class PlayMedia extends Operation {
* Displays an audio or video element that may be able to play the media
* file.
*
* @param data {byteArray} Data containing an audio or video file.
* @param {byteArray} data Data containing an audio or video file.
* @returns {string} Markup to display a media player.
*/
async present(data) {