Skip to content

Commit aace11c

Browse files
committed
feat: Uint8Array<SharedArrayBuffer> is accepted in utf16toString
1 parent 2184097 commit aace11c

File tree

3 files changed

+78
-18
lines changed

3 files changed

+78
-18
lines changed

tests/utf16.test.js

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ import { randomValues } from '@exodus/crypto/randomBytes'
55
import * as js from '../fallback/utf16.js'
66
import { describe, test } from 'node:test'
77

8+
const SharedArrayBuffer = globalThis.SharedArrayBuffer ?? ArrayBuffer
9+
const toShared = (u16) => {
10+
const res = new Uint16Array(new SharedArrayBuffer(u16.byteLength))
11+
res.set(u16)
12+
return res
13+
}
14+
815
const orphans = [
916
{ invalid: [0x61, 0x62, 0xd8_00, 0x77, 0x78], replaced: [0x61, 0x62, 0xff_fd, 0x77, 0x78] },
1017
{ invalid: [0xd8_00], replaced: [0xff_fd] },
@@ -33,7 +40,7 @@ const pool = [
3340
new Uint16Array(seed3.buffer, seed3.byteOffset, seed3.byteLength / 2),
3441
]
3542

36-
for (let i = 0; i < 500; i++) {
43+
for (let i = 0; i < 300; i++) {
3744
const offset = Math.floor((Math.random() * seed.length) / 2) * 2
3845
const u8 = seed.subarray(offset).map((x, j) => x + i * j)
3946
pool.push(new Uint16Array(u8.buffer, u8.byteOffset, u8.byteLength / 2))
@@ -66,7 +73,13 @@ describe('utf16toString', () => {
6673
})
6774

6875
test('orphans throw in utf16toString', (t) => {
69-
for (const utf16toString of [utf16.utf16toString, lib.utf16toString, js.decode]) {
76+
for (const utf16toString of [
77+
utf16.utf16toString,
78+
lib.utf16toString,
79+
(x) => utf16.utf16toString(toShared(x)),
80+
(x) => lib.utf16toString(toShared(x)),
81+
js.decode,
82+
]) {
7083
for (const { invalid } of orphans) {
7184
t.assert.throws(() => utf16toString(Uint16Array.of(...invalid)))
7285

@@ -88,6 +101,8 @@ describe('utf16toString', () => {
88101
for (const utf16toStringLoose of [
89102
utf16.utf16toStringLoose,
90103
lib.utf16toStringLoose,
104+
(x) => utf16.utf16toStringLoose(toShared(x)),
105+
(x) => lib.utf16toStringLoose(toShared(x)),
91106
(u16) => js.decode(u16, true),
92107
]) {
93108
const res = utf16toStringLoose(Uint16Array.of(...invalid))
@@ -172,7 +187,10 @@ describe('random data', () => {
172187
const decoderBE = nativeIsOk ? new TextDecoder('utf-16be', { ignoreBOM }) : null // polyfilled might be wrong
173188
for (const u16 of pool) {
174189
const str = utf16.utf16toStringLoose(u16)
190+
const s16 = toShared(u16)
175191
t.assert.strictEqual(str, lib.utf16toStringLoose(u16))
192+
t.assert.strictEqual(str, utf16.utf16toStringLoose(s16))
193+
t.assert.strictEqual(str, lib.utf16toStringLoose(s16))
176194
t.assert.strictEqual(str, js.decode(u16, true))
177195
const u8 = new Uint8Array(u16.buffer, u16.byteOffset, u16.byteLength)
178196
const strLE = utf16.utf16toStringLoose(u8, 'uint8-le')
@@ -192,9 +210,14 @@ describe('random data', () => {
192210
const decoderBE = nativeIsOk ? new TextDecoder('utf-16be', { ignoreBOM }) : null
193211
for (const u16 of poolAscii) {
194212
const str = utf16.utf16toString(u16)
213+
const s16 = toShared(u16)
195214
t.assert.strictEqual(str, utf16.utf16toStringLoose(u16))
196215
t.assert.strictEqual(str, lib.utf16toString(u16))
197216
t.assert.strictEqual(str, lib.utf16toStringLoose(u16))
217+
t.assert.strictEqual(str, utf16.utf16toString(s16))
218+
t.assert.strictEqual(str, utf16.utf16toStringLoose(s16))
219+
t.assert.strictEqual(str, lib.utf16toString(s16))
220+
t.assert.strictEqual(str, lib.utf16toStringLoose(s16))
198221
t.assert.strictEqual(str, js.decode(u16, false))
199222
t.assert.strictEqual(str, js.decode(u16, true))
200223
const u8 = new Uint8Array(u16.buffer, u16.byteOffset, u16.byteLength)
@@ -220,7 +243,9 @@ describe('random data', () => {
220243
t.assert.strictEqual(strings.length, pool.length)
221244
for (let i = 0; i < pool.length; i++) {
222245
const u16 = pool[i]
246+
const s16 = toShared(u16)
223247
const u8 = new Uint8Array(u16.buffer, u16.byteOffset, u16.byteLength)
248+
const s8 = new Uint8Array(s16.buffer, s16.byteOffset, s16.byteLength)
224249
let str
225250
try {
226251
str = utf16.utf16toString(u16)
@@ -233,9 +258,17 @@ describe('random data', () => {
233258
t.assert.throws(() => js.decode(u16, false))
234259
t.assert.throws(() => utf16.utf16toString(u8, isLE ? 'uint8-le' : 'uint8-be'))
235260
t.assert.throws(() => lib.utf16toString(u8, isLE ? 'uint8-le' : 'uint8-be'))
261+
262+
t.assert.throws(() => utf16.utf16toString(s16))
263+
t.assert.throws(() => lib.utf16toString(s16))
264+
t.assert.throws(() => js.decode(s16, false))
265+
t.assert.throws(() => utf16.utf16toString(s8, isLE ? 'uint8-le' : 'uint8-be'))
266+
t.assert.throws(() => lib.utf16toString(s8, isLE ? 'uint8-le' : 'uint8-be'))
267+
236268
if (nativeIsOk) t.assert.throws(() => (isLE ? decoderLE : decoderBE).decode(u8))
237269
} else {
238270
t.assert.strictEqual(str, strings[i])
271+
239272
t.assert.strictEqual(str, utf16.utf16toStringLoose(u16))
240273
t.assert.strictEqual(str, lib.utf16toString(u16))
241274
t.assert.strictEqual(str, lib.utf16toStringLoose(u16))
@@ -245,6 +278,18 @@ describe('random data', () => {
245278
t.assert.strictEqual(str, utf16.utf16toStringLoose(u8, isLE ? 'uint8-le' : 'uint8-be'))
246279
t.assert.strictEqual(str, lib.utf16toString(u8, isLE ? 'uint8-le' : 'uint8-be'))
247280
t.assert.strictEqual(str, lib.utf16toStringLoose(u8, isLE ? 'uint8-le' : 'uint8-be'))
281+
282+
t.assert.strictEqual(str, utf16.utf16toString(s16))
283+
t.assert.strictEqual(str, utf16.utf16toStringLoose(s16))
284+
t.assert.strictEqual(str, lib.utf16toString(s16))
285+
t.assert.strictEqual(str, lib.utf16toStringLoose(s16))
286+
t.assert.strictEqual(str, js.decode(s16, false))
287+
t.assert.strictEqual(str, js.decode(s16, true))
288+
t.assert.strictEqual(str, utf16.utf16toString(s8, isLE ? 'uint8-le' : 'uint8-be'))
289+
t.assert.strictEqual(str, utf16.utf16toStringLoose(s8, isLE ? 'uint8-le' : 'uint8-be'))
290+
t.assert.strictEqual(str, lib.utf16toString(s8, isLE ? 'uint8-le' : 'uint8-be'))
291+
t.assert.strictEqual(str, lib.utf16toStringLoose(s8, isLE ? 'uint8-le' : 'uint8-be'))
292+
248293
if (nativeIsOk) t.assert.strictEqual(str, (isLE ? decoderLE : decoderBE).decode(u8))
249294
if (Buffer && isLE) t.assert.strictEqual(str, Buffer.from(u8).toString('utf-16le'))
250295
}
@@ -298,7 +343,10 @@ describe('random data', () => {
298343
for (let i = 0; i < pool.length; i++) {
299344
const str = strings[i]
300345
const u16 = restored[i]
346+
const s16 = toShared(u16)
301347
const u8 = new Uint8Array(u16.buffer, u16.byteOffset, u16.byteLength)
348+
const s8 = new Uint8Array(s16.buffer, s16.byteOffset, s16.byteLength)
349+
302350
t.assert.strictEqual(str, utf16.utf16toString(u16))
303351
t.assert.strictEqual(str, utf16.utf16toStringLoose(u16))
304352
t.assert.strictEqual(str, lib.utf16toString(u16))
@@ -309,6 +357,18 @@ describe('random data', () => {
309357
t.assert.strictEqual(str, utf16.utf16toStringLoose(u8, isLE ? 'uint8-le' : 'uint8-be'))
310358
t.assert.strictEqual(str, lib.utf16toString(u8, isLE ? 'uint8-le' : 'uint8-be'))
311359
t.assert.strictEqual(str, lib.utf16toStringLoose(u8, isLE ? 'uint8-le' : 'uint8-be'))
360+
361+
t.assert.strictEqual(str, utf16.utf16toString(s16))
362+
t.assert.strictEqual(str, utf16.utf16toStringLoose(s16))
363+
t.assert.strictEqual(str, lib.utf16toString(s16))
364+
t.assert.strictEqual(str, lib.utf16toStringLoose(s16))
365+
t.assert.strictEqual(str, js.decode(s16, false))
366+
t.assert.strictEqual(str, js.decode(s16, true))
367+
t.assert.strictEqual(str, utf16.utf16toString(s8, isLE ? 'uint8-le' : 'uint8-be'))
368+
t.assert.strictEqual(str, utf16.utf16toStringLoose(s8, isLE ? 'uint8-le' : 'uint8-be'))
369+
t.assert.strictEqual(str, lib.utf16toString(s8, isLE ? 'uint8-le' : 'uint8-be'))
370+
t.assert.strictEqual(str, lib.utf16toStringLoose(s8, isLE ? 'uint8-le' : 'uint8-be'))
371+
312372
if (nativeIsOk) t.assert.strictEqual(str, (isLE ? decoderLE : decoderBE).decode(u8))
313373
if (Buffer && isLE) t.assert.strictEqual(str, Buffer.from(u8).toString('utf-16le'))
314374
}

utf16.d.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ export function utf16fromStringLoose(string: string, format?: Utf16Format): Uint
6666
* @param format - Input format (default: 'uint16')
6767
* @returns The decoded string
6868
*/
69-
export function utf16toString(arr: Uint16ArrayBuffer, format?: 'uint16'): string;
70-
export function utf16toString(arr: Uint8ArrayBuffer, format: 'uint8-le'): string;
71-
export function utf16toString(arr: Uint8ArrayBuffer, format: 'uint8-be'): string;
72-
export function utf16toString(arr: Uint16ArrayBuffer | Uint8ArrayBuffer, format?: Utf16Format): string;
69+
export function utf16toString(arr: Uint16Array, format?: 'uint16'): string;
70+
export function utf16toString(arr: Uint8Array, format: 'uint8-le'): string;
71+
export function utf16toString(arr: Uint8Array, format: 'uint8-be'): string;
72+
export function utf16toString(arr: Uint16Array | Uint8Array, format?: Utf16Format): string;
7373

7474
/**
7575
* Decode UTF-16 bytes to a string (loose mode)
@@ -86,7 +86,7 @@ export function utf16toString(arr: Uint16ArrayBuffer | Uint8ArrayBuffer, format?
8686
* @param format - Input format (default: 'uint16')
8787
* @returns The decoded string
8888
*/
89-
export function utf16toStringLoose(arr: Uint16ArrayBuffer, format?: 'uint16'): string;
90-
export function utf16toStringLoose(arr: Uint8ArrayBuffer, format: 'uint8-le'): string;
91-
export function utf16toStringLoose(arr: Uint8ArrayBuffer, format: 'uint8-be'): string;
92-
export function utf16toStringLoose(arr: Uint16ArrayBuffer | Uint8ArrayBuffer, format?: Utf16Format): string;
89+
export function utf16toStringLoose(arr: Uint16Array, format?: 'uint16'): string;
90+
export function utf16toStringLoose(arr: Uint8Array, format: 'uint8-le'): string;
91+
export function utf16toStringLoose(arr: Uint8Array, format: 'uint8-be'): string;
92+
export function utf16toStringLoose(arr: Uint16Array | Uint8Array, format?: Utf16Format): string;

utf32.d.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ export function utf32fromStringLoose(string: string, format?: Utf32Format): Uint
6464
* @param format - Input format (default: 'uint32')
6565
* @returns The decoded string
6666
*/
67-
export function utf32toString(arr: Uint32ArrayBuffer, format?: 'uint32'): string;
68-
export function utf32toString(arr: Uint8ArrayBuffer, format: 'uint8-le'): string;
69-
export function utf32toString(arr: Uint8ArrayBuffer, format: 'uint8-be'): string;
70-
export function utf32toString(arr: Uint32ArrayBuffer | Uint8ArrayBuffer, format?: Utf32Format): string;
67+
export function utf32toString(arr: Uint32Array, format?: 'uint32'): string;
68+
export function utf32toString(arr: Uint8Array, format: 'uint8-le'): string;
69+
export function utf32toString(arr: Uint8Array, format: 'uint8-be'): string;
70+
export function utf32toString(arr: Uint32Array | Uint8Array, format?: Utf32Format): string;
7171

7272
/**
7373
* Decode UTF-32 bytes to a string (loose mode)
@@ -83,7 +83,7 @@ export function utf32toString(arr: Uint32ArrayBuffer | Uint8ArrayBuffer, format?
8383
* @param format - Input format (default: 'uint32')
8484
* @returns The decoded string
8585
*/
86-
export function utf32toStringLoose(arr: Uint32ArrayBuffer, format?: 'uint32'): string;
87-
export function utf32toStringLoose(arr: Uint8ArrayBuffer, format: 'uint8-le'): string;
88-
export function utf32toStringLoose(arr: Uint8ArrayBuffer, format: 'uint8-be'): string;
89-
export function utf32toStringLoose(arr: Uint32ArrayBuffer | Uint8ArrayBuffer, format?: Utf32Format): string;
86+
export function utf32toStringLoose(arr: Uint32Array, format?: 'uint32'): string;
87+
export function utf32toStringLoose(arr: Uint8Array, format: 'uint8-le'): string;
88+
export function utf32toStringLoose(arr: Uint8Array, format: 'uint8-be'): string;
89+
export function utf32toStringLoose(arr: Uint32Array | Uint8Array, format?: Utf32Format): string;

0 commit comments

Comments
 (0)