2021-01-11 12:13:41 -05:00
|
|
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
2020-07-19 13:49:44 -04:00
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
// @ts-check
|
|
|
|
/// <reference path="../../core/lib.deno_core.d.ts" />
|
|
|
|
/// <reference path="../webidl/internal.d.ts" />
|
|
|
|
/// <reference path="../web/internal.d.ts" />
|
|
|
|
/// <reference path="../web/lib.deno_web.d.ts" />
|
|
|
|
/// <reference lib="esnext" />
|
|
|
|
|
2021-02-04 17:18:32 -05:00
|
|
|
"use strict";
|
2020-07-19 13:49:44 -04:00
|
|
|
|
|
|
|
((window) => {
|
|
|
|
const core = Deno.core;
|
2021-06-05 17:10:07 -04:00
|
|
|
const webidl = window.__bootstrap.webidl;
|
2020-07-19 13:49:44 -04:00
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
class TextDecoder {
|
|
|
|
/** @type {string} */
|
|
|
|
#encoding;
|
|
|
|
/** @type {boolean} */
|
|
|
|
#fatal;
|
|
|
|
/** @type {boolean} */
|
|
|
|
#ignoreBOM;
|
|
|
|
|
|
|
|
/** @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 = core.opSync("op_encoding_normalize_label", label);
|
|
|
|
this.#encoding = encoding;
|
|
|
|
this.#fatal = options.fatal;
|
|
|
|
this.#ignoreBOM = options.ignoreBOM;
|
|
|
|
this[webidl.brand] = webidl.brand;
|
2020-07-19 13:49:44 -04:00
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
/** @returns {string} */
|
|
|
|
get encoding() {
|
|
|
|
webidl.assertBranded(this, TextDecoder);
|
|
|
|
return this.#encoding;
|
2020-07-19 13:49:44 -04:00
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
/** @returns {boolean} */
|
|
|
|
get fatal() {
|
|
|
|
webidl.assertBranded(this, TextDecoder);
|
|
|
|
return this.#fatal;
|
2020-07-19 13:49:44 -04:00
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
/** @returns {boolean} */
|
|
|
|
get ignoreBOM() {
|
|
|
|
webidl.assertBranded(this, TextDecoder);
|
|
|
|
return this.#ignoreBOM;
|
2021-01-19 15:58:57 -05:00
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
/**
|
|
|
|
* @param {BufferSource} [input]
|
|
|
|
* @param {TextDecodeOptions} options
|
|
|
|
*/
|
|
|
|
decode(input = new Uint8Array(), options = {}) {
|
|
|
|
webidl.assertBranded(this, TextDecoder);
|
|
|
|
const prefix = "Failed to execute 'decode' on 'TextDecoder'";
|
|
|
|
if (input !== undefined) {
|
|
|
|
input = webidl.converters.BufferSource(input, {
|
|
|
|
prefix,
|
|
|
|
context: "Argument 1",
|
|
|
|
allowShared: true,
|
|
|
|
});
|
2021-01-19 15:58:57 -05:00
|
|
|
}
|
2021-06-05 17:10:07 -04:00
|
|
|
options = webidl.converters.TextDecodeOptions(options, {
|
|
|
|
prefix,
|
|
|
|
context: "Argument 2",
|
|
|
|
});
|
2021-01-24 14:08:01 -05:00
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
// TODO(lucacasonato): add fast path for non-streaming decoder & decode
|
2021-01-24 14:08:01 -05:00
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
if (this.#rid === null) {
|
|
|
|
this.#rid = core.opSync("op_encoding_new_decoder", {
|
|
|
|
label: this.#encoding,
|
|
|
|
fatal: this.#fatal,
|
|
|
|
ignoreBom: this.#ignoreBOM,
|
|
|
|
});
|
2021-01-24 14:08:01 -05:00
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
try {
|
|
|
|
if (ArrayBuffer.isView(input)) {
|
|
|
|
input = new Uint8Array(
|
|
|
|
input.buffer,
|
|
|
|
input.byteOffset,
|
|
|
|
input.byteLength,
|
2021-01-24 14:08:01 -05:00
|
|
|
);
|
|
|
|
} else {
|
2021-06-05 17:10:07 -04:00
|
|
|
input = new Uint8Array(input);
|
2021-01-24 14:08:01 -05:00
|
|
|
}
|
2021-06-05 17:10:07 -04:00
|
|
|
return core.opSync("op_encoding_decode", new Uint8Array(input), {
|
|
|
|
rid: this.#rid,
|
|
|
|
stream: options.stream,
|
|
|
|
});
|
|
|
|
} finally {
|
|
|
|
if (!options.stream) {
|
|
|
|
core.close(this.#rid);
|
|
|
|
this.#rid = null;
|
2020-07-19 13:49:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
get [Symbol.toStringTag]() {
|
|
|
|
return "TextDecoder";
|
2020-07-19 13:49:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
Object.defineProperty(TextDecoder.prototype, "encoding", {
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
});
|
|
|
|
Object.defineProperty(TextDecoder.prototype, "fatal", {
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
});
|
|
|
|
Object.defineProperty(TextDecoder.prototype, "ignoreBOM", {
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
});
|
|
|
|
Object.defineProperty(TextDecoder.prototype, "decode", {
|
|
|
|
enumerable: true,
|
|
|
|
writable: true,
|
|
|
|
configurable: true,
|
|
|
|
});
|
2020-07-19 13:49:44 -04:00
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
class TextEncoder {
|
|
|
|
constructor() {
|
|
|
|
this[webidl.brand] = webidl.brand;
|
2021-01-05 13:50:40 -05:00
|
|
|
}
|
2020-07-19 13:49:44 -04:00
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
/** @returns {string} */
|
2020-07-19 13:49:44 -04:00
|
|
|
get encoding() {
|
2021-06-05 17:10:07 -04:00
|
|
|
webidl.assertBranded(this, TextEncoder);
|
|
|
|
return "utf-8";
|
2020-07-19 13:49:44 -04:00
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
/**
|
|
|
|
* @param {string} input
|
|
|
|
* @returns {Uint8Array}
|
|
|
|
*/
|
|
|
|
encode(input = "") {
|
|
|
|
webidl.assertBranded(this, TextEncoder);
|
|
|
|
const prefix = "Failed to execute 'encode' on 'TextEncoder'";
|
|
|
|
input = webidl.converters.USVString(input, {
|
|
|
|
prefix,
|
|
|
|
context: "Argument 2",
|
2020-07-19 13:49:44 -04:00
|
|
|
});
|
2021-06-05 17:10:07 -04:00
|
|
|
return core.encode(input);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {string} source
|
|
|
|
* @param {Uint8Array} destination
|
|
|
|
* @returns {TextEncoderEncodeIntoResult}
|
|
|
|
*/
|
|
|
|
encodeInto(source, destination) {
|
|
|
|
webidl.assertBranded(this, TextEncoder);
|
|
|
|
const prefix = "Failed to execute 'encodeInto' on 'TextEncoder'";
|
|
|
|
source = webidl.converters.USVString(source, {
|
|
|
|
prefix,
|
|
|
|
context: "Argument 1",
|
|
|
|
});
|
|
|
|
destination = webidl.converters.Uint8Array(destination, {
|
|
|
|
prefix,
|
|
|
|
context: "Argument 2",
|
|
|
|
allowShared: true,
|
|
|
|
});
|
|
|
|
return core.opSync("op_encoding_encode_into", source, destination);
|
2020-07-19 13:49:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
get [Symbol.toStringTag]() {
|
|
|
|
return "TextEncoder";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
Object.defineProperty(TextEncoder.prototype, "encoding", {
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
});
|
|
|
|
Object.defineProperty(TextEncoder.prototype, "encode", {
|
|
|
|
enumerable: true,
|
|
|
|
writable: true,
|
|
|
|
configurable: true,
|
|
|
|
});
|
|
|
|
Object.defineProperty(TextEncoder.prototype, "encodeInto", {
|
|
|
|
enumerable: true,
|
|
|
|
writable: true,
|
|
|
|
configurable: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
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,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
);
|
2020-08-07 10:55:02 -04:00
|
|
|
|
2021-04-08 09:05:08 -04:00
|
|
|
/**
|
2021-04-28 10:08:51 -04:00
|
|
|
* @param {Uint8Array} bytes
|
2021-04-08 09:05:08 -04:00
|
|
|
*/
|
|
|
|
function decode(bytes, encoding) {
|
|
|
|
const BOMEncoding = BOMSniff(bytes);
|
|
|
|
let start = 0;
|
|
|
|
if (BOMEncoding !== null) {
|
|
|
|
encoding = BOMEncoding;
|
|
|
|
if (BOMEncoding === "UTF-8") start = 3;
|
|
|
|
else start = 2;
|
|
|
|
}
|
|
|
|
return new TextDecoder(encoding).decode(bytes.slice(start));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-04-28 10:08:51 -04:00
|
|
|
* @param {Uint8Array} bytes
|
2021-04-08 09:05:08 -04:00
|
|
|
*/
|
|
|
|
function BOMSniff(bytes) {
|
|
|
|
const BOM = bytes.subarray(0, 3);
|
|
|
|
if (BOM[0] === 0xEF && BOM[1] === 0xBB && BOM[2] === 0xBF) {
|
|
|
|
return "UTF-8";
|
|
|
|
}
|
|
|
|
if (BOM[0] === 0xFE && BOM[1] === 0xFF) return "UTF-16BE";
|
|
|
|
if (BOM[0] === 0xFF && BOM[1] === 0xFE) return "UTF-16LE";
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-06-05 17:10:07 -04:00
|
|
|
window.__bootstrap.encoding = {
|
|
|
|
TextEncoder,
|
|
|
|
TextDecoder,
|
|
|
|
decode,
|
|
|
|
};
|
2020-07-19 13:49:44 -04:00
|
|
|
})(this);
|