From 8b66532da6cd789e15c250e7d3fa317f93a115b1 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Sat, 9 May 2026 11:39:56 -0700 Subject: [PATCH] buffer utf8 fixes --- src/modules/buffer.c | 31 +++++++++++++++++++---- tests/test_buffer_indexof.cjs | 2 ++ tests/test_buffer_species_arraybuffer.cjs | 2 ++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/modules/buffer.c b/src/modules/buffer.c index 414d548..fe9b4bc 100644 --- a/src/modules/buffer.c +++ b/src/modules/buffer.c @@ -2940,14 +2940,19 @@ static ant_value_t js_buffer_toString(ant_t *js, ant_value_t *args, int nargs) { return result; } else if (encoding == ENC_UCS2) { size_t char_count = len / 2; - char *str = malloc(char_count + 1); + char *str = malloc(char_count * 3 + 1); if (!str) return js_mkerr(js, "Failed to allocate string"); - for (size_t i = 0; i < char_count; i++) str[i] = (char)data[i * 2]; - str[char_count] = '\0'; + size_t out_len = 0; + for (size_t i = 0; i < char_count; i++) { + uint32_t unit = (uint32_t)data[i * 2] | ((uint32_t)data[i * 2 + 1] << 8); + out_len += (size_t)utf8_encode(unit, str + out_len); + } - ant_value_t result = js_mkstr(js, str, char_count); + str[out_len] = '\0'; + ant_value_t result = js_mkstr(js, str, out_len); free(str); + return result; } else { size_t out_cap = len * 3 + 1; @@ -2989,7 +2994,23 @@ static ant_value_t js_buffer_utf8Slice(ant_t *js, ant_value_t *args, int nargs) if (end > ta_data->byte_length) end = ta_data->byte_length; if (end < start) end = start; - return js_mkstr(js, (char *)ta_data->buffer->data + ta_data->byte_offset + start, end - start); + uint8_t *data = ta_data->buffer->data + ta_data->byte_offset + start; + size_t len = end - start; size_t out_cap = len * 3 + 1; + + char *out = malloc(out_cap); + if (!out) return js_mkerr(js, "Failed to allocate string"); + + utf8_dec_t dec = { .bom_seen = true, .ignore_bom = true }; + utf8proc_ssize_t out_len = utf8_whatwg_decode(&dec, data, len, out, false, false); + if (out_len < 0) { + free(out); + return js_mkerr(js, "Failed to decode buffer as UTF-8"); + } + + ant_value_t result = js_mkstr(js, out, (size_t)out_len); + free(out); + + return result; } // Buffer.prototype.toBase64() diff --git a/tests/test_buffer_indexof.cjs b/tests/test_buffer_indexof.cjs index 86358bc..b3e1a3b 100644 --- a/tests/test_buffer_indexof.cjs +++ b/tests/test_buffer_indexof.cjs @@ -19,6 +19,8 @@ assert.strictEqual(Buffer.from('aabbcc', 'hex').indexOf('b', 0, 'hex'), 0); assert.strictEqual(Buffer.from('a\0b\0').indexOf('b', 0, 'ucs2'), 2); assert.strictEqual(Buffer.from([0xe9, 0]).indexOf('é', 0, 'ucs2'), 0); assert.deepStrictEqual([...Buffer.from('é', 'ucs2')], [0xe9, 0]); +assert.strictEqual(Buffer.from([0xe9, 0]).toString('ucs2'), 'é'); +assert.strictEqual(Buffer.from('ĀΩ', 'ucs2').toString('ucs2'), 'ĀΩ'); assert.strictEqual(Buffer.from([0x81, 0x7e]).readUInt16BE(0), 33150); const shortFrameHeader = Buffer.alloc(2); diff --git a/tests/test_buffer_species_arraybuffer.cjs b/tests/test_buffer_species_arraybuffer.cjs index 22ec98f..ec03a00 100644 --- a/tests/test_buffer_species_arraybuffer.cjs +++ b/tests/test_buffer_species_arraybuffer.cjs @@ -16,6 +16,8 @@ assert.strictEqual(shared.toString(), 'X-Test'); source[17] = 'Y'.charCodeAt(0); assert.strictEqual(shared.toString(), 'Y-Test'); assert.strictEqual(source.utf8Slice(13, 15), 'OK'); +assert.strictEqual(Buffer.from('aéz').utf8Slice(1, 3), 'é'); +assert.strictEqual(Buffer.from([0x61, 0xc3, 0x28, 0x62]).utf8Slice(0, 4), 'a�(b'); assert(Buffer.isBuffer(Buffer.allocUnsafeSlow(4))); console.log('buffer:species-arraybuffer:ok'); -- 2.51.2