src/vs/workbench/services/textfile/common/encoding.ts

792 LOC · 760 covered · 32 uncovered · 115 ranges · 179 concepts · 44 introducers · 108 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- encoding.ts ×19
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Readable, ReadableStream, newWriteableStream, listenStream } from '../../../../base/common/stream.js';
7 > import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from '../../../../base/common/buffer.js';
8 > import { importAMDNodeModule } from '../../../../amdX.js';
9 > import { CancellationTokenSource } from '../../../../base/common/cancellation.js';
10 > import { coalesce } from '../../../../base/common/arrays.js';
11 >
12 > export const UTF8 = 'utf8';
13 > export const UTF8_with_bom = 'utf8bom';
14 > export const UTF16be = 'utf16be';
15 > export const UTF16le = 'utf16le';
16 >
17 > export type UTF_ENCODING = typeof UTF8 | typeof UTF8_with_bom | typeof UTF16be | typeof UTF16le;
18 >
19 > export function isUTFEncoding(encoding: string): encoding is UTF_ENCODING {
20 return [UTF8, UTF8_with_bom, UTF16be, UTF16le].some(utfEncoding => utfEncoding === encoding);
21 }
23 > export const UTF16be_BOM = [0xFE, 0xFF];
24 > export const UTF16le_BOM = [0xFF, 0xFE];
25 > export const UTF8_BOM = [0xEF, 0xBB, 0xBF];
26 >
27 > const ZERO_BYTE_DETECTION_BUFFER_MAX_LEN = 512; // number of bytes to look at to decide about a file being binary or not
28 > const NO_ENCODING_GUESS_MIN_BYTES = 512; // when not auto guessing the encoding, small number of bytes are enough
29 > const AUTO_ENCODING_GUESS_MIN_BYTES = 512 * 8; // with auto guessing we want a lot more content to be read for guessing
30 > const AUTO_ENCODING_GUESS_MAX_BYTES = 512 * 128; // set an upper limit for the number of bytes we pass on to jschardet
31 >
32 > export interface IDecodeStreamOptions {
33 > acceptTextOnly: boolean;
34 > guessEncoding: boolean;
35 > candidateGuessEncodings: string[];
36 > minBytesRequiredForDetection?: number;
37 >
38 > overwriteEncoding(detectedEncoding: string | null): Promise<string>;
39 > }
40 >
41 > export interface IDecodeStreamResult {
42 > stream: ReadableStream<string>;
43 > detected: IDetectedEncodingResult;
44 > }
45 >
46 > export const enum DecodeStreamErrorKind {
47 >
48 > /**
49 > * Error indicating that the stream is binary even
50 > * though `acceptTextOnly` was specified.
51 > */
52 > STREAM_IS_BINARY = 1
53 > }
54 >
55 > export class DecodeStreamError extends Error {
56 >
57 > constructor(
58 > message: string, encoding.ts ×3
59 > readonly decodeStreamErrorKind: DecodeStreamErrorKind
60 > ) {
61 > super(message);
62 > }
64 >
65 > export interface IDecoderStream {
66 > write(buffer: Uint8Array): string;
67 > end(): string | undefined;
68 > }
69 >
70 > class DecoderStream implements IDecoderStream {
71 >
72 > /**
73 > * This stream will only load iconv-lite lazily if the encoding
74 > * is not UTF-8. This ensures that for most common cases we do
75 > * not pay the price of loading the module from disk.
76 > *
77 > * We still need to be careful when converting UTF-8 to a string
78 > * though because we read the file in chunks of Buffer and thus
79 > * need to decode it via TextDecoder helper that is available
80 > * in browser and node.js environments.
81 > */
82 > static async create(encoding: string): Promise<DecoderStream> {
83 > let decoder: IDecoderStream | undefined = undefined;
84 > if (encoding !== UTF8) {
85 > const iconv = await importAMDNodeModule<typeof import('@vscode/iconv-lite-umd')>('@vscode/iconv-lite-umd', 'lib/iconv-lite-umd.js'); encoding.ts ×1
86 > decoder = iconv.getDecoder(toNodeEncoding(encoding));
87 > } else { encoding.ts ×19
88 > const utf8TextDecoder = new TextDecoder(); encoding.ts ×1
89 > decoder = {
90 > write(buffer: Uint8Array): string {
91 > return utf8TextDecoder.decode(buffer, {
92 > // Signal to TextDecoder that potentially more data is coming
93 > // and that we are calling `decode` in the end to consume any
94 > // remainders
95 > stream: true
96 > });
97 > },
98 >
99 > end(): string | undefined {
100 > return utf8TextDecoder.decode();
101 > }
102 > };
103 > }
105 > return new DecoderStream(decoder);
106 > }
107 >
108 > private constructor(private iconvLiteDecoder: IDecoderStream) { }
109 >
110 > write(buffer: Uint8Array): string {
111 > return this.iconvLiteDecoder.write(buffer); encoding.ts ×7
112 > }
114 > end(): string | undefined {
115 > return this.iconvLiteDecoder.end(); encoding.ts ×7
116 > }
118 >
119 > export function toDecodeStream(source: VSBufferReadableStream, options: IDecodeStreamOptions): Promise<IDecodeStreamResult> {
120 > const minBytesRequiredForDetection = options.minBytesRequiredForDetection ?? (options.guessEncoding ? AUTO_ENCODING_GUESS_MIN_BYTES : NO_ENCODING_GUESS_MIN_BYTES); encoding.ts ×7
121 >
122 > return new Promise<IDecodeStreamResult>((resolve, reject) => {
123 > const target = newWriteableStream<string>(strings => strings.join(''));
124 >
125 > const bufferedChunks: VSBuffer[] = [];
126 > let bytesBuffered = 0;
127 >
128 > let decoder: IDecoderStream | undefined = undefined;
129 >
130 > const cts = new CancellationTokenSource();
131 >
132 > const createDecoder = async () => {
133 > try {
134 >
135 > // detect encoding from buffer
136 > const detected = await detectEncodingFromBuffer({
137 > buffer: VSBuffer.concat(bufferedChunks),
138 > bytesRead: bytesBuffered
139 > }, options.guessEncoding, options.candidateGuessEncodings);
140 >
141 > // throw early if the source seems binary and
142 > // we are instructed to only accept text
143 > if (detected.seemsBinary && options.acceptTextOnly) {
144 > throw new DecodeStreamError('Stream is binary but only text is accepted for decoding', DecodeStreamErrorKind.STREAM_IS_BINARY); encoding.ts ×3
145 > }
147 > // ensure to respect overwrite of encoding
148 > detected.encoding = await options.overwriteEncoding(detected.encoding);
149 >
150 > // decode and write buffered content
151 > decoder = await DecoderStream.create(detected.encoding);
152 > const decoded = decoder.write(VSBuffer.concat(bufferedChunks).buffer);
153 > target.write(decoded);
154 >
155 > bufferedChunks.length = 0;
156 > bytesBuffered = 0;
157 >
158 > // signal to the outside our detected encoding and final decoder stream
159 > resolve({
160 > stream: target,
161 > detected
162 > });
163 > } catch (error) {
165 > // Stop handling anything from the source and target
166 > cts.cancel();
167 > target.destroy();
168 >
169 > reject(error);
170 > }
171 > }; encoding.ts ×7
172 >
173 > listenStream(source, {
174 > onData: async chunk => {
176 > // if the decoder is ready, we just write directly
177 > if (decoder) {
178 > target.write(decoder.write(chunk.buffer)); encoding.ts ×1
179 > }
181 > // otherwise we need to buffer the data until the stream is ready
182 > else {
183 > bufferedChunks.push(chunk);
184 > bytesBuffered += chunk.byteLength;
185 >
186 > // buffered enough data for encoding detection, create stream
187 > if (bytesBuffered >= minBytesRequiredForDetection) {
189 > // pause stream here until the decoder is ready
190 > source.pause();
191 >
192 > await createDecoder();
193 >
194 > // resume stream now that decoder is ready but
195 > // outside of this stack to reduce recursion
196 > setTimeout(() => source.resume());
197 > }
198 > } encoding.ts ×3
199 > },
200 > onError: error => target.error(error), // simply forward to target encoding.ts ×7
201 > onEnd: async () => {
202 >
203 > // we were still waiting for data to do the encoding
204 > // detection. thus, wrap up starting the stream even
205 > // without all the data to get things going
206 > if (!decoder) {
207 > await createDecoder(); encoding.ts ×1
208 > }
210 > // end the target with the remainders of the decoder
211 > target.end(decoder?.end());
212 > }
213 > }, cts.token);
214 > });
215 > }
217 > export async function toEncodeReadable(readable: Readable<string>, encoding: string, options?: { addBOM?: boolean }): Promise<VSBufferReadable> { encoding.ts ×4
218 > const iconv = await importAMDNodeModule<typeof import('@vscode/iconv-lite-umd')>('@vscode/iconv-lite-umd', 'lib/iconv-lite-umd.js');
219 > const encoder = iconv.getEncoder(toNodeEncoding(encoding), options);
220 >
221 > let bytesWritten = false;
222 > let done = false;
223 >
224 > return {
225 > read() {
226 > if (done) {
227 > return null; encoding.ts ×5
228 > }
230 > const chunk = readable.read();
231 > if (typeof chunk !== 'string') {
232 > done = true;
233 >
234 > // If we are instructed to add a BOM but we detect that no
235 > // bytes have been written, we must ensure to return the BOM
236 > // ourselves so that we comply with the contract.
237 > if (!bytesWritten && options?.addBOM) {
238 > switch (encoding) { encoding.ts ×5
239 > case UTF8:
240 > case UTF8_with_bom:
241 > return VSBuffer.wrap(Uint8Array.from(UTF8_BOM)); encoding.ts ×1
242 > case UTF16be: encoding.ts ×5
243 > return VSBuffer.wrap(Uint8Array.from(UTF16be_BOM)); encoding.ts ×1
244 > case UTF16le: encoding.ts ×5
245 > return VSBuffer.wrap(Uint8Array.from(UTF16le_BOM)); encoding.ts ×1
246 > } encoding.ts ×5
247 > }
249 > const leftovers = encoder.end();
250 > if (leftovers && leftovers.length > 0) { encoding.ts ×4
251 bytesWritten = true;
252
253 return VSBuffer.wrap(leftovers);
254 }
256 > return null;
257 > }
259 > bytesWritten = true;
260 >
261 > return VSBuffer.wrap(encoder.write(chunk));
262 > } encoding.ts ×4
263 > };
264 > }
266 export async function encodingExists(encoding: string): Promise<boolean> {
267 const iconv = await importAMDNodeModule<typeof import('@vscode/iconv-lite-umd')>('@vscode/iconv-lite-umd', 'lib/iconv-lite-umd.js');
268
269 return iconv.encodingExists(toNodeEncoding(encoding));
270 }
272 > export function toNodeEncoding(enc: string | null): string {
273 > if (enc === UTF8_with_bom || enc === null) { encoding.ts ×1
274 > return UTF8; // iconv does not distinguish UTF 8 with or without BOM, so we need to help it encoding.ts ×1
275 > }
277 > return enc;
278 > }
280 > export function detectEncodingByBOMFromBuffer(buffer: VSBuffer | null, bytesRead: number): typeof UTF8_with_bom | typeof UTF16le | typeof UTF16be | null {
281 > if (!buffer || bytesRead < UTF16be_BOM.length) { encoding.ts ×4
282 > return null; encoding.ts ×1
283 > }
285 > const b0 = buffer.readUInt8(0);
286 > const b1 = buffer.readUInt8(1);
287 >
288 > // UTF-16 BE
289 > if (b0 === UTF16be_BOM[0] && b1 === UTF16be_BOM[1]) { encoding.ts ×4
290 > return UTF16be; encoding.ts ×1
291 > }
293 > // UTF-16 LE
294 > if (b0 === UTF16le_BOM[0] && b1 === UTF16le_BOM[1]) { encoding.ts ×4
295 > return UTF16le; encoding.ts ×1
296 > }
298 > if (bytesRead < UTF8_BOM.length) {
299 return null;
300 }
302 > const b2 = buffer.readUInt8(2);
303 >
304 > // UTF-8
305 > if (b0 === UTF8_BOM[0] && b1 === UTF8_BOM[1] && b2 === UTF8_BOM[2]) { encoding.ts ×4
306 > return UTF8_with_bom; encoding.ts ×1
307 > }
309 > return null;
310 > }
312 > // we explicitly ignore a specific set of encodings from auto guessing
313 > // - ASCII: we never want this encoding (most UTF-8 files would happily detect as
314 > // ASCII files and then you could not type non-ASCII characters anymore)
315 > // - UTF-16: we have our own detection logic for UTF-16
316 > // - UTF-32: we do not support this encoding in VSCode
317 > const IGNORE_ENCODINGS = ['ascii', 'utf-16', 'utf-32'];
318 >
319 > /**
320 > * Guesses the encoding from buffer.
321 > */
322 > async function guessEncodingByBuffer(buffer: VSBuffer, candidateGuessEncodings?: string[]): Promise<string | null> { encoding.ts ×6
323 > const jschardet = await importAMDNodeModule<typeof import('jschardet')>('jschardet', 'dist/jschardet.min.js');
324 >
325 > // ensure to limit buffer for guessing due to https://github.com/aadsm/jschardet/issues/53
326 > const limitedBuffer = buffer.slice(0, AUTO_ENCODING_GUESS_MAX_BYTES);
327 >
328 > // before guessing jschardet calls toString('binary') on input if it is a Buffer,
329 > // since we are using it inside browser environment as well we do conversion ourselves
330 > // https://github.com/aadsm/jschardet/blob/v2.1.1/src/index.js#L36-L40
331 > const binaryString = encodeLatin1(limitedBuffer.buffer);
332 >
333 > // ensure to convert candidate encodings to jschardet encoding names if provided
334 > if (candidateGuessEncodings) {
335 > candidateGuessEncodings = coalesce(candidateGuessEncodings.map(e => toJschardetEncoding(e))); encoding.ts ×3
336 > if (candidateGuessEncodings.length === 0) {
337 candidateGuessEncodings = undefined;
338 }
339 > } encoding.ts ×3
341 > let guessed: { encoding: string | undefined } | undefined;
342 > try {
343 > guessed = jschardet.detect(binaryString, candidateGuessEncodings ? { detectEncodings: candidateGuessEncodings } : undefined);
344 > } catch (error) {
345 return null; // jschardet throws for unknown encodings (https://github.com/microsoft/vscode/issues/239928)
346 }
348 > if (!guessed?.encoding) {
349 return null;
350 }
352 > const enc = guessed.encoding.toLowerCase();
353 > if (0 <= IGNORE_ENCODINGS.indexOf(enc)) {
354 > return null; // see comment above why we ignore some encodings encoding.ts ×1
355 > }
357 > return toIconvLiteEncoding(guessed.encoding);
358 > }
360 > const JSCHARDET_TO_ICONV_ENCODINGS: { [name: string]: string } = {
361 > 'ibm866': 'cp866',
362 > 'big5': 'cp950'
363 > };
364 >
365 > function normalizeEncoding(encodingName: string): string { encoding.ts ×3
366 > return encodingName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
367 > }
369 > function toIconvLiteEncoding(encodingName: string): string { encoding.ts ×3
370 > const normalizedEncodingName = normalizeEncoding(encodingName);
371 > const mapped = JSCHARDET_TO_ICONV_ENCODINGS[normalizedEncodingName];
372 >
373 > return mapped || normalizedEncodingName;
374 > }
376 > function toJschardetEncoding(encodingName: string): string | undefined { encoding.ts ×3
377 > const normalizedEncodingName = normalizeEncoding(encodingName);
378 > const mapped = GUESSABLE_ENCODINGS[normalizedEncodingName];
379 >
380 > return mapped ? mapped.guessableName : undefined;
381 > }
383 > function encodeLatin1(buffer: Uint8Array): string { encoding.ts ×6
384 > let result = '';
385 > for (let i = 0; i < buffer.length; i++) {
386 > result += String.fromCharCode(buffer[i]);
387 > }
388 >
389 > return result;
390 > }
392 > /**
393 > * The encodings that are allowed in a settings file don't match the canonical encoding labels specified by WHATWG.
394 > * See https://encoding.spec.whatwg.org/#names-and-labels
395 > * Iconv-lite strips all non-alphanumeric characters, but ripgrep doesn't. For backcompat, allow these labels.
396 > */
397 > export function toCanonicalName(enc: string): string {
398 > switch (enc) { encoding.ts ×12
399 > case 'shiftjis':
400 return 'shift-jis';
401 > case 'utf16le': encoding.ts ×12
402 return 'utf-16le';
403 > case 'utf16be': encoding.ts ×12
404 return 'utf-16be';
405 > case 'big5hkscs': encoding.ts ×12
406 return 'big5-hkscs';
407 > case 'eucjp': encoding.ts ×12
408 return 'euc-jp';
409 > case 'euckr': encoding.ts ×12
410 return 'euc-kr';
411 > case 'koi8r': encoding.ts ×12
412 return 'koi8-r';
413 > case 'koi8u': encoding.ts ×12
414 return 'koi8-u';
415 > case 'macroman': encoding.ts ×12
416 return 'x-mac-roman';
417 > case 'utf8bom': encoding.ts ×12
418 return 'utf8';
419 > default: { encoding.ts ×12
420 > const m = enc.match(/windows(\d+)/);
421 > if (m) {
422 > return 'windows-' + m[1];
423 > }
424
425 return enc;
426 }
428 > }
430 > export interface IDetectedEncodingResult {
431 > encoding: string | null;
432 > seemsBinary: boolean;
433 > }
434 >
435 > export interface IReadResult {
436 > buffer: VSBuffer | null;
437 > bytesRead: number;
438 > }
439 >
440 > export function detectEncodingFromBuffer(readResult: IReadResult, autoGuessEncoding?: false, candidateGuessEncodings?: string[]): IDetectedEncodingResult;
441 > export function detectEncodingFromBuffer(readResult: IReadResult, autoGuessEncoding?: boolean, candidateGuessEncodings?: string[]): Promise<IDetectedEncodingResult>;
442 > export function detectEncodingFromBuffer({ buffer, bytesRead }: IReadResult, autoGuessEncoding?: boolean, candidateGuessEncodings?: string[]): Promise<IDetectedEncodingResult> | IDetectedEncodingResult {
444 > // Always first check for BOM to find out about encoding
445 > let encoding = detectEncodingByBOMFromBuffer(buffer, bytesRead);
446 >
447 > // Detect 0 bytes to see if file is binary or UTF-16 LE/BE
448 > // unless we already know that this file has a UTF-16 encoding
449 > let seemsBinary = false;
450 > if (encoding !== UTF16be && encoding !== UTF16le && buffer) {
451 > let couldBeUTF16LE = true; // e.g. 0xAA 0x00 encoding.ts ×3
452 > let couldBeUTF16BE = true; // e.g. 0x00 0xAA
453 > let containsZeroByte = false;
454 >
455 > // This is a simplified guess to detect UTF-16 BE or LE by just checking if
456 > // the first 512 bytes have the 0-byte at a specific location. For UTF-16 LE
457 > // this would be the odd byte index and for UTF-16 BE the even one.
458 > // Note: this can produce false positives (a binary file that uses a 2-byte
459 > // encoding of the same format as UTF-16) and false negatives (a UTF-16 file
460 > // that is using 4 bytes to encode a character).
461 > for (let i = 0; i < bytesRead && i < ZERO_BYTE_DETECTION_BUFFER_MAX_LEN; i++) {
462 > const isEndian = (i % 2 === 1); // assume 2-byte sequences typical for UTF-16 encoding.ts ×5
463 > const isZeroByte = (buffer.readUInt8(i) === 0);
464 >
465 > if (isZeroByte) {
466 > containsZeroByte = true; encoding.ts ×4
467 > }
469 > // UTF-16 LE: expect e.g. 0xAA 0x00
470 > if (couldBeUTF16LE && (isEndian && !isZeroByte || !isEndian && isZeroByte)) {
471 > couldBeUTF16LE = false; encoding.ts ×1
472 > }
474 > // UTF-16 BE: expect e.g. 0x00 0xAA
475 > if (couldBeUTF16BE && (isEndian && isZeroByte || !isEndian && !isZeroByte)) {
476 > couldBeUTF16BE = false; encoding.ts ×1
477 > }
479 > // Return if this is neither UTF16-LE nor UTF16-BE and thus treat as binary
480 > if (isZeroByte && !couldBeUTF16LE && !couldBeUTF16BE) {
481 > break; encoding.ts ×2
482 > }
483 > } encoding.ts ×5
485 > // Handle case of 0-byte included
486 > if (containsZeroByte) {
487 > if (couldBeUTF16LE) { encoding.ts ×4
488 > encoding = UTF16le; encoding.ts ×1
489 > } else if (couldBeUTF16BE) { encoding.ts ×4
490 > encoding = UTF16be; encoding.ts ×1
491 > } else { encoding.ts ×1
492 > seemsBinary = true; encoding.ts ×2
493 > }
494 > } encoding.ts ×4
495 > } encoding.ts ×3
497 > // Auto guess encoding if configured
498 > if (autoGuessEncoding && !seemsBinary && !encoding && buffer) {
499 > return guessEncodingByBuffer(buffer.slice(0, bytesRead), candidateGuessEncodings).then(guessedEncoding => { encoding.ts ×6
500 > return {
501 > seemsBinary: false,
502 > encoding: guessedEncoding
503 > };
504 > });
505 > }
507 > return { seemsBinary, encoding };
508 > }
510 > type EncodingsMap = { [encoding: string]: { labelLong: string; labelShort: string; order: number; encodeOnly?: boolean; alias?: string; guessableName?: string } };
511 >
512 > export const SUPPORTED_ENCODINGS: EncodingsMap = {
513 > utf8: {
514 > labelLong: 'UTF-8',
515 > labelShort: 'UTF-8',
516 > order: 1,
517 > alias: 'utf8bom',
518 > guessableName: 'UTF-8'
519 > },
520 > utf8bom: {
521 > labelLong: 'UTF-8 with BOM',
522 > labelShort: 'UTF-8 with BOM',
523 > encodeOnly: true,
524 > order: 2,
525 > alias: 'utf8'
526 > },
527 > utf16le: {
528 > labelLong: 'UTF-16 LE',
529 > labelShort: 'UTF-16 LE',
530 > order: 3,
531 > guessableName: 'UTF-16LE'
532 > },
533 > utf16be: {
534 > labelLong: 'UTF-16 BE',
535 > labelShort: 'UTF-16 BE',
536 > order: 4,
537 > guessableName: 'UTF-16BE'
538 > },
539 > windows1252: {
540 > labelLong: 'Western (Windows 1252)',
541 > labelShort: 'Windows 1252',
542 > order: 5,
543 > guessableName: 'windows-1252'
544 > },
545 > iso88591: {
546 > labelLong: 'Western (ISO 8859-1)',
547 > labelShort: 'ISO 8859-1',
548 > order: 6
549 > },
550 > iso88593: {
551 > labelLong: 'Western (ISO 8859-3)',
552 > labelShort: 'ISO 8859-3',
553 > order: 7
554 > },
555 > iso885915: {
556 > labelLong: 'Western (ISO 8859-15)',
557 > labelShort: 'ISO 8859-15',
558 > order: 8
559 > },
560 > macroman: {
561 > labelLong: 'Western (Mac Roman)',
562 > labelShort: 'Mac Roman',
563 > order: 9
564 > },
565 > cp437: {
566 > labelLong: 'DOS (CP 437)',
567 > labelShort: 'CP437',
568 > order: 10
569 > },
570 > windows1256: {
571 > labelLong: 'Arabic (Windows 1256)',
572 > labelShort: 'Windows 1256',
573 > order: 11
574 > },
575 > iso88596: {
576 > labelLong: 'Arabic (ISO 8859-6)',
577 > labelShort: 'ISO 8859-6',
578 > order: 12
579 > },
580 > windows1257: {
581 > labelLong: 'Baltic (Windows 1257)',
582 > labelShort: 'Windows 1257',
583 > order: 13
584 > },
585 > iso88594: {
586 > labelLong: 'Baltic (ISO 8859-4)',
587 > labelShort: 'ISO 8859-4',
588 > order: 14
589 > },
590 > iso885914: {
591 > labelLong: 'Celtic (ISO 8859-14)',
592 > labelShort: 'ISO 8859-14',
593 > order: 15
594 > },
595 > windows1250: {
596 > labelLong: 'Central European (Windows 1250)',
597 > labelShort: 'Windows 1250',
598 > order: 16,
599 > guessableName: 'windows-1250'
600 > },
601 > iso88592: {
602 > labelLong: 'Central European (ISO 8859-2)',
603 > labelShort: 'ISO 8859-2',
604 > order: 17,
605 > guessableName: 'ISO-8859-2'
606 > },
607 > cp852: {
608 > labelLong: 'Central European (CP 852)',
609 > labelShort: 'CP 852',
610 > order: 18
611 > },
612 > windows1251: {
613 > labelLong: 'Cyrillic (Windows 1251)',
614 > labelShort: 'Windows 1251',
615 > order: 19,
616 > guessableName: 'windows-1251'
617 > },
618 > cp866: {
619 > labelLong: 'Cyrillic (CP 866)',
620 > labelShort: 'CP 866',
621 > order: 20,
622 > guessableName: 'IBM866'
623 > },
624 > cp1125: {
625 > labelLong: 'Cyrillic (CP 1125)',
626 > labelShort: 'CP 1125',
627 > order: 21,
628 > guessableName: 'IBM1125'
629 > },
630 > iso88595: {
631 > labelLong: 'Cyrillic (ISO 8859-5)',
632 > labelShort: 'ISO 8859-5',
633 > order: 22,
634 > guessableName: 'ISO-8859-5'
635 > },
636 > koi8r: {
637 > labelLong: 'Cyrillic (KOI8-R)',
638 > labelShort: 'KOI8-R',
639 > order: 23,
640 > guessableName: 'KOI8-R'
641 > },
642 > koi8u: {
643 > labelLong: 'Cyrillic (KOI8-U)',
644 > labelShort: 'KOI8-U',
645 > order: 24
646 > },
647 > iso885913: {
648 > labelLong: 'Estonian (ISO 8859-13)',
649 > labelShort: 'ISO 8859-13',
650 > order: 25
651 > },
652 > windows1253: {
653 > labelLong: 'Greek (Windows 1253)',
654 > labelShort: 'Windows 1253',
655 > order: 26,
656 > guessableName: 'windows-1253'
657 > },
658 > iso88597: {
659 > labelLong: 'Greek (ISO 8859-7)',
660 > labelShort: 'ISO 8859-7',
661 > order: 27,
662 > guessableName: 'ISO-8859-7'
663 > },
664 > windows1255: {
665 > labelLong: 'Hebrew (Windows 1255)',
666 > labelShort: 'Windows 1255',
667 > order: 28,
668 > guessableName: 'windows-1255'
669 > },
670 > iso88598: {
671 > labelLong: 'Hebrew (ISO 8859-8)',
672 > labelShort: 'ISO 8859-8',
673 > order: 29,
674 > guessableName: 'ISO-8859-8'
675 > },
676 > iso885910: {
677 > labelLong: 'Nordic (ISO 8859-10)',
678 > labelShort: 'ISO 8859-10',
679 > order: 30
680 > },
681 > iso885916: {
682 > labelLong: 'Romanian (ISO 8859-16)',
683 > labelShort: 'ISO 8859-16',
684 > order: 31
685 > },
686 > windows1254: {
687 > labelLong: 'Turkish (Windows 1254)',
688 > labelShort: 'Windows 1254',
689 > order: 32
690 > },
691 > iso88599: {
692 > labelLong: 'Turkish (ISO 8859-9)',
693 > labelShort: 'ISO 8859-9',
694 > order: 33
695 > },
696 > cp857: {
697 > labelLong: 'Turkish (CP 857)',
698 > labelShort: 'CP 857',
699 > order: 34
700 > },
701 > windows1258: {
702 > labelLong: 'Vietnamese (Windows 1258)',
703 > labelShort: 'Windows 1258',
704 > order: 35
705 > },
706 > gbk: {
707 > labelLong: 'Simplified Chinese (GBK)',
708 > labelShort: 'GBK',
709 > order: 36
710 > },
711 > gb18030: {
712 > labelLong: 'Simplified Chinese (GB18030)',
713 > labelShort: 'GB18030',
714 > order: 37
715 > },
716 > cp950: {
717 > labelLong: 'Traditional Chinese (Big5)',
718 > labelShort: 'Big5',
719 > order: 38,
720 > guessableName: 'Big5'
721 > },
722 > big5hkscs: {
723 > labelLong: 'Traditional Chinese (Big5-HKSCS)',
724 > labelShort: 'Big5-HKSCS',
725 > order: 39
726 > },
727 > shiftjis: {
728 > labelLong: 'Japanese (Shift JIS)',
729 > labelShort: 'Shift JIS',
730 > order: 40,
731 > guessableName: 'SHIFT_JIS'
732 > },
733 > eucjp: {
734 > labelLong: 'Japanese (EUC-JP)',
735 > labelShort: 'EUC-JP',
736 > order: 41,
737 > guessableName: 'EUC-JP'
738 > },
739 > euckr: {
740 > labelLong: 'Korean (EUC-KR)',
741 > labelShort: 'EUC-KR',
742 > order: 42,
743 > guessableName: 'EUC-KR'
744 > },
745 > windows874: {
746 > labelLong: 'Thai (Windows 874)',
747 > labelShort: 'Windows 874',
748 > order: 43
749 > },
750 > iso885911: {
751 > labelLong: 'Latin/Thai (ISO 8859-11)',
752 > labelShort: 'ISO 8859-11',
753 > order: 44
754 > },
755 > koi8ru: {
756 > labelLong: 'Cyrillic (KOI8-RU)',
757 > labelShort: 'KOI8-RU',
758 > order: 45
759 > },
760 > koi8t: {
761 > labelLong: 'Tajik (KOI8-T)',
762 > labelShort: 'KOI8-T',
763 > order: 46
764 > },
765 > gb2312: {
766 > labelLong: 'Simplified Chinese (GB 2312)',
767 > labelShort: 'GB 2312',
768 > order: 47,
769 > guessableName: 'GB2312'
770 > },
771 > cp865: {
772 > labelLong: 'Nordic DOS (CP 865)',
773 > labelShort: 'CP 865',
774 > order: 48
775 > },
776 > cp850: {
777 > labelLong: 'Western European DOS (CP 850)',
778 > labelShort: 'CP 850',
779 > order: 49
780 > }
781 > };
782 >
783 > export const GUESSABLE_ENCODINGS: EncodingsMap = (() => {
784 > const guessableEncodings: EncodingsMap = {};
785 > for (const encoding in SUPPORTED_ENCODINGS) {
786 > if (SUPPORTED_ENCODINGS[encoding].guessableName) {
787 > guessableEncodings[encoding] = SUPPORTED_ENCODINGS[encoding];
788 > }
789 > }
790 >
791 > return guessableEncodings;
792 > })();