192 lines
4.9 KiB
TypeScript
192 lines
4.9 KiB
TypeScript
function getGlobal() {
|
|
if (typeof globalThis !== "undefined") return globalThis;
|
|
if (typeof self !== "undefined") return self;
|
|
if (typeof window !== "undefined") return window;
|
|
return global;
|
|
}
|
|
|
|
const globalObject = getGlobal();
|
|
const nodeBuffer = globalObject.Buffer ?? null;
|
|
const textEncoder = globalObject.TextEncoder
|
|
? new globalObject.TextEncoder()
|
|
: null;
|
|
|
|
export type ITypedArray = Uint8Array | Uint16Array | Uint32Array;
|
|
export type IDataType = string | Buffer | ITypedArray;
|
|
export type IEmbeddedWasm = { name: string; data: string; hash: string };
|
|
|
|
export function intArrayToString(arr: Uint8Array, len: number): string {
|
|
return String.fromCharCode(...arr.subarray(0, len));
|
|
}
|
|
|
|
function hexCharCodesToInt(a: number, b: number): number {
|
|
return (
|
|
(((a & 0xf) + ((a >> 6) | ((a >> 3) & 0x8))) << 4) |
|
|
((b & 0xf) + ((b >> 6) | ((b >> 3) & 0x8)))
|
|
);
|
|
}
|
|
|
|
export function writeHexToUInt8(buf: Uint8Array, str: string) {
|
|
const size = str.length >> 1;
|
|
for (let i = 0; i < size; i++) {
|
|
const index = i << 1;
|
|
buf[i] = hexCharCodesToInt(
|
|
str.charCodeAt(index),
|
|
str.charCodeAt(index + 1),
|
|
);
|
|
}
|
|
}
|
|
|
|
export function hexStringEqualsUInt8(str: string, buf: Uint8Array): boolean {
|
|
if (str.length !== buf.length * 2) {
|
|
return false;
|
|
}
|
|
for (let i = 0; i < buf.length; i++) {
|
|
const strIndex = i << 1;
|
|
if (
|
|
buf[i] !==
|
|
hexCharCodesToInt(str.charCodeAt(strIndex), str.charCodeAt(strIndex + 1))
|
|
) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const alpha = "a".charCodeAt(0) - 10;
|
|
const digit = "0".charCodeAt(0);
|
|
export function getDigestHex(
|
|
tmpBuffer: Uint8Array,
|
|
input: Uint8Array,
|
|
hashLength: number,
|
|
): string {
|
|
let p = 0;
|
|
for (let i = 0; i < hashLength; i++) {
|
|
let nibble = input[i] >>> 4;
|
|
tmpBuffer[p++] = nibble > 9 ? nibble + alpha : nibble + digit;
|
|
nibble = input[i] & 0xf;
|
|
tmpBuffer[p++] = nibble > 9 ? nibble + alpha : nibble + digit;
|
|
}
|
|
|
|
return String.fromCharCode.apply(null, tmpBuffer);
|
|
}
|
|
|
|
export const getUInt8Buffer =
|
|
nodeBuffer !== null
|
|
? (data: IDataType): Uint8Array => {
|
|
if (typeof data === "string") {
|
|
const buf = nodeBuffer.from(data, "utf8");
|
|
return new Uint8Array(buf.buffer, buf.byteOffset, buf.length);
|
|
}
|
|
|
|
if (nodeBuffer.isBuffer(data)) {
|
|
return new Uint8Array(data.buffer, data.byteOffset, data.length);
|
|
}
|
|
|
|
if (ArrayBuffer.isView(data)) {
|
|
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
}
|
|
|
|
throw new Error("Invalid data type!");
|
|
}
|
|
: (data: IDataType): Uint8Array => {
|
|
if (typeof data === "string") {
|
|
return textEncoder.encode(data);
|
|
}
|
|
|
|
if (ArrayBuffer.isView(data)) {
|
|
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
}
|
|
|
|
throw new Error("Invalid data type!");
|
|
};
|
|
|
|
const base64Chars =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
const base64Lookup = new Uint8Array(256);
|
|
for (let i = 0; i < base64Chars.length; i++) {
|
|
base64Lookup[base64Chars.charCodeAt(i)] = i;
|
|
}
|
|
|
|
export function encodeBase64(data: Uint8Array, pad = true): string {
|
|
const len = data.length;
|
|
const extraBytes = len % 3;
|
|
const parts = [];
|
|
|
|
const len2 = len - extraBytes;
|
|
for (let i = 0; i < len2; i += 3) {
|
|
const tmp =
|
|
((data[i] << 16) & 0xff0000) +
|
|
((data[i + 1] << 8) & 0xff00) +
|
|
(data[i + 2] & 0xff);
|
|
|
|
const triplet =
|
|
base64Chars.charAt((tmp >> 18) & 0x3f) +
|
|
base64Chars.charAt((tmp >> 12) & 0x3f) +
|
|
base64Chars.charAt((tmp >> 6) & 0x3f) +
|
|
base64Chars.charAt(tmp & 0x3f);
|
|
|
|
parts.push(triplet);
|
|
}
|
|
|
|
if (extraBytes === 1) {
|
|
const tmp = data[len - 1];
|
|
const a = base64Chars.charAt(tmp >> 2);
|
|
const b = base64Chars.charAt((tmp << 4) & 0x3f);
|
|
|
|
parts.push(`${a}${b}`);
|
|
if (pad) {
|
|
parts.push("==");
|
|
}
|
|
} else if (extraBytes === 2) {
|
|
const tmp = (data[len - 2] << 8) + data[len - 1];
|
|
const a = base64Chars.charAt(tmp >> 10);
|
|
const b = base64Chars.charAt((tmp >> 4) & 0x3f);
|
|
const c = base64Chars.charAt((tmp << 2) & 0x3f);
|
|
parts.push(`${a}${b}${c}`);
|
|
if (pad) {
|
|
parts.push("=");
|
|
}
|
|
}
|
|
|
|
return parts.join("");
|
|
}
|
|
|
|
export function getDecodeBase64Length(data: string): number {
|
|
let bufferLength = Math.floor(data.length * 0.75);
|
|
const len = data.length;
|
|
|
|
if (data[len - 1] === "=") {
|
|
bufferLength -= 1;
|
|
if (data[len - 2] === "=") {
|
|
bufferLength -= 1;
|
|
}
|
|
}
|
|
|
|
return bufferLength;
|
|
}
|
|
|
|
export function decodeBase64(data: string): Uint8Array {
|
|
const bufferLength = getDecodeBase64Length(data);
|
|
const len = data.length;
|
|
|
|
const bytes = new Uint8Array(bufferLength);
|
|
|
|
let p = 0;
|
|
for (let i = 0; i < len; i += 4) {
|
|
const encoded1 = base64Lookup[data.charCodeAt(i)];
|
|
const encoded2 = base64Lookup[data.charCodeAt(i + 1)];
|
|
const encoded3 = base64Lookup[data.charCodeAt(i + 2)];
|
|
const encoded4 = base64Lookup[data.charCodeAt(i + 3)];
|
|
|
|
bytes[p] = (encoded1 << 2) | (encoded2 >> 4);
|
|
p += 1;
|
|
bytes[p] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
|
|
p += 1;
|
|
bytes[p] = ((encoded3 & 3) << 6) | (encoded4 & 63);
|
|
p += 1;
|
|
}
|
|
|
|
return bytes;
|
|
}
|