diff options
author | 2023-07-02 08:01:52 +0800 | |
---|---|---|
committer | 2023-07-01 17:01:52 -0700 | |
commit | 4720fa1207d374a2447d457ad478f9f8911b959a (patch) | |
tree | e8268b3c91ea992842682afd94f32747668a136f | |
parent | df10252979aa3d87a8d127707a23678b76a15583 (diff) | |
download | bun-4720fa1207d374a2447d457ad478f9f8911b959a.tar.gz bun-4720fa1207d374a2447d457ad478f9f8911b959a.tar.zst bun-4720fa1207d374a2447d457ad478f9f8911b959a.zip |
[WIP]Fix calling `Buffer.toString` with `(offset, length, encoding)` (#3467)
* Allow `toString` to be called with `(offset, length, encoding)`.
Close: #3085
* handle undefined value
* add tests for buffer.xxxSlice
* fix parameters
* fix offset and length
Diffstat (limited to '')
-rw-r--r-- | src/bun.js/bindings/JSBuffer.cpp | 67 | ||||
-rw-r--r-- | src/js/builtins/JSBufferPrototype.ts | 32 | ||||
-rw-r--r-- | test/js/node/buffer.test.js | 79 |
3 files changed, 135 insertions, 43 deletions
diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp index 00965da89..4b0e058dd 100644 --- a/src/bun.js/bindings/JSBuffer.cpp +++ b/src/bun.js/bindings/JSBuffer.cpp @@ -1436,43 +1436,56 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JS if (length == 0) return JSC::JSValue::encode(JSC::jsEmptyString(vm)); - switch (callFrame->argumentCount()) { - case 0: { - break; - } - case 2: - case 3: - case 1: { - EnsureStillAliveScope arg1 = callFrame->uncheckedArgument(0); - if (!arg1.value().isUndefined()) { - encoding = parseEncoding(lexicalGlobalObject, scope, arg1.value()); + size_t argsCount = callFrame->argumentCount(); + + JSC::JSValue arg1 = callFrame->argument(0); + JSC::JSValue arg2 = callFrame->argument(1); + JSC::JSValue arg3 = callFrame->argument(2); + + // This method could be called in following forms: + // - toString() + // - toString(encoding) + // - toString(encoding, start) + // - toString(encoding, start, end) + // - toString(offset, length) + // - toString(offset, length, encoding) + if (argsCount == 0) + return jsBufferToString(vm, lexicalGlobalObject, castedThis, offset, length, encoding); + + if (arg1.isString()) { + encoding = parseEncoding(lexicalGlobalObject, scope, arg1); RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); - } - if (callFrame->argumentCount() == 1) - break; - } - // any - case 5: { - JSC::JSValue arg2 = callFrame->uncheckedArgument(1); - int32_t ioffset = arg2.toInt32(lexicalGlobalObject); + + if (!arg3.isUndefined()) { + // length is end + length = std::min(byteLength, static_cast<uint32_t>(arg3.toInt32(lexicalGlobalObject))); + } + + int32_t istart = arg2.toInt32(lexicalGlobalObject); + if (istart < 0) { + throwTypeError(lexicalGlobalObject, scope, "Start must be a positive integer"_s); + return JSC::JSValue::encode(jsUndefined()); + } + offset = static_cast<uint32_t>(istart); + length = (length > offset) ? (length - offset) : 0; + } else { + int32_t ioffset = arg1.toInt32(lexicalGlobalObject); if (ioffset < 0) { throwTypeError(lexicalGlobalObject, scope, "Offset must be a positive integer"_s); return JSC::JSValue::encode(jsUndefined()); } offset = static_cast<uint32_t>(ioffset); + length = (length > offset) ? (length - offset) : 0; - if (callFrame->argumentCount() == 2) - break; - } + if (!arg3.isUndefined()) { + encoding = parseEncoding(lexicalGlobalObject, scope, arg3); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined())); + } - default: { - length = std::min(byteLength, static_cast<uint32_t>(callFrame->argument(2).toInt32(lexicalGlobalObject))); - break; - } + if (!arg2.isUndefined()) + length = std::min(length, static_cast<uint32_t>(arg2.toInt32(lexicalGlobalObject))); } - length -= std::min(offset, length); - return jsBufferToString(vm, lexicalGlobalObject, castedThis, offset, length, encoding); } diff --git a/src/js/builtins/JSBufferPrototype.ts b/src/js/builtins/JSBufferPrototype.ts index 97b25b9b2..f5d6a7bfb 100644 --- a/src/js/builtins/JSBufferPrototype.ts +++ b/src/js/builtins/JSBufferPrototype.ts @@ -427,29 +427,29 @@ export function hexWrite(this: BufferExt, text, offset, length) { return this.write(text, offset, length, "hex"); } -export function utf8Slice(this: BufferExt, offset, length) { - return this.toString(offset, length, "utf8"); +export function utf8Slice(this: BufferExt, start, end) { + return this.toString("utf8", start, end); } -export function ucs2Slice(this: BufferExt, offset, length) { - return this.toString(offset, length, "ucs2"); +export function ucs2Slice(this: BufferExt, start, end) { + return this.toString("ucs2", start, end); } -export function utf16leSlice(this: BufferExt, offset, length) { - return this.toString(offset, length, "utf16le"); +export function utf16leSlice(this: BufferExt, start, end) { + return this.toString("utf16le", start, end); } -export function latin1Slice(this: BufferExt, offset, length) { - return this.toString(offset, length, "latin1"); +export function latin1Slice(this: BufferExt, start, end) { + return this.toString("latin1", start, end); } -export function asciiSlice(this: BufferExt, offset, length) { - return this.toString(offset, length, "ascii"); +export function asciiSlice(this: BufferExt, start, end) { + return this.toString("ascii", start, end); } -export function base64Slice(this: BufferExt, offset, length) { - return this.toString(offset, length, "base64"); +export function base64Slice(this: BufferExt, start, end) { + return this.toString("base64", start, end); } -export function base64urlSlice(this: BufferExt, offset, length) { - return this.toString(offset, length, "base64url"); +export function base64urlSlice(this: BufferExt, start, end) { + return this.toString("base64url", start, end); } -export function hexSlice(this: BufferExt, offset, length) { - return this.toString(offset, length, "hex"); +export function hexSlice(this: BufferExt, start, end) { + return this.toString("hex", start, end); } export function toJSON(this: BufferExt) { diff --git a/test/js/node/buffer.test.js b/test/js/node/buffer.test.js index 697774e0a..e0d8f5486 100644 --- a/test/js/node/buffer.test.js +++ b/test/js/node/buffer.test.js @@ -2353,6 +2353,85 @@ it("Buffer.byteLength()", () => { } }); +it("Buffer.toString(encoding, start, end)", () => { + const buf = Buffer.from("0123456789", "utf8"); + + expect(buf.toString()).toStrictEqual("0123456789"); + expect(buf.toString("utf8")).toStrictEqual("0123456789"); + expect(buf.toString("utf8", 3)).toStrictEqual("3456789"); + expect(buf.toString("utf8", 3, 4)).toStrictEqual("3"); + + expect(buf.toString("utf8", 3, 100)).toStrictEqual("3456789"); + expect(buf.toString("utf8", 3, 1)).toStrictEqual(""); + expect(buf.toString("utf8", 100, 200)).toStrictEqual(""); + expect(buf.toString("utf8", 100, 1)).toStrictEqual(""); +}); + +it("Buffer.toString(offset, length, encoding)", () => { + const buf = Buffer.from("0123456789", "utf8"); + + expect(buf.toString(3, 6, "utf8")).toStrictEqual("345678"); + expect(buf.toString(3, 100, "utf8")).toStrictEqual("3456789"); + expect(buf.toString(100, 200, "utf8")).toStrictEqual(""); + expect(buf.toString(100, 50, "utf8")).toStrictEqual(""); +}); + +it("Buffer.asciiSlice())", () => { + const buf = Buffer.from("0123456789", "ascii"); + + expect(buf.asciiSlice()).toStrictEqual("0123456789"); + expect(buf.asciiSlice(3)).toStrictEqual("3456789"); + expect(buf.asciiSlice(3, 4)).toStrictEqual("3"); +}); + +it("Buffer.latin1Slice()", () => { + const buf = Buffer.from("âéö", "latin1"); + + expect(buf.latin1Slice()).toStrictEqual("âéö"); + expect(buf.latin1Slice(1)).toStrictEqual("éö"); + expect(buf.latin1Slice(1, 2)).toStrictEqual("é"); +}); + +it("Buffer.utf8Slice()", () => { + const buf = Buffer.from("あいうえお", "utf8"); + + expect(buf.utf8Slice()).toStrictEqual("あいうえお"); + expect(buf.utf8Slice(3)).toStrictEqual("いうえお"); + expect(buf.utf8Slice(3, 6)).toStrictEqual("い"); +}); + +it("Buffer.hexSlice()", () => { + const buf = Buffer.from("0123456789", "utf8"); + + expect(buf.hexSlice()).toStrictEqual("30313233343536373839"); + expect(buf.hexSlice(3)).toStrictEqual("33343536373839"); + expect(buf.hexSlice(3, 4)).toStrictEqual("33"); +}); + +it("Buffer.ucs2Slice()", () => { + const buf = Buffer.from("あいうえお", "ucs2"); + + expect(buf.ucs2Slice()).toStrictEqual("あいうえお"); + expect(buf.ucs2Slice(2)).toStrictEqual("いうえお"); + expect(buf.ucs2Slice(2, 6)).toStrictEqual("いう"); +}); + +it("Buffer.base64Slice()", () => { + const buf = Buffer.from("0123456789", "utf8"); + + expect(buf.base64Slice()).toStrictEqual("MDEyMzQ1Njc4OQ=="); + expect(buf.base64Slice(3)).toStrictEqual("MzQ1Njc4OQ=="); + expect(buf.base64Slice(3, 4)).toStrictEqual("Mw=="); +}); + +it("Buffer.base64urlSlice()", () => { + const buf = Buffer.from("0123456789", "utf8"); + + expect(buf.base64urlSlice()).toStrictEqual("MDEyMzQ1Njc4OQ"); + expect(buf.base64urlSlice(3)).toStrictEqual("MzQ1Njc4OQ"); + expect(buf.base64urlSlice(3, 4)).toStrictEqual("Mw"); +}); + it("should not crash on invalid UTF-8 byte sequence", () => { const buf = Buffer.from([0xc0, 0xfd]); expect(buf.length).toBe(2); |