UNPKG

cesr

Version:

[![NPM Version](https://img.shields.io/npm/v/cesr.svg?style=flat)](https://www.npmjs.com/package/cesr) [![NPM License](https://img.shields.io/npm/l/cesr.svg?style=flat)](https://github.com/lenkan/cesr-js/blob/main/LICENSE) [![CI](https://github.com/lenkan

97 lines (96 loc) 3.51 kB
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"; /** * Resolves the quadlet/triplet count of a frame */ export function resolveQuadletCount(frame) { if (typeof frame.size.fs !== "undefined" && frame.size.fs > 0) { return frame.size.fs / 4; } const raw = frame.raw ?? new Uint8Array(0); const ls = frame.size.ls ?? 0; const ss = frame.size.ss ?? 0; const ps = (3 - ((raw.byteLength + ls) % 3)) % 3; const fs = raw.byteLength + ps + ls; const cs = frame.size.hs + ss; return cs / 4 + fs / 3; } export function encodeText(frame) { if (frame.code.length !== frame.size.hs) { throw new Error(`Frame code ${frame.code} length ${frame.code.length} does not match expected size ${frame.size.hs}`); } const ls = frame.size.ls ?? 0; const raw = frame.raw ?? new Uint8Array(0); const padSize = (3 - ((raw.byteLength + ls) % 3)) % 3; const padded = prepad(raw, padSize + ls); const soft = frame.size.ss ? encodeBase64Int(frame.soft ?? padded.byteLength / 3, frame.size.ss) : ""; const result = `${frame.code}${soft}${encodeBase64Url(padded).slice(padSize)}`; if (frame.size.fs !== undefined && frame.size.fs > 0 && result.length < frame.size.fs) { throw new Error(`Encoded size ${result.length} does not match expected size ${frame.size.fs}`); } return result; } export function encodeBinary(frame) { const raw = frame.raw ?? new Uint8Array(0); // TODO: xs const ss = frame.size.ss ?? 0; const cs = frame.size.hs + ss; const ls = frame.size.ls ?? 0; const n = Math.ceil((cs * 3) / 4); const soft = ss ? encodeBase64Int(frame.soft ?? (ls + raw.length) / 3, ss) : ""; const padding = 2 * (cs % 4); const bcode = toArray(lshift(decodeBase64Int(frame.code + soft), padding), n); const result = new Uint8Array(bcode.length + ls + raw.length); result.set(bcode, 0); result.set(raw, bcode.length + ls); return result; } export function peekText(input, entry) { if (typeof input === "string") { input = encodeUtf8(input); } if (input.length < 4) { return { n: 0 }; } const ss = entry.ss ?? 0; const cs = entry.hs + ss; if (input.length < cs) { return { n: 0 }; } const ls = entry.ls ?? 0; const ps = (entry.hs + ss) % 4; const hard = decodeUtf8(input.slice(0, entry.hs)); const soft0 = decodeBase64Int(decodeUtf8(input.slice(entry.hs, entry.hs + ss))); const fs = entry.fs !== undefined && entry.fs > 0 ? entry.fs : cs + soft0 * 4; if (input.length < fs - ls) { return { n: 0 }; } const padding = "A".repeat(ps); const text = decodeUtf8(input.slice(0, fs)); const rawtext = padding + text.slice(cs); const raw = decodeBase64Url(rawtext).slice(ps + ls); return { frame: { code: hard, soft: soft0, raw, size: { hs: entry.hs, fs, ss, ls, xs: entry.xs ?? 0, }, }, n: fs, }; } export function decodeText(input, entry) { const result = peekText(input, entry); if (!result.frame) { throw new Error("Could not parse frame from input"); } return result.frame; }