From 3a82edd0a07ee998bf41337879c2cf69f75b0c11 Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Sun, 4 Feb 2024 22:27:56 +0100 Subject: [PATCH] Use string concatentation instead of spreading to prevent stack overflow --- src/main/TextDecoder.ts | 24 ++++++++++++------------ src/test/TextDecoder.test.ts | 8 ++++++++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/main/TextDecoder.ts b/src/main/TextDecoder.ts index 146f6f0..4571075 100644 --- a/src/main/TextDecoder.ts +++ b/src/main/TextDecoder.ts @@ -64,7 +64,7 @@ export class TextDecoder implements globalThis.TextDecoder { // Decode the input bytes const inputStream = new ByteBuffer(bytes); - const output = []; + let output = ""; let result: number | number[] | null; while (!inputStream.isEndOfBuffer()) { result = this.decoder.decode(inputStream); @@ -72,10 +72,10 @@ export class TextDecoder implements globalThis.TextDecoder { break; } if (result != null) { - if (Array.isArray(result)) { - output.push(...result); + if (typeof result === "number") { + output += String.fromCodePoint(result); } else { - output.push(result); + output += String.fromCodePoint(...result); } } } @@ -86,10 +86,10 @@ export class TextDecoder implements globalThis.TextDecoder { break; } if (result != null) { - if (Array.isArray(result)) { - output.push(...result); + if (typeof result === "number") { + output += String.fromCodePoint(result); } else { - output.push(result); + output += String.fromCodePoint(...result); } } } while(!inputStream.isEndOfBuffer()); @@ -99,14 +99,14 @@ export class TextDecoder implements globalThis.TextDecoder { // Remove BOM header from output if ignoreBOM flag is not set if ([ "utf-8", "utf-16le", "utf-16be" ].includes(this.encoding) && !this.ignoreBOM && !this.seenBOM) { if (output.length > 0) { - if (output[0] === 0xFEFF) { - output.shift(); - } this.seenBOM = true; + if (output[0] === "\uFEFF") { + return output.substring(1); + } } } - // Create and return string from decoded code points - return String.fromCodePoint(...output); + // Join the decoded code points into a full string and return it + return output; } } diff --git a/src/test/TextDecoder.test.ts b/src/test/TextDecoder.test.ts index 2443a6d..2f2f55d 100644 --- a/src/test/TextDecoder.test.ts +++ b/src/test/TextDecoder.test.ts @@ -328,4 +328,12 @@ describe("TextDecoder", () => { it("correctly maps 0xCA to U+05BA in windows-1255 encoding", () => { expect(new TextDecoder("windows-1255").decode(new Uint8Array([ 0xca ]))).toBe("\u05BA"); }); + it("correctly decodes a very large input", () => { + const data = new Uint16Array(1_000_000); + data.fill(0x5400); + const utf16 = new Uint8Array(data.buffer); + const decoded = new TextDecoder("utf-16be").decode(utf16); + expect(decoded.length).toBe(1_000_000); + expect(decoded).toContain("TTTT"); + }); });