deno.land / x / deno@v1.28.2 / ext / web / 08_text_encoding.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// @ts-check/// <reference path="../../core/lib.deno_core.d.ts" />/// <reference path="../../core/internal.d.ts" />/// <reference path="../webidl/internal.d.ts" />/// <reference path="../fetch/lib.deno_fetch.d.ts" />/// <reference path="../web/internal.d.ts" />/// <reference path="../web/lib.deno_web.d.ts" />/// <reference lib="esnext" />
"use strict";
((window) => { const core = Deno.core; const ops = core.ops; const webidl = window.__bootstrap.webidl; const { PromiseReject, PromiseResolve, StringPrototypeCharCodeAt, StringPrototypeSlice, TypedArrayPrototypeSubarray, Uint8Array, ObjectPrototypeIsPrototypeOf, ArrayBufferIsView, Uint32Array, } = window.__bootstrap.primordials;
class TextDecoder { /** @type {string} */ #encoding; /** @type {boolean} */ #fatal; /** @type {boolean} */ #ignoreBOM; /** @type {boolean} */ #utf8SinglePass;
/** @type {number | null} */ #rid = null;
/** * @param {string} label * @param {TextDecoderOptions} options */ constructor(label = "utf-8", options = {}) { const prefix = "Failed to construct 'TextDecoder'"; label = webidl.converters.DOMString(label, { prefix, context: "Argument 1", }); options = webidl.converters.TextDecoderOptions(options, { prefix, context: "Argument 2", }); const encoding = ops.op_encoding_normalize_label(label); this.#encoding = encoding; this.#fatal = options.fatal; this.#ignoreBOM = options.ignoreBOM; this.#utf8SinglePass = encoding === "utf-8" && !options.fatal; this[webidl.brand] = webidl.brand; }
/** @returns {string} */ get encoding() { webidl.assertBranded(this, TextDecoderPrototype); return this.#encoding; }
/** @returns {boolean} */ get fatal() { webidl.assertBranded(this, TextDecoderPrototype); return this.#fatal; }
/** @returns {boolean} */ get ignoreBOM() { webidl.assertBranded(this, TextDecoderPrototype); return this.#ignoreBOM; }
/** * @param {BufferSource} [input] * @param {TextDecodeOptions} options */ decode(input = new Uint8Array(), options = undefined) { webidl.assertBranded(this, TextDecoderPrototype); const prefix = "Failed to execute 'decode' on 'TextDecoder'"; if (input !== undefined) { input = webidl.converters.BufferSource(input, { prefix, context: "Argument 1", allowShared: true, }); } let stream = false; if (options !== undefined) { options = webidl.converters.TextDecodeOptions(options, { prefix, context: "Argument 2", }); stream = options.stream; }
try { // Note from spec: implementations are strongly encouraged to use an implementation strategy that avoids this copy. // When doing so they will have to make sure that changes to input do not affect future calls to decode(). if ( ObjectPrototypeIsPrototypeOf( SharedArrayBuffer.prototype, input || input.buffer, ) ) { // We clone the data into a non-shared ArrayBuffer so we can pass it // to Rust. // `input` is now a Uint8Array, and calling the TypedArray constructor // with a TypedArray argument copies the data. if (ArrayBufferIsView(input)) { input = new Uint8Array( input.buffer, input.byteOffset, input.byteLength, ); } else { input = new Uint8Array(input); } }
// Fast path for single pass encoding. if (!stream && this.#rid === null) { // Fast path for utf8 single pass encoding. if (this.#utf8SinglePass) { return ops.op_encoding_decode_utf8(input, this.#ignoreBOM); }
return ops.op_encoding_decode_single( input, this.#encoding, this.#fatal, this.#ignoreBOM, ); }
if (this.#rid === null) { this.#rid = ops.op_encoding_new_decoder( this.#encoding, this.#fatal, this.#ignoreBOM, ); } return ops.op_encoding_decode(input, this.#rid, stream); } finally { if (!stream && this.#rid !== null) { core.close(this.#rid); this.#rid = null; } } } }
webidl.configurePrototype(TextDecoder); const TextDecoderPrototype = TextDecoder.prototype;
class TextEncoder { constructor() { this[webidl.brand] = webidl.brand; }
/** @returns {string} */ get encoding() { webidl.assertBranded(this, TextEncoderPrototype); return "utf-8"; }
/** * @param {string} input * @returns {Uint8Array} */ encode(input = "") { webidl.assertBranded(this, TextEncoderPrototype); const prefix = "Failed to execute 'encode' on 'TextEncoder'"; // The WebIDL type of `input` is `USVString`, but `core.encode` already // converts lone surrogates to the replacement character. input = webidl.converters.DOMString(input, { prefix, context: "Argument 1", }); return core.encode(input); }
/** * @param {string} source * @param {Uint8Array} destination * @returns {TextEncoderEncodeIntoResult} */ encodeInto(source, destination) { webidl.assertBranded(this, TextEncoderPrototype); const prefix = "Failed to execute 'encodeInto' on 'TextEncoder'"; // The WebIDL type of `source` is `USVString`, but the ops bindings // already convert lone surrogates to the replacement character. source = webidl.converters.DOMString(source, { prefix, context: "Argument 1", }); destination = webidl.converters.Uint8Array(destination, { prefix, context: "Argument 2", allowShared: true, }); ops.op_encoding_encode_into(source, destination, encodeIntoBuf); return { read: encodeIntoBuf[0], written: encodeIntoBuf[1], }; } }
const encodeIntoBuf = new Uint32Array(2);
webidl.configurePrototype(TextEncoder); const TextEncoderPrototype = TextEncoder.prototype;
class TextDecoderStream { /** @type {TextDecoder} */ #decoder; /** @type {TransformStream<BufferSource, string>} */ #transform;
/** * @param {string} label * @param {TextDecoderOptions} options */ constructor(label = "utf-8", options = {}) { const prefix = "Failed to construct 'TextDecoderStream'"; label = webidl.converters.DOMString(label, { prefix, context: "Argument 1", }); options = webidl.converters.TextDecoderOptions(options, { prefix, context: "Argument 2", }); this.#decoder = new TextDecoder(label, options); this.#transform = new TransformStream({ // The transform and flush functions need access to TextDecoderStream's // `this`, so they are defined as functions rather than methods. transform: (chunk, controller) => { try { chunk = webidl.converters.BufferSource(chunk, { allowShared: true, }); const decoded = this.#decoder.decode(chunk, { stream: true }); if (decoded) { controller.enqueue(decoded); } return PromiseResolve(); } catch (err) { return PromiseReject(err); } }, flush: (controller) => { try { const final = this.#decoder.decode(); if (final) { controller.enqueue(final); } return PromiseResolve(); } catch (err) { return PromiseReject(err); } }, }); this[webidl.brand] = webidl.brand; }
/** @returns {string} */ get encoding() { webidl.assertBranded(this, TextDecoderStreamPrototype); return this.#decoder.encoding; }
/** @returns {boolean} */ get fatal() { webidl.assertBranded(this, TextDecoderStreamPrototype); return this.#decoder.fatal; }
/** @returns {boolean} */ get ignoreBOM() { webidl.assertBranded(this, TextDecoderStreamPrototype); return this.#decoder.ignoreBOM; }
/** @returns {ReadableStream<string>} */ get readable() { webidl.assertBranded(this, TextDecoderStreamPrototype); return this.#transform.readable; }
/** @returns {WritableStream<BufferSource>} */ get writable() { webidl.assertBranded(this, TextDecoderStreamPrototype); return this.#transform.writable; } }
webidl.configurePrototype(TextDecoderStream); const TextDecoderStreamPrototype = TextDecoderStream.prototype;
class TextEncoderStream { /** @type {string | null} */ #pendingHighSurrogate = null; /** @type {TransformStream<string, Uint8Array>} */ #transform;
constructor() { this.#transform = new TransformStream({ // The transform and flush functions need access to TextEncoderStream's // `this`, so they are defined as functions rather than methods. transform: (chunk, controller) => { try { chunk = webidl.converters.DOMString(chunk); if (chunk === "") { return PromiseResolve(); } if (this.#pendingHighSurrogate !== null) { chunk = this.#pendingHighSurrogate + chunk; } const lastCodeUnit = StringPrototypeCharCodeAt( chunk, chunk.length - 1, ); if (0xD800 <= lastCodeUnit && lastCodeUnit <= 0xDBFF) { this.#pendingHighSurrogate = StringPrototypeSlice(chunk, -1); chunk = StringPrototypeSlice(chunk, 0, -1); } else { this.#pendingHighSurrogate = null; } if (chunk) { controller.enqueue(core.encode(chunk)); } return PromiseResolve(); } catch (err) { return PromiseReject(err); } }, flush: (controller) => { try { if (this.#pendingHighSurrogate !== null) { controller.enqueue(new Uint8Array([0xEF, 0xBF, 0xBD])); } return PromiseResolve(); } catch (err) { return PromiseReject(err); } }, }); this[webidl.brand] = webidl.brand; }
/** @returns {string} */ get encoding() { webidl.assertBranded(this, TextEncoderStreamPrototype); return "utf-8"; }
/** @returns {ReadableStream<Uint8Array>} */ get readable() { webidl.assertBranded(this, TextEncoderStreamPrototype); return this.#transform.readable; }
/** @returns {WritableStream<string>} */ get writable() { webidl.assertBranded(this, TextEncoderStreamPrototype); return this.#transform.writable; } }
webidl.configurePrototype(TextEncoderStream); const TextEncoderStreamPrototype = TextEncoderStream.prototype;
webidl.converters.TextDecoderOptions = webidl.createDictionaryConverter( "TextDecoderOptions", [ { key: "fatal", converter: webidl.converters.boolean, defaultValue: false, }, { key: "ignoreBOM", converter: webidl.converters.boolean, defaultValue: false, }, ], ); webidl.converters.TextDecodeOptions = webidl.createDictionaryConverter( "TextDecodeOptions", [ { key: "stream", converter: webidl.converters.boolean, defaultValue: false, }, ], );
/** * @param {Uint8Array} bytes */ function decode(bytes, encoding) { const BOMEncoding = BOMSniff(bytes); if (BOMEncoding !== null) { encoding = BOMEncoding; const start = BOMEncoding === "UTF-8" ? 3 : 2; bytes = TypedArrayPrototypeSubarray(bytes, start); } return new TextDecoder(encoding).decode(bytes); }
/** * @param {Uint8Array} bytes */ function BOMSniff(bytes) { if (bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF) { return "UTF-8"; } if (bytes[0] === 0xFE && bytes[1] === 0xFF) return "UTF-16BE"; if (bytes[0] === 0xFF && bytes[1] === 0xFE) return "UTF-16LE"; return null; }
window.__bootstrap.encoding = { TextEncoder, TextDecoder, TextEncoderStream, TextDecoderStream, decode, };})(this);
Version Info