cesr
Version:
[](https://www.npmjs.com/package/cesr) [](https://github.com/lenkan/cesr-js/blob/main/LICENSE)
154 lines (153 loc) • 7.36 kB
JavaScript
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _CodeTable_instances, _CodeTable_table, _CodeTable_hards, _CodeTable_strict, _CodeTable_encodeBinary, _CodeTable_encodeText;
import { prepad, toArray } from "./array-utils.js";
import { decodeBase64Int, decodeBase64Url, encodeBase64Int, encodeBase64Url } from "./encoding-base64.js";
import { decodeUtf8, encodeUtf8 } from "./encoding-utf8.js";
import { lshift } from "./shifting.js";
function resolveSize(init) {
return {
hs: init.hs,
fs: init.fs ?? 0,
ls: init.ls ?? 0,
os: init.os ?? 0,
ss: init.ss ?? 0,
xs: init.xs ?? 0,
};
}
export class CodeTable {
constructor(table, options = {}) {
_CodeTable_instances.add(this);
_CodeTable_table.set(this, {});
_CodeTable_hards.set(this, {});
_CodeTable_strict.set(this, void 0);
__classPrivateFieldSet(this, _CodeTable_strict, options.strict ?? false, "f");
for (const [key, value] of Object.entries(table)) {
__classPrivateFieldGet(this, _CodeTable_hards, "f")[key.slice(0, 1)] = value.hs;
__classPrivateFieldGet(this, _CodeTable_table, "f")[key] = resolveSize(value);
}
}
/**
* Finds the size table of a code
* @param input The input to parse the code from
*/
lookup(input) {
if (typeof input !== "string") {
input = decodeUtf8(input.slice(0, 4));
}
const hs = __classPrivateFieldGet(this, _CodeTable_hards, "f")[input.slice(0, 1)];
const hard = input.slice(0, hs ?? 4);
const size = __classPrivateFieldGet(this, _CodeTable_table, "f")[hard];
if (size) {
return size;
}
if (!__classPrivateFieldGet(this, _CodeTable_strict, "f")) {
switch (hard.charAt(0)) {
case "-":
switch (hard.charAt(1)) {
case "-":
return resolveSize({ hs: 3, ss: 5, fs: 8 });
case "_":
return resolveSize({ hs: 5, ss: 3, fs: 8 });
default:
return resolveSize({ hs: 2, ss: 2, fs: 4 });
}
}
}
throw new Error(`Unknown code ${hard}`);
}
encode(frame, domain = "text") {
if (domain === "text") {
return __classPrivateFieldGet(this, _CodeTable_instances, "m", _CodeTable_encodeText).call(this, frame);
}
return __classPrivateFieldGet(this, _CodeTable_instances, "m", _CodeTable_encodeBinary).call(this, frame);
}
decode(input) {
if (typeof input === "string") {
input = encodeUtf8(input);
}
const result = this.read(input);
if (result.frame === null) {
throw new Error("Not enough data in input");
}
return result.frame;
}
/**
* Tries to read a frame from the input. Returns an object with the frame and the number of bytes read.
* @param input The input. May be longer than one frame, in which case only the first frame is returned.
*/
read(input) {
if (input.length < 4) {
return { frame: null, n: 0 };
}
const size = this.lookup(input);
if (!size) {
throw new Error(`Unknown code ${input}`);
}
const ss = size.ss ?? 0;
const cs = size.hs + ss;
if (input.length < cs) {
return { frame: null, n: 0 };
}
const ls = size.ls ?? 0;
const ps = (size.hs + ss) % 4;
const ms = ss - (size.os ?? 0);
const os = size.os ?? 0;
const hard = decodeUtf8(input.slice(0, size.hs));
const soft0 = decodeBase64Int(decodeUtf8(input.slice(size.hs, cs)));
const soft1 = decodeBase64Int(decodeUtf8(input.slice(size.hs + ms, size.hs + ms + os)));
const fs = size.fs !== undefined && size.fs > 0 ? size.fs : cs + soft0 * 4;
if (input.length < fs) {
return { frame: null, n: 0 };
}
const padding = "A".repeat(ps);
const text = decodeUtf8(input.slice(0, fs));
const rawtext = padding + text.slice(cs, fs);
const raw = decodeBase64Url(rawtext).slice(ps + ls);
return { frame: { code: hard, count: soft0, index: soft0, ondex: soft1, raw, text }, n: fs };
}
}
_CodeTable_table = new WeakMap(), _CodeTable_hards = new WeakMap(), _CodeTable_strict = new WeakMap(), _CodeTable_instances = new WeakSet(), _CodeTable_encodeBinary = function _CodeTable_encodeBinary(frame) {
const raw = frame.raw ?? new Uint8Array(0);
// TODO: xs
const size = this.lookup(frame.code);
const cs = size.hs + size.ss;
const ms = size.ss - size.os;
const os = size.os;
const n = Math.ceil((cs * 3) / 4);
const soft = ms ? encodeBase64Int(frame.count ?? frame.index ?? (size.ls + raw.length) / 3, ms) : "";
const other = os ? encodeBase64Int(frame.ondex ?? 0, os ?? 0) : "";
const padding = 2 * (cs % 4);
const bcode = toArray(lshift(decodeBase64Int(frame.code + soft + other), padding), n);
const result = new Uint8Array(bcode.length + size.ls + raw.length);
result.set(bcode, 0);
result.set(raw, bcode.length + size.ls);
return result;
}, _CodeTable_encodeText = function _CodeTable_encodeText(frame) {
const size = this.lookup(frame.code);
if (frame.code.length !== size.hs) {
throw new Error(`Frame code ${frame.code} length ${frame.code.length} does not match expected size ${size.hs}`);
}
const ls = size.ls ?? 0;
const ms = (size.ss ?? 0) - (size.os ?? 0);
const os = size.os ?? 0;
const raw = frame.raw ?? new Uint8Array(0);
const padSize = (3 - ((raw.byteLength + ls) % 3)) % 3;
const padded = prepad(raw, padSize + ls);
const soft = ms ? encodeBase64Int(frame.count ?? frame.index ?? padded.byteLength / 3, ms) : "";
const other = os ? encodeBase64Int(frame.ondex ?? 0, os ?? 0) : "";
const result = `${frame.code}${soft}${other}${encodeBase64Url(padded).slice(padSize)}`;
if (size.fs !== undefined && size.fs > 0 && result.length < size.fs) {
throw new Error(`Encoded size ${result.length} does not match expected size ${size.fs}`);
}
return encodeUtf8(result);
};