diff --git a/src/InputHandler.test.ts b/src/InputHandler.test.ts index ca63bdae..d8defa1c 100644 --- a/src/InputHandler.test.ts +++ b/src/InputHandler.test.ts @@ -1248,4 +1248,22 @@ describe('InputHandler', () => { assert.deepEqual(getLines(term, term.rows + 1), ['12345', '125', '125', '125', '125', '125']); }); }); + it('should parse big chunks in smaller subchunks', () => { + // max single chunk size is hardcoded as 131072 + const calls: any[] = []; + const term = new TestTerminal({cols: 10, rows: 10}); + (term as any)._inputHandler._parser.parse = (data: Uint32Array, length: number) => { + calls.push([data.length, length]); + }; + term.writeSync('12345'); + term.writeSync('a'.repeat(10000)); + term.writeSync('a'.repeat(200000)); + term.writeSync('a'.repeat(300000)); + assert.deepEqual(calls, [ + [4096, 5], + [10000, 10000], + [131072, 131072], [131072, 200000 - 131072], + [131072, 131072], [131072, 131072], [131072, 300000 - 131072 - 131072] + ]); + }); }); diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 21ad8ea0..f0f8d147 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -28,6 +28,11 @@ import { DcsHandler } from 'common/parser/DcsParser'; */ const GLEVEL: {[key: string]: number} = {'(': 0, ')': 1, '*': 2, '+': 3, '-': 1, '.': 2}; +/** + * Max length of the UTF32 input buffer. Real memory consumption is 4 times higher. + */ +const MAX_PARSEBUFFER_LENGTH = 131072; + /** * DCS subparser implementations @@ -335,14 +340,28 @@ export class InputHandler extends Disposable implements IInputHandler { this._logService.debug('parsing data', data); + // resize input buffer if needed if (this._parseBuffer.length < data.length) { - this._parseBuffer = new Uint32Array(data.length); + if (this._parseBuffer.length < MAX_PARSEBUFFER_LENGTH) { + this._parseBuffer = new Uint32Array(Math.min(data.length, MAX_PARSEBUFFER_LENGTH)); + } } - this._parser.parse(this._parseBuffer, - (typeof data === 'string') + + // process big data in smaller chunks + if (data.length > MAX_PARSEBUFFER_LENGTH) { + for (let i = 0; i < data.length; i += MAX_PARSEBUFFER_LENGTH) { + const end = i + MAX_PARSEBUFFER_LENGTH < data.length ? i + MAX_PARSEBUFFER_LENGTH : data.length; + const len = (typeof data === 'string') + ? this._stringDecoder.decode(data.substring(i, end), this._parseBuffer) + : this._utf8Decoder.decode(data.subarray(i, end), this._parseBuffer); + this._parser.parse(this._parseBuffer, len); + } + } else { + const len = (typeof data === 'string') ? this._stringDecoder.decode(data, this._parseBuffer) - : this._utf8Decoder.decode(data, this._parseBuffer) - ); + : this._utf8Decoder.decode(data, this._parseBuffer); + this._parser.parse(this._parseBuffer, len); + } buffer = this._bufferService.buffer; if (buffer.x !== cursorStartX || buffer.y !== cursorStartY) {