UNPKG

@nberlette/utf8

Version:

Blazing fast universal ponyfills for TextEncoder and TextDecoder.

238 lines 11 kB
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 _TextDecoder_encoding, _TextDecoder_fatal, _TextDecoder_ignoreBOM, _TextDecoder_buffer; /** * This module provides a high performance dependency-free ponyfill for the * `TextDecoder` Web API, allowing you to decode UTF-8 encoded `BufferSource` * buffers into strings in any ES2015+ environment. * * Currently only UTF-8 encoding is supported, but additional encodings will be * added in the near future. Encodings that are currently being implemented are * UTF-16, ISO-8859-1, Windows-1252, and ASCII. * * @module text-decoder */ import { normalizeEncoding, StringFromCharCode, toUint8Array, TypeError, Uint8Array, Uint8ArrayPrototypeSubarray, undefined, } from "./_internal.js"; /** * Decodes an encoded sequence of bytes into a string, using the specified * encoding standard. Currently, only UTF-8 encoding is supported. * * @see https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder * @category Encoding * @tags utf-8, decoder */ export class TextDecoder { /** * Creates a new TextDecoder instance. * @param label The encoding to use. Currently, only "utf-8" is supported. * @param options Configuration options. */ constructor(label = "utf-8", options = {}) { _TextDecoder_encoding.set(this, void 0); _TextDecoder_fatal.set(this, void 0); _TextDecoder_ignoreBOM.set(this, void 0); _TextDecoder_buffer.set(this, new Uint8Array(0)); __classPrivateFieldSet(this, _TextDecoder_encoding, normalizeEncoding(label), "f"); __classPrivateFieldSet(this, _TextDecoder_fatal, !!options.fatal, "f"); __classPrivateFieldSet(this, _TextDecoder_ignoreBOM, !!options.ignoreBOM, "f"); if (__classPrivateFieldGet(this, _TextDecoder_encoding, "f") !== "utf-8") { throw new TypeError(`The encoding "${label}" is not supported.`); } } /** The encoding standard to use. */ get encoding() { return __classPrivateFieldGet(this, _TextDecoder_encoding, "f"); } /** If true, invalid bytes will throw a TypeError. */ get fatal() { return __classPrivateFieldGet(this, _TextDecoder_fatal, "f"); } /** If true, the BOM (Byte Order Mark) will be ignored. */ get ignoreBOM() { return __classPrivateFieldGet(this, _TextDecoder_ignoreBOM, "f"); } /** * Decodes a BufferSource into a string using UTF-8 decoding. * * @param input The bytes to decode. Defaults to an empty Uint8Array. * @param [options] Decoding options. * @returns The decoded string. * @throws if the input is not a BufferSource. * @throws if fatal is true and an invalid byte sequence is encountered. */ decode(input, options) { const stream = options?.stream ?? false; let bytes = toUint8Array(input); // Concatenate any leftover bytes from the previous decode call if (__classPrivateFieldGet(this, _TextDecoder_buffer, "f").length > 0) { const combined = new Uint8Array(__classPrivateFieldGet(this, _TextDecoder_buffer, "f").length + bytes.length); combined.set(__classPrivateFieldGet(this, _TextDecoder_buffer, "f"), 0); combined.set(bytes, __classPrivateFieldGet(this, _TextDecoder_buffer, "f").length); bytes = combined; __classPrivateFieldSet(this, _TextDecoder_buffer, new Uint8Array(), "f"); } let string = "", i = 0; // Handle BOM if (!this.ignoreBOM && bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) i += 3; while (i < bytes.length) { const startIndex = i; const byte1 = bytes[i++]; if (byte1 <= 0x7f) { string += StringFromCharCode(byte1); } else if (byte1 >= 0xc0 && byte1 <= 0xdf) { // 2-byte sequence const byte2 = bytes[i++]; if (byte2 === undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, Uint8ArrayPrototypeSubarray(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } if ((byte2 & 0xc0) !== 0x80) { if (this.fatal) throw new TypeError("Invalid continuation byte"); string += "\uFFFD"; i = startIndex + 1; continue; } const codePoint = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f); string += StringFromCharCode(codePoint); } else if (byte1 >= 0xe0 && byte1 <= 0xef) { // 3-byte sequence const byte2 = bytes[i++]; if (byte2 === undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, Uint8ArrayPrototypeSubarray(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } const byte3 = bytes[i++]; if (byte3 === undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, Uint8ArrayPrototypeSubarray(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } if ((byte2 & 0xc0) !== 0x80 || (byte3 & 0xc0) !== 0x80) { if (this.fatal) throw new TypeError("Invalid continuation bytes"); string += "\uFFFD"; i = startIndex + 1; continue; } const codePoint = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6) | (byte3 & 0x3f); string += StringFromCharCode(codePoint); } else if (byte1 >= 0xf0 && byte1 <= 0xf7) { // 4-byte sequence const byte2 = bytes[i++]; if (byte2 === undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, Uint8ArrayPrototypeSubarray(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } const byte3 = bytes[i++]; if (byte3 === undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, Uint8ArrayPrototypeSubarray(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } const byte4 = bytes[i++]; if (byte4 === undefined) { // Incomplete sequence if (stream) { __classPrivateFieldSet(this, _TextDecoder_buffer, Uint8ArrayPrototypeSubarray(bytes, startIndex), "f"); break; } else { if (this.fatal) throw new TypeError("Incomplete byte sequence"); string += "\uFFFD"; break; } } if ((byte2 & 0xc0) !== 0x80 || (byte3 & 0xc0) !== 0x80 || (byte4 & 0xc0) !== 0x80) { if (this.fatal) throw new TypeError("Invalid continuation bytes"); string += "\uFFFD"; i = startIndex + 1; continue; } let codePoint = ((byte1 & 0x07) << 18) | ((byte2 & 0x3f) << 12) | ((byte3 & 0x3f) << 6) | (byte4 & 0x3f); codePoint -= 0x10000; string += StringFromCharCode(0xd800 + ((codePoint >> 10) & 0x3ff), 0xdc00 + (codePoint & 0x3ff)); } else { if (this.fatal) throw new TypeError("Invalid byte"); string += "\uFFFD"; } } // If not streaming, reset the buffer if (!stream) __classPrivateFieldSet(this, _TextDecoder_buffer, new Uint8Array(), "f"); return string; } } _TextDecoder_encoding = new WeakMap(), _TextDecoder_fatal = new WeakMap(), _TextDecoder_ignoreBOM = new WeakMap(), _TextDecoder_buffer = new WeakMap(); //# sourceMappingURL=text_decoder.js.map