Something went wrong. Try again.
Monorepo for the nibling.run platform
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475// node:string_decoder. write() returns only whole characters and holds a split// multibyte sequence (utf8, utf16le) or a partial base64 group until the next call;// end() flushes what is held the way Node does.import { Buffer } from "./buffer";
const CANONICAL: Record<string, string> = { utf8: "utf8", "utf-8": "utf8", ucs2: "utf16le", "ucs-2": "utf16le", utf16le: "utf16le", "utf-16le": "utf16le", latin1: "latin1", binary: "latin1", base64: "base64", base64url: "base64url", hex: "hex", ascii: "ascii",};
function toBuffer(buf: ArrayBufferView): Buffer { return buf instanceof Buffer ? buf : Buffer.from(new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));}
export class StringDecoder { readonly encoding: string; #utf8: TextDecoder | null = null; #held: Buffer = Buffer.alloc(0);
constructor(encoding?: string) { const enc = CANONICAL[String(encoding ?? "utf8").toLowerCase()]; if (!enc) throw Object.assign(new TypeError(`Unknown encoding: ${encoding}`), { code: "ERR_UNKNOWN_ENCODING" }); this.encoding = enc; if (enc === "utf8") this.#utf8 = new TextDecoder("utf-8"); }
write(buf: string | ArrayBufferView): string { if (typeof buf === "string") return buf; if (!ArrayBuffer.isView(buf)) { throw Object.assign(new TypeError('The "buf" argument must be an instance of Buffer, TypedArray, or DataView.'), { code: "ERR_INVALID_ARG_TYPE", }); } const bytes = toBuffer(buf); if (this.#utf8) return this.#utf8.decode(bytes, { stream: true }); switch (this.encoding) { case "utf16le": return this.#utf16(bytes); case "base64": case "base64url": return this.#base64(bytes); default: return bytes.toString(this.encoding); } }
end(buf?: string | ArrayBufferView): string { const head = buf === undefined ? "" : this.write(buf); if (this.#utf8) return head + this.#utf8.decode(); const held = this.#held; this.#held = Buffer.alloc(0); if (held.length === 0) return head; // A held odd byte is dropped; a held high surrogate is emitted alone (as Node). return head + held.toString(this.encoding, 0, this.encoding === "utf16le" ? held.length - (held.length % 2) : held.length); }
#utf16(bytes: Buffer): string { const all = Buffer.concat([this.#held, bytes]); let usable = all.length - (all.length % 2); if (usable >= 2) { const last = all[usable - 2]! | (all[usable - 1]! << 8); if (last >= 0xd800 && last <= 0xdbff) usable -= 2; } this.#held = Buffer.from(all.subarray(usable)); return all.toString("utf16le", 0, usable); }
#base64(bytes: Buffer): string { const all = Buffer.concat([this.#held, bytes]); const usable = all.length - (all.length % 3); this.#held = Buffer.from(all.subarray(usable)); return all.toString(this.encoding, 0, usable); }}