From 96e3848b5e3f79601738c4da251c13b6d0972253 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Thu, 6 Nov 2014 15:46:33 +0000 Subject: [PATCH] Updated CEF used, removed Encoding API shim. The new CEF release branch is based off Chromium 39, so has native support for the Encoding API. --- README.md | 2 +- resources/report/js/encoding.js | 2408 ------------------------------- 2 files changed, 1 insertion(+), 2409 deletions(-) delete mode 100644 resources/report/js/encoding.js diff --git a/README.md b/README.md index 35462cf1..c559e340 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ LOOT uses [CMake](http://cmake.org) to generate build files, and requires the fo * [Alphanum](http://www.davekoelle.com/files/alphanum.hpp) * [Boost](http://www.boost.org) v1.56.0 -* [Chromium Embedded Framework](https://code.google.com/p/chromiumembedded/) branch 2062 +* [Chromium Embedded Framework](https://code.google.com/p/chromiumembedded/) branch 2171 * [Google Test](https://code.google.com/p/googletest/) v1.7: Required to build the LOOT API's tests, but not the API itself or the LOOT application. * [Libespm](http://github.com/WrinklyNinja/libespm) * [Libgit2](http://libgit2.github.com/) v0.21.1 diff --git a/resources/report/js/encoding.js b/resources/report/js/encoding.js deleted file mode 100644 index 149aa497..00000000 --- a/resources/report/js/encoding.js +++ /dev/null @@ -1,2408 +0,0 @@ -// Copyright 2014 Joshua Bell. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// If we're in node require encoding-indexes and attach it to the global. -/** - * @fileoverview Global `this` required for resolving indexes in node. - * @suppress {globalThis} - */ -if (typeof module !== "undefined" && module.exports) { - this["encoding-indexes"] = - require("./encoding-indexes.js")["encoding-indexes"]; -} - -(function(global) { - 'use strict'; - - // - // Utilities - // - - /** - * @param {number} a The number to test. - * @param {number} min The minimum value in the range, inclusive. - * @param {number} max The maximum value in the range, inclusive. - * @return {boolean} True if a >= min and a <= max. - */ - function inRange(a, min, max) { - return min <= a && a <= max; - } - - /** - * @param {number} n The numerator. - * @param {number} d The denominator. - * @return {number} The result of the integer division of n by d. - */ - function div(n, d) { - return Math.floor(n / d); - } - - /** - * @param {Object=} o - * @return {Object} - * TODO: Use Object() if Closure Compiler can be made to accept it. - */ - function ToDictionary(o) { return o || {}; } - - - // - // Implementation of Encoding specification - // http://dvcs.w3.org/hg/encoding/raw-file/tip/Overview.html - // - - // - // 3. Terminology - // - - // - // 4. Encodings - // - - /** @const */ var EOF_byte = -1; - /** @const */ var EOF_code_point = -1; - - /** - * @constructor - * @param {Uint8Array} bytes Array of bytes that provide the stream. - */ - function ByteInputStream(bytes) { - /** @type {number} */ - var pos = 0; - - /** - * @this {ByteInputStream} - * @return {number} Get the next byte from the stream. - */ - this.get = function() { - return (pos >= bytes.length) ? EOF_byte : Number(bytes[pos]); - }; - - /** @param {number} n Number (positive or negative) by which to - * offset the byte pointer. */ - this.offset = function(n) { - pos += n; - if (pos < 0) - throw Error('Seeking past start of the buffer'); - if (pos > bytes.length) - throw Error('Seeking past EOF'); - }; - - /** - * @param {Array.} test Array of bytes to compare against. - * @return {boolean} True if the start of the stream matches the test - * bytes. - */ - this.match = function(test) { - if (test.length > pos + bytes.length) - return false; - var i; - for (i = 0; i < test.length; i += 1) { - if (Number(bytes[pos + i]) !== test[i]) - return false; - } - return true; - }; - } - - /** - * @constructor - * @param {Array.} bytes The array to write bytes into. - */ - function ByteOutputStream(bytes) { - /** @type {number} */ - var pos = 0; - - /** - * @param {...number} var_args The byte or bytes to emit into the stream. - * @return {number} The last byte emitted. - */ - this.emit = function(var_args) { - /** @type {number} */ - var last = EOF_byte; - var i; - for (i = 0; i < arguments.length; ++i) { - last = Number(arguments[i]); - bytes[pos++] = last; - } - return last; - }; - } - - /** - * @constructor - * @param {string} string The source of code units for the stream. - */ - function CodePointInputStream(string) { - /** - * @param {string} string Input string of UTF-16 code units. - * @return {Array.} Code points. - */ - function stringToCodePoints(string) { - /** @type {Array.} */ - var cps = []; - // Based on http://www.w3.org/TR/WebIDL/#idl-DOMString - var i = 0, n = string.length; - while (i < string.length) { - var c = string.charCodeAt(i); - if (!inRange(c, 0xD800, 0xDFFF)) { - cps.push(c); - } else if (inRange(c, 0xDC00, 0xDFFF)) { - cps.push(0xFFFD); - } else { // (inRange(cu, 0xD800, 0xDBFF)) - if (i === n - 1) { - cps.push(0xFFFD); - } else { - var d = string.charCodeAt(i + 1); - if (inRange(d, 0xDC00, 0xDFFF)) { - var a = c & 0x3FF; - var b = d & 0x3FF; - i += 1; - cps.push(0x10000 + (a << 10) + b); - } else { - cps.push(0xFFFD); - } - } - } - i += 1; - } - return cps; - } - - /** @type {number} */ - var pos = 0; - /** @type {Array.} */ - var cps = stringToCodePoints(string); - - /** @param {number} n The number of bytes (positive or negative) - * to advance the code point pointer by.*/ - this.offset = function(n) { - pos += n; - if (pos < 0) { - throw Error('Seeking past start of the buffer'); - } - if (pos > cps.length) { - throw Error('Seeking past EOF'); - } - }; - - - /** @return {number} Get the next code point from the stream. */ - this.get = function() { - if (pos >= cps.length) { - return EOF_code_point; - } - return cps[pos]; - }; - } - - /** - * @constructor - */ - function CodePointOutputStream() { - /** @type {string} */ - var string = ''; - - /** @return {string} The accumulated string. */ - this.string = function() { - return string; - }; - - /** @param {number} c The code point to encode into the stream. */ - this.emit = function(c) { - if (c <= 0xFFFF) { - string += String.fromCharCode(c); - } else { - c -= 0x10000; - string += String.fromCharCode(0xD800 + ((c >> 10) & 0x3ff)); - string += String.fromCharCode(0xDC00 + (c & 0x3ff)); - } - }; - } - - /** - * @constructor - * @param {string} message Description of the error. - * @return {Error} - */ - function EncodingError(message) { - var that = Error(message); - that.name = 'EncodingError'; - that.code = 0; - return that; - } - EncodingError.prototype = Error.prototype; - - /** - * @param {boolean} fatal If true, decoding errors raise an exception. - * @param {number=} opt_code_point Override the standard fallback code point. - * @return {number} The code point to insert on a decoding error. - */ - function decoderError(fatal, opt_code_point) { - if (fatal) - throw EncodingError('Decoder error'); - return opt_code_point || 0xFFFD; - } - - /** - * @param {number} code_point The code point that could not be encoded. - * @return {number} Always throws, no value is actually returned. - */ - function encoderError(code_point) { - throw EncodingError('The code point ' + code_point + - ' could not be encoded.'); - } - - // TODO: Define @typedef for Encoding: {name:string,labels:Array.} - // https://github.com/google/closure-compiler/issues/247 - - /** - * @param {string} label The encoding label. - * @return {?{name:string,labels:Array.}} - */ - function getEncoding(label) { - label = String(label).trim().toLowerCase(); - if (Object.prototype.hasOwnProperty.call(label_to_encoding, label)) { - return label_to_encoding[label]; - } - return null; - } - - /** @interface */ - function Decoder() {} - Decoder.prototype = { - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - decode: function(byte_pointer) {} - }; - - /** @interface */ - function Encoder() {} - Encoder.prototype = { - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - encode: function(output_byte_stream, code_point_pointer) {} - }; - - /** - * Encodings table: http://encoding.spec.whatwg.org/encodings.json - * @const - * @type {Array.<{ - * heading: string, - * encodings: Array.<{name:string,labels:Array.}> - * }>} - */ - var encodings = [ - { - "encodings": [ - { - "labels": [ - "unicode-1-1-utf-8", - "utf-8", - "utf8" - ], - "name": "utf-8" - } - ], - "heading": "The Encoding" - }, - { - "encodings": [ - { - "labels": [ - "866", - "cp866", - "csibm866", - "ibm866" - ], - "name": "ibm866" - }, - { - "labels": [ - "csisolatin2", - "iso-8859-2", - "iso-ir-101", - "iso8859-2", - "iso88592", - "iso_8859-2", - "iso_8859-2:1987", - "l2", - "latin2" - ], - "name": "iso-8859-2" - }, - { - "labels": [ - "csisolatin3", - "iso-8859-3", - "iso-ir-109", - "iso8859-3", - "iso88593", - "iso_8859-3", - "iso_8859-3:1988", - "l3", - "latin3" - ], - "name": "iso-8859-3" - }, - { - "labels": [ - "csisolatin4", - "iso-8859-4", - "iso-ir-110", - "iso8859-4", - "iso88594", - "iso_8859-4", - "iso_8859-4:1988", - "l4", - "latin4" - ], - "name": "iso-8859-4" - }, - { - "labels": [ - "csisolatincyrillic", - "cyrillic", - "iso-8859-5", - "iso-ir-144", - "iso8859-5", - "iso88595", - "iso_8859-5", - "iso_8859-5:1988" - ], - "name": "iso-8859-5" - }, - { - "labels": [ - "arabic", - "asmo-708", - "csiso88596e", - "csiso88596i", - "csisolatinarabic", - "ecma-114", - "iso-8859-6", - "iso-8859-6-e", - "iso-8859-6-i", - "iso-ir-127", - "iso8859-6", - "iso88596", - "iso_8859-6", - "iso_8859-6:1987" - ], - "name": "iso-8859-6" - }, - { - "labels": [ - "csisolatingreek", - "ecma-118", - "elot_928", - "greek", - "greek8", - "iso-8859-7", - "iso-ir-126", - "iso8859-7", - "iso88597", - "iso_8859-7", - "iso_8859-7:1987", - "sun_eu_greek" - ], - "name": "iso-8859-7" - }, - { - "labels": [ - "csiso88598e", - "csisolatinhebrew", - "hebrew", - "iso-8859-8", - "iso-8859-8-e", - "iso-ir-138", - "iso8859-8", - "iso88598", - "iso_8859-8", - "iso_8859-8:1988", - "visual" - ], - "name": "iso-8859-8" - }, - { - "labels": [ - "csiso88598i", - "iso-8859-8-i", - "logical" - ], - "name": "iso-8859-8-i" - }, - { - "labels": [ - "csisolatin6", - "iso-8859-10", - "iso-ir-157", - "iso8859-10", - "iso885910", - "l6", - "latin6" - ], - "name": "iso-8859-10" - }, - { - "labels": [ - "iso-8859-13", - "iso8859-13", - "iso885913" - ], - "name": "iso-8859-13" - }, - { - "labels": [ - "iso-8859-14", - "iso8859-14", - "iso885914" - ], - "name": "iso-8859-14" - }, - { - "labels": [ - "csisolatin9", - "iso-8859-15", - "iso8859-15", - "iso885915", - "iso_8859-15", - "l9" - ], - "name": "iso-8859-15" - }, - { - "labels": [ - "iso-8859-16" - ], - "name": "iso-8859-16" - }, - { - "labels": [ - "cskoi8r", - "koi", - "koi8", - "koi8-r", - "koi8_r" - ], - "name": "koi8-r" - }, - { - "labels": [ - "koi8-u" - ], - "name": "koi8-u" - }, - { - "labels": [ - "csmacintosh", - "mac", - "macintosh", - "x-mac-roman" - ], - "name": "macintosh" - }, - { - "labels": [ - "dos-874", - "iso-8859-11", - "iso8859-11", - "iso885911", - "tis-620", - "windows-874" - ], - "name": "windows-874" - }, - { - "labels": [ - "cp1250", - "windows-1250", - "x-cp1250" - ], - "name": "windows-1250" - }, - { - "labels": [ - "cp1251", - "windows-1251", - "x-cp1251" - ], - "name": "windows-1251" - }, - { - "labels": [ - "ansi_x3.4-1968", - "ascii", - "cp1252", - "cp819", - "csisolatin1", - "ibm819", - "iso-8859-1", - "iso-ir-100", - "iso8859-1", - "iso88591", - "iso_8859-1", - "iso_8859-1:1987", - "l1", - "latin1", - "us-ascii", - "windows-1252", - "x-cp1252" - ], - "name": "windows-1252" - }, - { - "labels": [ - "cp1253", - "windows-1253", - "x-cp1253" - ], - "name": "windows-1253" - }, - { - "labels": [ - "cp1254", - "csisolatin5", - "iso-8859-9", - "iso-ir-148", - "iso8859-9", - "iso88599", - "iso_8859-9", - "iso_8859-9:1989", - "l5", - "latin5", - "windows-1254", - "x-cp1254" - ], - "name": "windows-1254" - }, - { - "labels": [ - "cp1255", - "windows-1255", - "x-cp1255" - ], - "name": "windows-1255" - }, - { - "labels": [ - "cp1256", - "windows-1256", - "x-cp1256" - ], - "name": "windows-1256" - }, - { - "labels": [ - "cp1257", - "windows-1257", - "x-cp1257" - ], - "name": "windows-1257" - }, - { - "labels": [ - "cp1258", - "windows-1258", - "x-cp1258" - ], - "name": "windows-1258" - }, - { - "labels": [ - "x-mac-cyrillic", - "x-mac-ukrainian" - ], - "name": "x-mac-cyrillic" - } - ], - "heading": "Legacy single-byte encodings" - }, - { - "encodings": [ - { - "labels": [ - "chinese", - "csgb2312", - "csiso58gb231280", - "gb18030", - "gb2312", - "gb_2312", - "gb_2312-80", - "gbk", - "iso-ir-58", - "x-gbk" - ], - "name": "gb18030" - }, - { - "labels": [ - "hz-gb-2312" - ], - "name": "hz-gb-2312" - } - ], - "heading": "Legacy multi-byte Chinese (simplified) encodings" - }, - { - "encodings": [ - { - "labels": [ - "big5", - "big5-hkscs", - "cn-big5", - "csbig5", - "x-x-big5" - ], - "name": "big5" - } - ], - "heading": "Legacy multi-byte Chinese (traditional) encodings" - }, - { - "encodings": [ - { - "labels": [ - "cseucpkdfmtjapanese", - "euc-jp", - "x-euc-jp" - ], - "name": "euc-jp" - }, - { - "labels": [ - "csiso2022jp", - "iso-2022-jp" - ], - "name": "iso-2022-jp" - }, - { - "labels": [ - "csshiftjis", - "ms_kanji", - "shift-jis", - "shift_jis", - "sjis", - "windows-31j", - "x-sjis" - ], - "name": "shift_jis" - } - ], - "heading": "Legacy multi-byte Japanese encodings" - }, - { - "encodings": [ - { - "labels": [ - "cseuckr", - "csksc56011987", - "euc-kr", - "iso-ir-149", - "korean", - "ks_c_5601-1987", - "ks_c_5601-1989", - "ksc5601", - "ksc_5601", - "windows-949" - ], - "name": "euc-kr" - } - ], - "heading": "Legacy multi-byte Korean encodings" - }, - { - "encodings": [ - { - "labels": [ - "csiso2022kr", - "iso-2022-cn", - "iso-2022-cn-ext", - "iso-2022-kr" - ], - "name": "replacement" - }, - { - "labels": [ - "utf-16be" - ], - "name": "utf-16be" - }, - { - "labels": [ - "utf-16", - "utf-16le" - ], - "name": "utf-16le" - }, - { - "labels": [ - "x-user-defined" - ], - "name": "x-user-defined" - } - ], - "heading": "Legacy miscellaneous encodings" - } - ]; - - // Label to encoding registry. - /** @type {Object.}>} */ - var label_to_encoding = {}; - encodings.forEach(function(category) { - category.encodings.forEach(function(encoding) { - encoding.labels.forEach(function(label) { - label_to_encoding[label] = encoding; - }); - }); - }); - - // Registry of of encoder/decoder factories, by encoding name. - /** @type {Object.} */ - var encoders = {}; - /** @type {Object.} */ - var decoders = {}; - - // - // 5. Indexes - // - - /** - * @param {number} pointer The |pointer| to search for. - * @param {Array.|undefined} index The |index| to search within. - * @return {?number} The code point corresponding to |pointer| in |index|, - * or null if |code point| is not in |index|. - */ - function indexCodePointFor(pointer, index) { - if (!index) return null; - return index[pointer] || null; - } - - /** - * @param {number} code_point The |code point| to search for. - * @param {Array.} index The |index| to search within. - * @return {?number} The first pointer corresponding to |code point| in - * |index|, or null if |code point| is not in |index|. - */ - function indexPointerFor(code_point, index) { - var pointer = index.indexOf(code_point); - return pointer === -1 ? null : pointer; - } - - /** - * @param {string} name Name of the index. - * @return {(Array.|Array.>)} - * */ - function index(name) { - if (!('encoding-indexes' in global)) { - throw Error("Indexes missing." + - " Did you forget to include encoding-indexes.js?"); - } - return global['encoding-indexes'][name]; - } - - /** - * @param {number} pointer The |pointer| to search for in the gb18030 index. - * @return {?number} The code point corresponding to |pointer| in |index|, - * or null if |code point| is not in the gb18030 index. - */ - function indexGB18030CodePointFor(pointer) { - if ((pointer > 39419 && pointer < 189000) || (pointer > 1237575)) - return null; - var /** @type {number} */ offset = 0, - /** @type {number} */ code_point_offset = 0, - /** @type {Array.>} */ idx = index('gb18030'); - var i; - for (i = 0; i < idx.length; ++i) { - var entry = idx[i]; - if (entry[0] <= pointer) { - offset = entry[0]; - code_point_offset = entry[1]; - } else { - break; - } - } - return code_point_offset + pointer - offset; - } - - /** - * @param {number} code_point The |code point| to locate in the gb18030 index. - * @return {number} The first pointer corresponding to |code point| in the - * gb18030 index. - */ - function indexGB18030PointerFor(code_point) { - var /** @type {number} */ offset = 0, - /** @type {number} */ pointer_offset = 0, - /** @type {Array.>} */ idx = index('gb18030'); - var i; - for (i = 0; i < idx.length; ++i) { - var entry = idx[i]; - if (entry[1] <= code_point) { - offset = entry[1]; - pointer_offset = entry[0]; - } else { - break; - } - } - return pointer_offset + code_point - offset; - } - - - // - // 7. API - // - - /** @const */ var DEFAULT_ENCODING = 'utf-8'; - - // 7.1 Interface TextDecoder - - /** - * @constructor - * @param {string=} opt_encoding The label of the encoding; - * defaults to 'utf-8'. - * @param {Object=} options - */ - function TextDecoder(opt_encoding, options) { - if (!(this instanceof TextDecoder)) { - return new TextDecoder(opt_encoding, options); - } - opt_encoding = opt_encoding ? String(opt_encoding) : DEFAULT_ENCODING; - options = ToDictionary(options); - /** @private */ - this._encoding = getEncoding(opt_encoding); - if (this._encoding === null || this._encoding.name === 'replacement') - throw TypeError('Unknown encoding: ' + opt_encoding); - - if (!decoders[this._encoding.name]) { - throw Error('Decoder not present.' + - ' Did you forget to include encoding-indexes.js?'); - } - - /** @private @type {boolean} */ - this._streaming = false; - /** @private @type {boolean} */ - this._BOMseen = false; - /** @private @type {?Decoder} */ - this._decoder = null; - /** @private @type {{fatal: boolean}} */ - this._options = {fatal: Boolean(options['fatal'])}; - - if (Object.defineProperty) - Object.defineProperty(this, 'encoding', {value: this._encoding.name}); - else - this.encoding = this._encoding.name; - - return this; - } - - // TODO: Issue if input byte stream is offset by decoder - // TODO: BOM detection will not work if stream header spans multiple calls - // (last N bytes of previous stream may need to be retained?) - TextDecoder.prototype = { - /** - * @param {ArrayBufferView=} opt_view The buffer of bytes to decode. - * @param {Object=} options - * @return {string} The decoded string. - */ - decode: function decode(opt_view, options) { - if (opt_view && !('buffer' in opt_view && 'byteOffset' in opt_view && - 'byteLength' in opt_view)) { - throw TypeError('Expected ArrayBufferView'); - } else if (!opt_view) { - opt_view = new Uint8Array(0); - } - options = ToDictionary(options); - - if (!this._streaming) { - this._decoder = decoders[this._encoding.name](this._options); - this._BOMseen = false; - } - this._streaming = Boolean(options['stream']); - - var bytes = new Uint8Array(opt_view.buffer, - opt_view.byteOffset, - opt_view.byteLength); - var input_stream = new ByteInputStream(bytes); - - var output_stream = new CodePointOutputStream(); - - /** @type {?number} */ - var code_point; - - while (input_stream.get() !== EOF_byte) { - code_point = /** @type {?number} */ (this._decoder.decode(input_stream)); - if (code_point !== null && code_point !== EOF_code_point) - output_stream.emit(code_point); - } - if (!this._streaming) { - do { - code_point = /** @type {?number} */ (this._decoder.decode(input_stream)); - if (code_point !== null && code_point !== EOF_code_point) - output_stream.emit(code_point); - } while (code_point !== EOF_code_point && - input_stream.get() != EOF_byte); - this._decoder = null; - } - - var result = output_stream.string(); - if (!this._BOMseen && result.length) { - this._BOMseen = true; - if (['utf-8', 'utf-16le', 'utf-16be'].indexOf(this.encoding) !== -1 && - result.charCodeAt(0) === 0xFEFF) { - result = result.substring(1); - } - } - - return result; - } - }; - - // 7.2 Interface TextEncoder - - /** - * @constructor - * @param {string=} opt_encoding The label of the encoding; - * defaults to 'utf-8'. - * @param {Object=} options - */ - function TextEncoder(opt_encoding, options) { - if (!(this instanceof TextEncoder)) - return new TextEncoder(opt_encoding, options); - opt_encoding = opt_encoding ? String(opt_encoding) : DEFAULT_ENCODING; - options = ToDictionary(options); - /** @private */ - this._encoding = getEncoding(opt_encoding); - - var allowLegacyEncoding = - Boolean(options['NONSTANDARD_allowLegacyEncoding']); - var isLegacyEncoding = (this._encoding.name !== 'utf-8' && - this._encoding.name !== 'utf-16le' && - this._encoding.name !== 'utf-16be'); - if (this._encoding === null || (isLegacyEncoding && !allowLegacyEncoding)) - throw TypeError('Unknown encoding: ' + opt_encoding); - - if (!encoders[this._encoding.name]) { - throw Error('Encoder not present.' + - ' Did you forget to include encoding-indexes.js?'); - } - - /** @private @type {boolean} */ - this._streaming = false; - /** @private @type {?Encoder} */ - this._encoder = null; - /** @private @type {{fatal: boolean}} */ - this._options = {fatal: Boolean(options['fatal'])}; - - if (Object.defineProperty) - Object.defineProperty(this, 'encoding', {value: this._encoding.name}); - else - this.encoding = this._encoding.name; - - return this; - } - - TextEncoder.prototype = { - /** - * @param {string=} opt_string The string to encode. - * @param {Object=} options - * @return {Uint8Array} Encoded bytes, as a Uint8Array. - */ - encode: function encode(opt_string, options) { - opt_string = opt_string ? String(opt_string) : ''; - options = ToDictionary(options); - // TODO: any options? - if (!this._streaming) - this._encoder = encoders[this._encoding.name](this._options); - this._streaming = Boolean(options['stream']); - - var bytes = []; - var output_stream = new ByteOutputStream(bytes); - var input_stream = new CodePointInputStream(opt_string); - while (input_stream.get() !== EOF_code_point) { - this._encoder.encode(output_stream, input_stream); - } - if (!this._streaming) { - /** @type {number} */ - var last_byte; - do { - last_byte = this._encoder.encode(output_stream, input_stream); - } while (last_byte !== EOF_byte); - this._encoder = null; - } - return new Uint8Array(bytes); - } - }; - - - // - // 8. The encoding - // - - // 8.1 utf-8 - - /** - * @constructor - * @implements {Decoder} - * @param {{fatal: boolean}} options - */ - function UTF8Decoder(options) { - var fatal = options.fatal; - var /** @type {number} */ utf8_code_point = 0, - /** @type {number} */ utf8_bytes_needed = 0, - /** @type {number} */ utf8_bytes_seen = 0, - /** @type {number} */ utf8_lower_boundary = 0; - - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite === EOF_byte) { - if (utf8_bytes_needed !== 0) - return decoderError(fatal); - return EOF_code_point; - } - byte_pointer.offset(1); - - if (utf8_bytes_needed === 0) { - if (inRange(bite, 0x00, 0x7F)) - return bite; - if (inRange(bite, 0xC2, 0xDF)) { - utf8_bytes_needed = 1; - utf8_lower_boundary = 0x80; - utf8_code_point = bite - 0xC0; - } else if (inRange(bite, 0xE0, 0xEF)) { - utf8_bytes_needed = 2; - utf8_lower_boundary = 0x800; - utf8_code_point = bite - 0xE0; - } else if (inRange(bite, 0xF0, 0xF4)) { - utf8_bytes_needed = 3; - utf8_lower_boundary = 0x10000; - utf8_code_point = bite - 0xF0; - } else { - return decoderError(fatal); - } - utf8_code_point = utf8_code_point * Math.pow(64, utf8_bytes_needed); - return null; - } - if (!inRange(bite, 0x80, 0xBF)) { - utf8_code_point = 0; - utf8_bytes_needed = 0; - utf8_bytes_seen = 0; - utf8_lower_boundary = 0; - byte_pointer.offset(-1); - return decoderError(fatal); - } - utf8_bytes_seen += 1; - utf8_code_point = utf8_code_point + (bite - 0x80) * - Math.pow(64, utf8_bytes_needed - utf8_bytes_seen); - if (utf8_bytes_seen !== utf8_bytes_needed) - return null; - var code_point = utf8_code_point; - var lower_boundary = utf8_lower_boundary; - utf8_code_point = 0; - utf8_bytes_needed = 0; - utf8_bytes_seen = 0; - utf8_lower_boundary = 0; - if (inRange(code_point, lower_boundary, 0x10FFFF) && - !inRange(code_point, 0xD800, 0xDFFF)) { - return code_point; - } - return decoderError(fatal); - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {{fatal: boolean}} options - */ - function UTF8Encoder(options) { - var fatal = options.fatal; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - /** @type {number} */ - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if (inRange(code_point, 0xD800, 0xDFFF)) - return encoderError(code_point); - if (inRange(code_point, 0x0000, 0x007f)) - return output_byte_stream.emit(code_point); - var count, offset; - if (inRange(code_point, 0x0080, 0x07FF)) { - count = 1; - offset = 0xC0; - } else if (inRange(code_point, 0x0800, 0xFFFF)) { - count = 2; - offset = 0xE0; - } else if (inRange(code_point, 0x10000, 0x10FFFF)) { - count = 3; - offset = 0xF0; - } - var result = output_byte_stream.emit( - div(code_point, Math.pow(64, count)) + offset); - while (count > 0) { - var temp = div(code_point, Math.pow(64, count - 1)); - result = output_byte_stream.emit(0x80 + (temp % 64)); - count -= 1; - } - return result; - }; - } - - /** @param {{fatal: boolean}} options */ - encoders['utf-8'] = function(options) { - return new UTF8Encoder(options); - }; - /** @param {{fatal: boolean}} options */ - decoders['utf-8'] = function(options) { - return new UTF8Decoder(options); - }; - - // - // 9. Legacy single-byte encodings - // - - /** - * @constructor - * @implements {Decoder} - * @param {Array.} index The encoding index. - * @param {{fatal: boolean}} options - */ - function SingleByteDecoder(index, options) { - var fatal = options.fatal; - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite === EOF_byte) - return EOF_code_point; - byte_pointer.offset(1); - if (inRange(bite, 0x00, 0x7F)) - return bite; - var code_point = index[bite - 0x80]; - if (code_point === null) - return decoderError(fatal); - return code_point; - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {Array.} index The encoding index. - * @param {{fatal: boolean}} options - */ - function SingleByteEncoder(index, options) { - var fatal = options.fatal; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if (inRange(code_point, 0x0000, 0x007F)) - return output_byte_stream.emit(code_point); - var pointer = indexPointerFor(code_point, index); - if (pointer === null) - encoderError(code_point); - return output_byte_stream.emit(pointer + 0x80); - }; - } - - (function() { - if (!('encoding-indexes' in global)) - return; - encodings.forEach(function(category) { - if (category.heading !== 'Legacy single-byte encodings') - return; - category.encodings.forEach(function(encoding) { - var name = encoding.name; - var idx = index(name); - /** @param {{fatal: boolean}} options */ - decoders[name] = function(options) { - return new SingleByteDecoder(idx, options); - }; - /** @param {{fatal: boolean}} options */ - encoders[name] = function(options) { - return new SingleByteEncoder(idx, options); - }; - }); - }); - }()); - - // - // 10. Legacy multi-byte Chinese (simplified) encodings - // - - // 9.1 gb18030 - - /** - * @constructor - * @implements {Decoder} - * @param {{fatal: boolean}} options - */ - function GB18030Decoder(options) { - var fatal = options.fatal; - var /** @type {number} */ gb18030_first = 0x00, - /** @type {number} */ gb18030_second = 0x00, - /** @type {number} */ gb18030_third = 0x00; - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite === EOF_byte && gb18030_first === 0x00 && - gb18030_second === 0x00 && gb18030_third === 0x00) { - return EOF_code_point; - } - if (bite === EOF_byte && - (gb18030_first !== 0x00 || gb18030_second !== 0x00 || gb18030_third !== 0x00)) { - gb18030_first = 0x00; - gb18030_second = 0x00; - gb18030_third = 0x00; - decoderError(fatal); - } - byte_pointer.offset(1); - var code_point; - if (gb18030_third !== 0x00) { - code_point = null; - if (inRange(bite, 0x30, 0x39)) { - code_point = indexGB18030CodePointFor( - (((gb18030_first - 0x81) * 10 + (gb18030_second - 0x30)) * 126 + - (gb18030_third - 0x81)) * 10 + bite - 0x30); - } - gb18030_first = 0x00; - gb18030_second = 0x00; - gb18030_third = 0x00; - if (code_point === null) { - byte_pointer.offset(-3); - return decoderError(fatal); - } - return code_point; - } - if (gb18030_second !== 0x00) { - if (inRange(bite, 0x81, 0xFE)) { - gb18030_third = bite; - return null; - } - byte_pointer.offset(-2); - gb18030_first = 0x00; - gb18030_second = 0x00; - return decoderError(fatal); - } - if (gb18030_first !== 0x00) { - if (inRange(bite, 0x30, 0x39)) { - gb18030_second = bite; - return null; - } - var lead = gb18030_first; - var pointer = null; - gb18030_first = 0x00; - var offset = bite < 0x7F ? 0x40 : 0x41; - if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFE)) - pointer = (lead - 0x81) * 190 + (bite - offset); - code_point = pointer === null ? null : - indexCodePointFor(pointer, index('gb18030')); - if (pointer === null) - byte_pointer.offset(-1); - if (code_point === null) - return decoderError(fatal); - return code_point; - } - if (inRange(bite, 0x00, 0x7F)) - return bite; - if (bite === 0x80) - return 0x20AC; - if (inRange(bite, 0x81, 0xFE)) { - gb18030_first = bite; - return null; - } - return decoderError(fatal); - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {{fatal: boolean}} options - */ - function GB18030Encoder(options) { - var fatal = options.fatal; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if (inRange(code_point, 0x0000, 0x007F)) { - return output_byte_stream.emit(code_point); - } - var pointer = indexPointerFor(code_point, index('gb18030')); - if (pointer !== null) { - var lead = div(pointer, 190) + 0x81; - var trail = pointer % 190; - var offset = trail < 0x3F ? 0x40 : 0x41; - return output_byte_stream.emit(lead, trail + offset); - } - pointer = indexGB18030PointerFor(code_point); - var byte1 = div(div(div(pointer, 10), 126), 10); - pointer = pointer - byte1 * 10 * 126 * 10; - var byte2 = div(div(pointer, 10), 126); - pointer = pointer - byte2 * 10 * 126; - var byte3 = div(pointer, 10); - var byte4 = pointer - byte3 * 10; - return output_byte_stream.emit(byte1 + 0x81, - byte2 + 0x30, - byte3 + 0x81, - byte4 + 0x30); - }; - } - - /** @param {{fatal: boolean}} options */ - encoders['gb18030'] = function(options) { - return new GB18030Encoder(options); - }; - /** @param {{fatal: boolean}} options */ - decoders['gb18030'] = function(options) { - return new GB18030Decoder(options); - }; - - // 10.2 hz-gb-2312 - - /** - * @constructor - * @implements {Decoder} - * @param {{fatal: boolean}} options - */ - function HZGB2312Decoder(options) { - var fatal = options.fatal; - var /** @type {boolean} */ hzgb2312 = false, - /** @type {number} */ hzgb2312_lead = 0x00; - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite === EOF_byte && hzgb2312_lead === 0x00) - return EOF_code_point; - if (bite === EOF_byte && hzgb2312_lead !== 0x00) { - hzgb2312_lead = 0x00; - return decoderError(fatal); - } - byte_pointer.offset(1); - if (hzgb2312_lead === 0x7E) { - hzgb2312_lead = 0x00; - if (bite === 0x7B) { - hzgb2312 = true; - return null; - } - if (bite === 0x7D) { - hzgb2312 = false; - return null; - } - if (bite === 0x7E) - return 0x007E; - if (bite === 0x0A) - return null; - byte_pointer.offset(-1); - return decoderError(fatal); - } - if (hzgb2312_lead !== 0x00) { - var lead = hzgb2312_lead; - hzgb2312_lead = 0x00; - var code_point = null; - if (inRange(bite, 0x21, 0x7E)) { - code_point = indexCodePointFor((lead - 1) * 190 + - (bite + 0x3F), index('gb18030')); - } - if (bite === 0x0A) - hzgb2312 = false; - if (code_point === null) - return decoderError(fatal); - return code_point; - } - if (bite === 0x7E) { - hzgb2312_lead = 0x7E; - return null; - } - if (hzgb2312) { - if (inRange(bite, 0x20, 0x7F)) { - hzgb2312_lead = bite; - return null; - } - if (bite === 0x0A) - hzgb2312 = false; - return decoderError(fatal); - } - if (inRange(bite, 0x00, 0x7F)) - return bite; - return decoderError(fatal); - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {{fatal: boolean}} options - */ - function HZGB2312Encoder(options) { - var fatal = options.fatal; - /** @type {boolean} */ - var hzgb2312 = false; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) { - return EOF_byte; - } - code_point_pointer.offset(1); - if (inRange(code_point, 0x0000, 0x007F) && hzgb2312) { - code_point_pointer.offset(-1); - hzgb2312 = false; - return output_byte_stream.emit(0x7E, 0x7D); - } - if (code_point === 0x007E) - return output_byte_stream.emit(0x7E, 0x7E); - if (inRange(code_point, 0x0000, 0x007F)) - return output_byte_stream.emit(code_point); - if (!hzgb2312) { - code_point_pointer.offset(-1); - hzgb2312 = true; - return output_byte_stream.emit(0x7E, 0x7B); - } - var pointer = indexPointerFor(code_point, index('gb18030')); - if (pointer === null) - return encoderError(code_point); - var lead = div(pointer, 190) + 1; - var trail = pointer % 190 - 0x3F; - if (!inRange(lead, 0x21, 0x7E) || !inRange(trail, 0x21, 0x7E)) - return encoderError(code_point); - return output_byte_stream.emit(lead, trail); - }; - } - - /** @param {{fatal: boolean}} options */ - encoders['hz-gb-2312'] = function(options) { - return new HZGB2312Encoder(options); - }; - /** @param {{fatal: boolean}} options */ - decoders['hz-gb-2312'] = function(options) { - return new HZGB2312Decoder(options); - }; - - // - // 11. Legacy multi-byte Chinese (traditional) encodings - // - - // 11.1 big5 - - /** - * @constructor - * @implements {Decoder} - * @param {{fatal: boolean}} options - */ - function Big5Decoder(options) { - var fatal = options.fatal; - var /** @type {number} */ big5_lead = 0x00, - /** @type {?number} */ big5_pending = null; - - /** - * @param {ByteInputStream} byte_pointer The byte steram to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - // NOTE: Hack to support emitting two code points - if (big5_pending !== null) { - var pending = big5_pending; - big5_pending = null; - return pending; - } - var bite = byte_pointer.get(); - if (bite === EOF_byte && big5_lead === 0x00) - return EOF_code_point; - if (bite === EOF_byte && big5_lead !== 0x00) { - big5_lead = 0x00; - return decoderError(fatal); - } - byte_pointer.offset(1); - if (big5_lead !== 0x00) { - var lead = big5_lead; - var pointer = null; - big5_lead = 0x00; - var offset = bite < 0x7F ? 0x40 : 0x62; - if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0xA1, 0xFE)) - pointer = (lead - 0x81) * 157 + (bite - offset); - if (pointer === 1133) { - big5_pending = 0x0304; - return 0x00CA; - } - if (pointer === 1135) { - big5_pending = 0x030C; - return 0x00CA; - } - if (pointer === 1164) { - big5_pending = 0x0304; - return 0x00EA; - } - if (pointer === 1166) { - big5_pending = 0x030C; - return 0x00EA; - } - var code_point = (pointer === null) ? null : - indexCodePointFor(pointer, index('big5')); - if (pointer === null) - byte_pointer.offset(-1); - if (code_point === null) - return decoderError(fatal); - return code_point; - } - if (inRange(bite, 0x00, 0x7F)) - return bite; - if (inRange(bite, 0x81, 0xFE)) { - big5_lead = bite; - return null; - } - return decoderError(fatal); - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {{fatal: boolean}} options - */ - function Big5Encoder(options) { - var fatal = options.fatal; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if (inRange(code_point, 0x0000, 0x007F)) - return output_byte_stream.emit(code_point); - var pointer = indexPointerFor(code_point, index('big5')); - if (pointer === null) - return encoderError(code_point); - var lead = div(pointer, 157) + 0x81; - //if (lead < 0xA1) { - // return encoderError(code_point); - //} - var trail = pointer % 157; - var offset = trail < 0x3F ? 0x40 : 0x62; - return output_byte_stream.emit(lead, trail + offset); - }; - } - - /** @param {{fatal: boolean}} options */ - encoders['big5'] = function(options) { - return new Big5Encoder(options); - }; - /** @param {{fatal: boolean}} options */ - decoders['big5'] = function(options) { - return new Big5Decoder(options); - }; - - - // - // 12. Legacy multi-byte Japanese encodings - // - - // 12.1 euc.jp - - /** - * @constructor - * @implements {Decoder} - * @param {{fatal: boolean}} options - */ - function EUCJPDecoder(options) { - var fatal = options.fatal; - var /** @type {number} */ eucjp_first = 0x00, - /** @type {number} */ eucjp_second = 0x00; - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite === EOF_byte) { - if (eucjp_first === 0x00 && eucjp_second === 0x00) - return EOF_code_point; - eucjp_first = 0x00; - eucjp_second = 0x00; - return decoderError(fatal); - } - byte_pointer.offset(1); - - var lead, code_point; - if (eucjp_second !== 0x00) { - lead = eucjp_second; - eucjp_second = 0x00; - code_point = null; - if (inRange(lead, 0xA1, 0xFE) && inRange(bite, 0xA1, 0xFE)) { - code_point = indexCodePointFor((lead - 0xA1) * 94 + bite - 0xA1, - index('jis0212')); - } - if (!inRange(bite, 0xA1, 0xFE)) - byte_pointer.offset(-1); - if (code_point === null) - return decoderError(fatal); - return code_point; - } - if (eucjp_first === 0x8E && inRange(bite, 0xA1, 0xDF)) { - eucjp_first = 0x00; - return 0xFF61 + bite - 0xA1; - } - if (eucjp_first === 0x8F && inRange(bite, 0xA1, 0xFE)) { - eucjp_first = 0x00; - eucjp_second = bite; - return null; - } - if (eucjp_first !== 0x00) { - lead = eucjp_first; - eucjp_first = 0x00; - code_point = null; - if (inRange(lead, 0xA1, 0xFE) && inRange(bite, 0xA1, 0xFE)) { - code_point = indexCodePointFor((lead - 0xA1) * 94 + bite - 0xA1, - index('jis0208')); - } - if (!inRange(bite, 0xA1, 0xFE)) - byte_pointer.offset(-1); - if (code_point === null) - return decoderError(fatal); - return code_point; - } - if (inRange(bite, 0x00, 0x7F)) - return bite; - if (bite === 0x8E || bite === 0x8F || (inRange(bite, 0xA1, 0xFE))) { - eucjp_first = bite; - return null; - } - return decoderError(fatal); - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {{fatal: boolean}} options - */ - function EUCJPEncoder(options) { - var fatal = options.fatal; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if (inRange(code_point, 0x0000, 0x007F)) - return output_byte_stream.emit(code_point); - if (code_point === 0x00A5) - return output_byte_stream.emit(0x5C); - if (code_point === 0x203E) - return output_byte_stream.emit(0x7E); - if (inRange(code_point, 0xFF61, 0xFF9F)) - return output_byte_stream.emit(0x8E, code_point - 0xFF61 + 0xA1); - - var pointer = indexPointerFor(code_point, index('jis0208')); - if (pointer === null) - return encoderError(code_point); - var lead = div(pointer, 94) + 0xA1; - var trail = pointer % 94 + 0xA1; - return output_byte_stream.emit(lead, trail); - }; - } - - /** @param {{fatal: boolean}} options */ - encoders['euc-jp'] = function(options) { - return new EUCJPEncoder(options); - }; - /** @param {{fatal: boolean}} options */ - decoders['euc-jp'] = function(options) { - return new EUCJPDecoder(options); - }; - - // 12.2 iso-2022-jp - - /** - * @constructor - * @implements {Decoder} - * @param {{fatal: boolean}} options - */ - function ISO2022JPDecoder(options) { - var fatal = options.fatal; - /** @enum */ - var state = { - ASCII: 0, - escape_start: 1, - escape_middle: 2, - escape_final: 3, - lead: 4, - trail: 5, - Katakana: 6 - }; - var /** @type {number} */ iso2022jp_state = state.ASCII, - /** @type {boolean} */ iso2022jp_jis0212 = false, - /** @type {number} */ iso2022jp_lead = 0x00; - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite !== EOF_byte) - byte_pointer.offset(1); - switch (iso2022jp_state) { - case state.ASCII: - default: - if (bite === 0x1B) { - iso2022jp_state = state.escape_start; - return null; - } - if (inRange(bite, 0x00, 0x7F)) - return bite; - if (bite === EOF_byte) - return EOF_code_point; - return decoderError(fatal); - - case state.escape_start: - if (bite === 0x24 || bite === 0x28) { - iso2022jp_lead = bite; - iso2022jp_state = state.escape_middle; - return null; - } - if (bite !== EOF_byte) - byte_pointer.offset(-1); - iso2022jp_state = state.ASCII; - return decoderError(fatal); - - case state.escape_middle: - var lead = iso2022jp_lead; - iso2022jp_lead = 0x00; - if (lead === 0x24 && (bite === 0x40 || bite === 0x42)) { - iso2022jp_jis0212 = false; - iso2022jp_state = state.lead; - return null; - } - if (lead === 0x24 && bite === 0x28) { - iso2022jp_state = state.escape_final; - return null; - } - if (lead === 0x28 && (bite === 0x42 || bite === 0x4A)) { - iso2022jp_state = state.ASCII; - return null; - } - if (lead === 0x28 && bite === 0x49) { - iso2022jp_state = state.Katakana; - return null; - } - if (bite === EOF_byte) - byte_pointer.offset(-1); - else - byte_pointer.offset(-2); - iso2022jp_state = state.ASCII; - return decoderError(fatal); - - case state.escape_final: - if (bite === 0x44) { - iso2022jp_jis0212 = true; - iso2022jp_state = state.lead; - return null; - } - if (bite === EOF_byte) - byte_pointer.offset(-2); - else - byte_pointer.offset(-3); - iso2022jp_state = state.ASCII; - return decoderError(fatal); - - case state.lead: - if (bite === 0x0A) { - iso2022jp_state = state.ASCII; - return decoderError(fatal, 0x000A); - } - if (bite === 0x1B) { - iso2022jp_state = state.escape_start; - return null; - } - if (bite === EOF_byte) - return EOF_code_point; - iso2022jp_lead = bite; - iso2022jp_state = state.trail; - return null; - - case state.trail: - iso2022jp_state = state.lead; - if (bite === EOF_byte) - return decoderError(fatal); - var code_point = null; - var pointer = (iso2022jp_lead - 0x21) * 94 + bite - 0x21; - if (inRange(iso2022jp_lead, 0x21, 0x7E) && - inRange(bite, 0x21, 0x7E)) { - code_point = (iso2022jp_jis0212 === false) ? - indexCodePointFor(pointer, index('jis0208')) : - indexCodePointFor(pointer, index('jis0212')); - } - if (code_point === null) - return decoderError(fatal); - return code_point; - - case state.Katakana: - if (bite === 0x1B) { - iso2022jp_state = state.escape_start; - return null; - } - if (inRange(bite, 0x21, 0x5F)) - return 0xFF61 + bite - 0x21; - if (bite === EOF_byte) - return EOF_code_point; - return decoderError(fatal); - } - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {{fatal: boolean}} options - */ - function ISO2022JPEncoder(options) { - var fatal = options.fatal; - /** @enum */ - var state = { - ASCII: 0, - lead: 1, - Katakana: 2 - }; - var /** @type {number} */ iso2022jp_state = state.ASCII; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if ((inRange(code_point, 0x0000, 0x007F) || - code_point === 0x00A5 || code_point === 0x203E) && - iso2022jp_state !== state.ASCII) { - code_point_pointer.offset(-1); - iso2022jp_state = state.ASCII; - return output_byte_stream.emit(0x1B, 0x28, 0x42); - } - if (inRange(code_point, 0x0000, 0x007F)) - return output_byte_stream.emit(code_point); - if (code_point === 0x00A5) - return output_byte_stream.emit(0x5C); - if (code_point === 0x203E) - return output_byte_stream.emit(0x7E); - if (inRange(code_point, 0xFF61, 0xFF9F) && - iso2022jp_state !== state.Katakana) { - code_point_pointer.offset(-1); - iso2022jp_state = state.Katakana; - return output_byte_stream.emit(0x1B, 0x28, 0x49); - } - if (inRange(code_point, 0xFF61, 0xFF9F)) - return output_byte_stream.emit(code_point - 0xFF61 - 0x21); - if (iso2022jp_state !== state.lead) { - code_point_pointer.offset(-1); - iso2022jp_state = state.lead; - return output_byte_stream.emit(0x1B, 0x24, 0x42); - } - var pointer = indexPointerFor(code_point, index('jis0208')); - if (pointer === null) - return encoderError(code_point); - var lead = div(pointer, 94) + 0x21; - var trail = pointer % 94 + 0x21; - return output_byte_stream.emit(lead, trail); - }; - } - - /** @param {{fatal: boolean}} options */ - encoders['iso-2022-jp'] = function(options) { - return new ISO2022JPEncoder(options); - }; - /** @param {{fatal: boolean}} options */ - decoders['iso-2022-jp'] = function(options) { - return new ISO2022JPDecoder(options); - }; - - // 12.3 shift_jis - - /** - * @constructor - * @implements {Decoder} - * @param {{fatal: boolean}} options - */ - function ShiftJISDecoder(options) { - var fatal = options.fatal; - var /** @type {number} */ shiftjis_lead = 0x00; - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite === EOF_byte && shiftjis_lead === 0x00) - return EOF_code_point; - if (bite === EOF_byte && shiftjis_lead !== 0x00) { - shiftjis_lead = 0x00; - return decoderError(fatal); - } - byte_pointer.offset(1); - if (shiftjis_lead !== 0x00) { - var lead = shiftjis_lead; - shiftjis_lead = 0x00; - if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFC)) { - var offset = (bite < 0x7F) ? 0x40 : 0x41; - var lead_offset = (lead < 0xA0) ? 0x81 : 0xC1; - var code_point = indexCodePointFor((lead - lead_offset) * 188 + - bite - offset, index('jis0208')); - if (code_point === null) - return decoderError(fatal); - return code_point; - } - byte_pointer.offset(-1); - return decoderError(fatal); - } - if (inRange(bite, 0x00, 0x80)) - return bite; - if (inRange(bite, 0xA1, 0xDF)) - return 0xFF61 + bite - 0xA1; - if (inRange(bite, 0x81, 0x9F) || inRange(bite, 0xE0, 0xFC)) { - shiftjis_lead = bite; - return null; - } - return decoderError(fatal); - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {{fatal: boolean}} options - */ - function ShiftJISEncoder(options) { - var fatal = options.fatal; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if (inRange(code_point, 0x0000, 0x0080)) - return output_byte_stream.emit(code_point); - if (code_point === 0x00A5) - return output_byte_stream.emit(0x5C); - if (code_point === 0x203E) - return output_byte_stream.emit(0x7E); - if (inRange(code_point, 0xFF61, 0xFF9F)) - return output_byte_stream.emit(code_point - 0xFF61 + 0xA1); - var pointer = indexPointerFor(code_point, index('jis0208')); - if (pointer === null) - return encoderError(code_point); - var lead = div(pointer, 188); - var lead_offset = lead < 0x1F ? 0x81 : 0xC1; - var trail = pointer % 188; - var offset = trail < 0x3F ? 0x40 : 0x41; - return output_byte_stream.emit(lead + lead_offset, trail + offset); - }; - } - - /** @param {{fatal: boolean}} options */ - encoders['shift_jis'] = function(options) { - return new ShiftJISEncoder(options); - }; - /** @param {{fatal: boolean}} options */ - decoders['shift_jis'] = function(options) { - return new ShiftJISDecoder(options); - }; - - // - // 13. Legacy multi-byte Korean encodings - // - - // 13.1 euc-kr - - /** - * @constructor - * @implements {Decoder} - * @param {{fatal: boolean}} options - */ - function EUCKRDecoder(options) { - var fatal = options.fatal; - var /** @type {number} */ euckr_lead = 0x00; - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite === EOF_byte && euckr_lead === 0) - return EOF_code_point; - if (bite === EOF_byte && euckr_lead !== 0) { - euckr_lead = 0x00; - return decoderError(fatal); - } - byte_pointer.offset(1); - if (euckr_lead !== 0x00) { - var lead = euckr_lead; - var pointer = null; - euckr_lead = 0x00; - - if (inRange(lead, 0x81, 0xC6)) { - var temp = (26 + 26 + 126) * (lead - 0x81); - if (inRange(bite, 0x41, 0x5A)) - pointer = temp + bite - 0x41; - else if (inRange(bite, 0x61, 0x7A)) - pointer = temp + 26 + bite - 0x61; - else if (inRange(bite, 0x81, 0xFE)) - pointer = temp + 26 + 26 + bite - 0x81; - } - - if (inRange(lead, 0xC7, 0xFD) && inRange(bite, 0xA1, 0xFE)) { - pointer = (26 + 26 + 126) * (0xC7 - 0x81) + (lead - 0xC7) * 94 + - (bite - 0xA1); - } - - var code_point = (pointer === null) ? null : - indexCodePointFor(pointer, index('euc-kr')); - if (pointer === null) - byte_pointer.offset(-1); - if (code_point === null) - return decoderError(fatal); - return code_point; - } - - if (inRange(bite, 0x00, 0x7F)) - return bite; - - if (inRange(bite, 0x81, 0xFD)) { - euckr_lead = bite; - return null; - } - - return decoderError(fatal); - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {{fatal: boolean}} options - */ - function EUCKREncoder(options) { - var fatal = options.fatal; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if (inRange(code_point, 0x0000, 0x007F)) - return output_byte_stream.emit(code_point); - var pointer = indexPointerFor(code_point, index('euc-kr')); - if (pointer === null) - return encoderError(code_point); - var lead, trail; - if (pointer < ((26 + 26 + 126) * (0xC7 - 0x81))) { - lead = div(pointer, (26 + 26 + 126)) + 0x81; - trail = pointer % (26 + 26 + 126); - var offset = trail < 26 ? 0x41 : trail < 26 + 26 ? 0x47 : 0x4D; - return output_byte_stream.emit(lead, trail + offset); - } - pointer = pointer - (26 + 26 + 126) * (0xC7 - 0x81); - lead = div(pointer, 94) + 0xC7; - trail = pointer % 94 + 0xA1; - return output_byte_stream.emit(lead, trail); - }; - } - - /** @param {{fatal: boolean}} options */ - encoders['euc-kr'] = function(options) { - return new EUCKREncoder(options); - }; - /** @param {{fatal: boolean}} options */ - decoders['euc-kr'] = function(options) { - return new EUCKRDecoder(options); - }; - - - // - // 14. Legacy miscellaneous encodings - // - - // 14.1 replacement - - // Not needed - API throws TypeError - - // 14.2 utf-16 - - /** - * @constructor - * @implements {Decoder} - * @param {boolean} utf16_be True if big-endian, false if little-endian. - * @param {{fatal: boolean}} options - */ - function UTF16Decoder(utf16_be, options) { - var fatal = options.fatal; - var /** @type {?number} */ utf16_lead_byte = null, - /** @type {?number} */ utf16_lead_surrogate = null; - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite === EOF_byte && utf16_lead_byte === null && - utf16_lead_surrogate === null) { - return EOF_code_point; - } - if (bite === EOF_byte && (utf16_lead_byte !== null || - utf16_lead_surrogate !== null)) { - return decoderError(fatal); - } - byte_pointer.offset(1); - if (utf16_lead_byte === null) { - utf16_lead_byte = bite; - return null; - } - var code_point; - if (utf16_be) - code_point = (utf16_lead_byte << 8) + bite; - else - code_point = (bite << 8) + utf16_lead_byte; - utf16_lead_byte = null; - if (utf16_lead_surrogate !== null) { - var lead_surrogate = utf16_lead_surrogate; - utf16_lead_surrogate = null; - if (inRange(code_point, 0xDC00, 0xDFFF)) { - return 0x10000 + (lead_surrogate - 0xD800) * 0x400 + - (code_point - 0xDC00); - } - byte_pointer.offset(-2); - return decoderError(fatal); - } - if (inRange(code_point, 0xD800, 0xDBFF)) { - utf16_lead_surrogate = code_point; - return null; - } - if (inRange(code_point, 0xDC00, 0xDFFF)) - return decoderError(fatal); - return code_point; - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {boolean} utf16_be True if big-endian, false if little-endian. - * @param {{fatal: boolean}} options - */ - function UTF16Encoder(utf16_be, options) { - var fatal = options.fatal; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - /** - * @param {number} code_unit - * @return {number} last byte emitted - */ - function convert_to_bytes(code_unit) { - var byte1 = code_unit >> 8; - var byte2 = code_unit & 0x00FF; - if (utf16_be) - return output_byte_stream.emit(byte1, byte2); - return output_byte_stream.emit(byte2, byte1); - } - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if (inRange(code_point, 0xD800, 0xDFFF)) - encoderError(code_point); - if (code_point <= 0xFFFF) - return convert_to_bytes(code_point); - var lead = div((code_point - 0x10000), 0x400) + 0xD800; - var trail = ((code_point - 0x10000) % 0x400) + 0xDC00; - convert_to_bytes(lead); - return convert_to_bytes(trail); - }; - } - - // 14.3 utf-16be - /** @param {{fatal: boolean}} options */ - encoders['utf-16be'] = function(options) { - return new UTF16Encoder(true, options); - }; - /** @param {{fatal: boolean}} options */ - decoders['utf-16be'] = function(options) { - return new UTF16Decoder(true, options); - }; - - // 14.4 utf-16le - /** @param {{fatal: boolean}} options */ - encoders['utf-16le'] = function(options) { - return new UTF16Encoder(false, options); - }; - /** @param {{fatal: boolean}} options */ - decoders['utf-16le'] = function(options) { - return new UTF16Decoder(false, options); - }; - - // 14.5 x-user-defined - - /** - * @constructor - * @implements {Decoder} - * @param {{fatal: boolean}} options - */ - function XUserDefinedDecoder(options) { - var fatal = options.fatal; - /** - * @param {ByteInputStream} byte_pointer The byte stream to decode. - * @return {?number} The next code point decoded, or null if not enough - * data exists in the input stream to decode a complete code point. - */ - this.decode = function(byte_pointer) { - var bite = byte_pointer.get(); - if (bite === EOF_byte) - return EOF_code_point; - byte_pointer.offset(1); - if (inRange(bite, 0x00, 0x7F)) - return bite; - return 0xF780 + bite - 0x80; - }; - } - - /** - * @constructor - * @implements {Encoder} - * @param {{fatal: boolean}} options - */ - function XUserDefinedEncoder(options) { - var fatal = options.fatal; - /** - * @param {ByteOutputStream} output_byte_stream Output byte stream. - * @param {CodePointInputStream} code_point_pointer Input stream. - * @return {number} The last byte emitted. - */ - this.encode = function(output_byte_stream, code_point_pointer) { - var code_point = code_point_pointer.get(); - if (code_point === EOF_code_point) - return EOF_byte; - code_point_pointer.offset(1); - if (inRange(code_point, 0x0000, 0x007F)) - return output_byte_stream.emit(code_point); - if (inRange(code_point, 0xF780, 0xF7FF)) - return output_byte_stream.emit(code_point - 0xF780 + 0x80); - return encoderError(code_point); - }; - } - - /** @param {{fatal: boolean}} options */ - encoders['x-user-defined'] = function(options) { - return new XUserDefinedEncoder(options); - }; - /** @param {{fatal: boolean}} options */ - decoders['x-user-defined'] = function(options) { - return new XUserDefinedDecoder(options); - }; - - // NOTE: currently unused - /** - * @param {string} label The encoding label. - * @param {ByteInputStream} input_stream The byte stream to test. - */ - function detectEncoding(label, input_stream) { - if (input_stream.match([0xFF, 0xFE])) { - input_stream.offset(2); - return 'utf-16le'; - } - if (input_stream.match([0xFE, 0xFF])) { - input_stream.offset(2); - return 'utf-16be'; - } - if (input_stream.match([0xEF, 0xBB, 0xBF])) { - input_stream.offset(3); - return 'utf-8'; - } - return label; - } - - if (!('TextEncoder' in global)) - global['TextEncoder'] = TextEncoder; - if (!('TextDecoder' in global)) - global['TextDecoder'] = TextDecoder; -}(this));