1/* 2 * Copyright 2017 Sam Thorogood. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17/** 18 * @fileoverview Polyfill for TextEncoder and TextDecoder. 19 * 20 * You probably want `text.min.js`, and not this file directly. 21 */ 22 23(function(scope) { 24'use strict'; 25 26// fail early 27if (scope['TextEncoder'] && scope['TextDecoder']) { 28 return false; 29} 30 31/** 32 * @constructor 33 * @param {string=} utfLabel 34 */ 35function FastTextEncoder(utfLabel='utf-8') { 36 if (utfLabel !== 'utf-8') { 37 throw new RangeError( 38 `Failed to construct 'TextEncoder': The encoding label provided ('${utfLabel}') is invalid.`); 39 } 40} 41 42Object.defineProperty(FastTextEncoder.prototype, 'encoding', {value: 'utf-8'}); 43 44/** 45 * @param {string} string 46 * @param {{stream: boolean}=} options 47 * @return {!Uint8Array} 48 */ 49FastTextEncoder.prototype.encode = function(string, options={stream: false}) { 50 if (options.stream) { 51 throw new Error(`Failed to encode: the 'stream' option is unsupported.`); 52 } 53 54 let pos = 0; 55 const len = string.length; 56 const out = []; 57 58 let at = 0; // output position 59 let tlen = Math.max(32, len + (len >> 1) + 7); // 1.5x size 60 let target = new Uint8Array((tlen >> 3) << 3); // ... but at 8 byte offset 61 62 while (pos < len) { 63 let value = string.charCodeAt(pos++); 64 if (value >= 0xd800 && value <= 0xdbff) { 65 // high surrogate 66 if (pos < len) { 67 const extra = string.charCodeAt(pos); 68 if ((extra & 0xfc00) === 0xdc00) { 69 ++pos; 70 value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000; 71 } 72 } 73 if (value >= 0xd800 && value <= 0xdbff) { 74 continue; // drop lone surrogate 75 } 76 } 77 78 // expand the buffer if we couldn't write 4 bytes 79 if (at + 4 > target.length) { 80 tlen += 8; // minimum extra 81 tlen *= (1.0 + (pos / string.length) * 2); // take 2x the remaining 82 tlen = (tlen >> 3) << 3; // 8 byte offset 83 84 const update = new Uint8Array(tlen); 85 update.set(target); 86 target = update; 87 } 88 89 if ((value & 0xffffff80) === 0) { // 1-byte 90 target[at++] = value; // ASCII 91 continue; 92 } else if ((value & 0xfffff800) === 0) { // 2-byte 93 target[at++] = ((value >> 6) & 0x1f) | 0xc0; 94 } else if ((value & 0xffff0000) === 0) { // 3-byte 95 target[at++] = ((value >> 12) & 0x0f) | 0xe0; 96 target[at++] = ((value >> 6) & 0x3f) | 0x80; 97 } else if ((value & 0xffe00000) === 0) { // 4-byte 98 target[at++] = ((value >> 18) & 0x07) | 0xf0; 99 target[at++] = ((value >> 12) & 0x3f) | 0x80; 100 target[at++] = ((value >> 6) & 0x3f) | 0x80; 101 } else { 102 // FIXME: do we care 103 continue; 104 } 105 106 target[at++] = (value & 0x3f) | 0x80; 107 } 108 109 return target.slice(0, at); 110} 111 112/** 113 * @constructor 114 * @param {string=} utfLabel 115 * @param {{fatal: boolean}=} options 116 */ 117function FastTextDecoder(utfLabel='utf-8', options={fatal: false}) { 118 if (utfLabel !== 'utf-8') { 119 throw new RangeError( 120 `Failed to construct 'TextDecoder': The encoding label provided ('${utfLabel}') is invalid.`); 121 } 122 if (options.fatal) { 123 throw new Error(`Failed to construct 'TextDecoder': the 'fatal' option is unsupported.`); 124 } 125} 126 127Object.defineProperty(FastTextDecoder.prototype, 'encoding', {value: 'utf-8'}); 128 129Object.defineProperty(FastTextDecoder.prototype, 'fatal', {value: false}); 130 131Object.defineProperty(FastTextDecoder.prototype, 'ignoreBOM', {value: false}); 132 133/** 134 * @param {(!ArrayBuffer|!ArrayBufferView)} buffer 135 * @param {{stream: boolean}=} options 136 */ 137FastTextDecoder.prototype.decode = function(buffer, options={stream: false}) { 138 if (options['stream']) { 139 throw new Error(`Failed to decode: the 'stream' option is unsupported.`); 140 } 141 142 const bytes = new Uint8Array(buffer); 143 let pos = 0; 144 const len = bytes.length; 145 const out = []; 146 147 while (pos < len) { 148 const byte1 = bytes[pos++]; 149 if (byte1 === 0) { 150 break; // NULL 151 } 152 153 if ((byte1 & 0x80) === 0) { // 1-byte 154 out.push(byte1); 155 } else if ((byte1 & 0xe0) === 0xc0) { // 2-byte 156 const byte2 = bytes[pos++] & 0x3f; 157 out.push(((byte1 & 0x1f) << 6) | byte2); 158 } else if ((byte1 & 0xf0) === 0xe0) { 159 const byte2 = bytes[pos++] & 0x3f; 160 const byte3 = bytes[pos++] & 0x3f; 161 out.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3); 162 } else if ((byte1 & 0xf8) === 0xf0) { 163 const byte2 = bytes[pos++] & 0x3f; 164 const byte3 = bytes[pos++] & 0x3f; 165 const byte4 = bytes[pos++] & 0x3f; 166 167 // this can be > 0xffff, so possibly generate surrogates
168 let codepoint = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4; 169 if (codepoint > 0xffff) { 170 // codepoint &= ~0x10000; 171 codepoint -= 0x10000; 172 out.push((codepoint >>> 10) & 0x3ff | 0xd800) 173 codepoint = 0xdc00 | codepoint & 0x3ff; 174 } 175 out.push(codepoint); 176 } else { 177 // FIXME: we're ignoring this 178 } 179 } 180 181 return String.fromCharCode.apply(null, out); 182} 183 184scope['TextEncoder'] = FastTextEncoder; 185scope['TextDecoder'] = FastTextDecoder; 186 187}(typeof window !== 'undefined' ? window : (typeof global !== 'undefined' ? global : this)));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.