Skip to content

Commit

Permalink
Encodings: do not load iconv-lite if file is UTF-8 (fix #101916)
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero committed Jul 8, 2020
1 parent 79d85e4 commit d3c4b4b
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 6 deletions.
6 changes: 4 additions & 2 deletions src/vs/workbench/services/textfile/browser/textFileService.ts
Expand Up @@ -619,8 +619,10 @@ export class EncodingOracle extends Disposable implements IResourceEncodings {
fileEncoding = this.textResourceConfigurationService.getValue(resource, 'files.encoding'); // and last we check for settings
}

if (!fileEncoding || !(await encodingExists(fileEncoding))) {
fileEncoding = UTF8; // the default is UTF 8
if (fileEncoding !== UTF8) {
if (!fileEncoding || !(await encodingExists(fileEncoding))) {
fileEncoding = UTF8; // the default is UTF-8
}
}

return fileEncoding;
Expand Down
43 changes: 39 additions & 4 deletions src/vs/workbench/services/textfile/common/encoding.ts
Expand Up @@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { DecoderStream } from 'iconv-lite-umd';
import { Readable, ReadableStream, newWriteableStream } from 'vs/base/common/stream';
import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from 'vs/base/common/buffer';

Expand Down Expand Up @@ -39,6 +38,43 @@ export interface IDecodeStreamResult {
detected: IDetectedEncodingResult;
}

export interface IDecoderStream {
write(buffer: Uint8Array): string;
end(): string | undefined;
}

class DecoderStream implements IDecoderStream {

/**
* This stream will only load iconv-lite lazily if the encoding
* is not UTF-8. This ensures that for most common cases we do
* not pay the price of loading the module from disk.
*/
static async create(encoding: string): Promise<DecoderStream> {
let decoder: IDecoderStream | undefined = undefined;
if (encoding !== UTF8) {
const iconv = await import('iconv-lite-umd');
decoder = iconv.getDecoder(toNodeEncoding(encoding));
}

return new DecoderStream(decoder);
}

private constructor(private iconvLiteDecoder: IDecoderStream | undefined) { }

write(buffer: Uint8Array): string {
if (this.iconvLiteDecoder) {
return this.iconvLiteDecoder.write(buffer);
}

return VSBuffer.wrap(buffer).toString();
}

end(): string | undefined {
return this.iconvLiteDecoder?.end();
}
}

export function toDecodeStream(source: VSBufferReadableStream, options: IDecodeStreamOptions): Promise<IDecodeStreamResult> {
const minBytesRequiredForDetection = options.minBytesRequiredForDetection ?? options.guessEncoding ? AUTO_ENCODING_GUESS_MIN_BYTES : NO_ENCODING_GUESS_MIN_BYTES;

Expand All @@ -48,7 +84,7 @@ export function toDecodeStream(source: VSBufferReadableStream, options: IDecodeS
const bufferedChunks: VSBuffer[] = [];
let bytesBuffered = 0;

let decoder: DecoderStream | undefined = undefined;
let decoder: IDecoderStream | undefined = undefined;

const createDecoder = async () => {
try {
Expand All @@ -63,8 +99,7 @@ export function toDecodeStream(source: VSBufferReadableStream, options: IDecodeS
detected.encoding = await options.overwriteEncoding(detected.encoding);

// decode and write buffered content
const iconv = await import('iconv-lite-umd');
decoder = iconv.getDecoder(toNodeEncoding(detected.encoding));
decoder = await DecoderStream.create(detected.encoding);
const decoded = decoder.write(VSBuffer.concat(bufferedChunks).buffer);
target.write(decoded);

Expand Down

0 comments on commit d3c4b4b

Please sign in to comment.