@exodus/bytes 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -4
- package/base58check.js +4 -54
- package/base58check.node.js +14 -0
- package/encoding-lite.js +1 -0
- package/encoding.js +1 -0
- package/fallback/base58check.js +53 -0
- package/fallback/encoding.js +13 -0
- package/package.json +7 -2
- package/utf16.js +3 -2
- package/utf16.node.js +9 -7
- package/utf8.node.js +16 -3
package/README.md
CHANGED
|
@@ -41,6 +41,7 @@ Spec compliant, passing WPT and covered with extra tests.
|
|
|
41
41
|
Moreover, tests for this library uncovered [bugs in all major implementations](https://docs.google.com/spreadsheets/d/1pdEefRG6r9fZy61WHGz0TKSt8cO4ISWqlpBN5KntIvQ/edit).
|
|
42
42
|
|
|
43
43
|
[Faster than Node.js native implementation on Node.js](https://github.com/nodejs/node/issues/61041#issuecomment-3649242024).
|
|
44
|
+
Runs (and passes WPT) on Node.js built without ICU.
|
|
44
45
|
|
|
45
46
|
### Caveat: `TextDecoder` / `TextEncoder` APIs are lossy by default per spec
|
|
46
47
|
|
|
@@ -160,6 +161,8 @@ Same as `windows1252toString = createSinglebyteDecoder('windows-1252')`.
|
|
|
160
161
|
|
|
161
162
|
### `@exodus/bytes/base58check.js`
|
|
162
163
|
|
|
164
|
+
On non-Node.js, requires peer dependency [@exodus/crypto](https://www.npmjs.com/package/@exodus/crypto) to be installed.
|
|
165
|
+
|
|
163
166
|
##### `async toBase58check(arr)`
|
|
164
167
|
##### `toBase58checkSync(arr)`
|
|
165
168
|
##### `async fromBase58check(str, format = 'uint8')`
|
|
@@ -184,7 +187,7 @@ some [hooks](https://encoding.spec.whatwg.org/#specification-hooks) (see below).
|
|
|
184
187
|
import { TextDecoder, TextDecoder } from '@exodus/bytes/encoding.js'
|
|
185
188
|
|
|
186
189
|
// Hooks for standards
|
|
187
|
-
import { getBOMEncoding, legacyHookDecode, normalizeEncoding } from '@exodus/bytes/encoding.js'
|
|
190
|
+
import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding.js'
|
|
188
191
|
```
|
|
189
192
|
|
|
190
193
|
#### `new TextDecoder(label = 'utf-8', { fatal = false, ignoreBOM = false })`
|
|
@@ -195,10 +198,19 @@ import { getBOMEncoding, legacyHookDecode, normalizeEncoding } from '@exodus/byt
|
|
|
195
198
|
|
|
196
199
|
[TextEncoder](https://encoding.spec.whatwg.org/#interface-textdecoder) implementation/polyfill.
|
|
197
200
|
|
|
198
|
-
#### `
|
|
201
|
+
#### `labelToName(label)`
|
|
199
202
|
|
|
200
203
|
Implements [get an encoding from a string `label`](https://encoding.spec.whatwg.org/#concept-encoding-get).
|
|
201
204
|
|
|
205
|
+
Converts an encoding [label](https://encoding.spec.whatwg.org/#names-and-labels) to its name,
|
|
206
|
+
as a case-sensitive string.
|
|
207
|
+
|
|
208
|
+
If an encoding with that label does not exist, returns `null`.
|
|
209
|
+
|
|
210
|
+
All encoding names are also valid labels for corresponding encodings.
|
|
211
|
+
|
|
212
|
+
#### `normalizeEncoding(label)`
|
|
213
|
+
|
|
202
214
|
Converts an encoding [label](https://encoding.spec.whatwg.org/#names-and-labels) to its name,
|
|
203
215
|
as an ASCII-lowercased string.
|
|
204
216
|
|
|
@@ -210,6 +222,11 @@ except that it:
|
|
|
210
222
|
[labels](https://encoding.spec.whatwg.org/#ref-for-replacement%E2%91%A1)
|
|
211
223
|
2. Does not throw for invalid labels and instead returns `null`
|
|
212
224
|
|
|
225
|
+
It is identical to:
|
|
226
|
+
```js
|
|
227
|
+
labelToName(label)?.toLowerCase() ?? null
|
|
228
|
+
```
|
|
229
|
+
|
|
213
230
|
All encoding names are also valid labels for corresponding encodings.
|
|
214
231
|
|
|
215
232
|
#### `getBOMEncoding(input)`
|
|
@@ -251,7 +268,7 @@ new TextDecoder(getBOMEncoding(input) ?? fallbackEncoding).decode(input)
|
|
|
251
268
|
import { TextDecoder, TextDecoder } from '@exodus/bytes/encoding-lite.js'
|
|
252
269
|
|
|
253
270
|
// Hooks for standards
|
|
254
|
-
import { getBOMEncoding, legacyHookDecode, normalizeEncoding } from '@exodus/bytes/encoding-lite.js'
|
|
271
|
+
import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding-lite.js'
|
|
255
272
|
```
|
|
256
273
|
|
|
257
274
|
The exact same exports as `@exodus/bytes/encoding.js` are also exported as
|
|
@@ -263,7 +280,7 @@ and their [labels](https://encoding.spec.whatwg.org/#names-and-labels) when used
|
|
|
263
280
|
|
|
264
281
|
Legacy single-byte encodingds are loaded by default in both cases.
|
|
265
282
|
|
|
266
|
-
`TextEncoder` and hooks for standards (including `normalizeEncoding`) do not have any behavior
|
|
283
|
+
`TextEncoder` and hooks for standards (including `labelToName` / `normalizeEncoding`) do not have any behavior
|
|
267
284
|
differences in the lite version and support full range if inputs.
|
|
268
285
|
|
|
269
286
|
To avoid inconsistencies, the exported classes and methods are exactly the same objects.
|
|
@@ -274,6 +291,7 @@ To avoid inconsistencies, the exported classes and methods are exactly the same
|
|
|
274
291
|
TextDecoder: [class TextDecoder],
|
|
275
292
|
TextEncoder: [class TextEncoder],
|
|
276
293
|
getBOMEncoding: [Function: getBOMEncoding],
|
|
294
|
+
labelToName: [Function: labelToName],
|
|
277
295
|
legacyHookDecode: [Function: legacyHookDecode],
|
|
278
296
|
normalizeEncoding: [Function: normalizeEncoding]
|
|
279
297
|
}
|
|
@@ -286,6 +304,7 @@ Error: Legacy multi-byte encodings are disabled in /encoding-lite.js, use /encod
|
|
|
286
304
|
TextDecoder: [class TextDecoder],
|
|
287
305
|
TextEncoder: [class TextEncoder],
|
|
288
306
|
getBOMEncoding: [Function: getBOMEncoding],
|
|
307
|
+
labelToName: [Function: labelToName],
|
|
289
308
|
legacyHookDecode: [Function: legacyHookDecode],
|
|
290
309
|
normalizeEncoding: [Function: normalizeEncoding]
|
|
291
310
|
}
|
package/base58check.js
CHANGED
|
@@ -1,63 +1,12 @@
|
|
|
1
|
-
import { typedView } from './array.js'
|
|
2
|
-
import { assertUint8 } from './assert.js'
|
|
3
|
-
import { toBase58, fromBase58 } from './base58.js'
|
|
4
1
|
import { hashSync } from '@exodus/crypto/hash' // eslint-disable-line @exodus/import/no-deprecated
|
|
2
|
+
import { makeBase58check } from './fallback/base58check.js'
|
|
5
3
|
|
|
6
4
|
// Note: while API is async, we use hashSync for now until we improve webcrypto perf for hash256
|
|
7
5
|
// Inputs to base58 are typically very small, and that makes a difference
|
|
8
6
|
|
|
9
|
-
const E_CHECKSUM = 'Invalid checksum'
|
|
10
|
-
|
|
11
|
-
// checksum length is 4, i.e. only the first 4 bytes of the hash are used
|
|
12
|
-
|
|
13
|
-
function encodeWithChecksum(arr, checksum) {
|
|
14
|
-
// arr type in already validated in input
|
|
15
|
-
const res = new Uint8Array(arr.length + 4)
|
|
16
|
-
res.set(arr, 0)
|
|
17
|
-
res.set(checksum.subarray(0, 4), arr.length)
|
|
18
|
-
return toBase58(res)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function decodeWithChecksum(str) {
|
|
22
|
-
const arr = fromBase58(str) // checks input
|
|
23
|
-
const payloadSize = arr.length - 4
|
|
24
|
-
if (payloadSize < 0) throw new Error(E_CHECKSUM)
|
|
25
|
-
return [arr.subarray(0, payloadSize), arr.subarray(payloadSize)]
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function assertChecksum(c, r) {
|
|
29
|
-
if ((c[0] ^ r[0]) | (c[1] ^ r[1]) | (c[2] ^ r[2]) | (c[3] ^ r[3])) throw new Error(E_CHECKSUM)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const makeBase58check = (hashAlgo, hashAlgoSync) => {
|
|
33
|
-
const apis = {
|
|
34
|
-
async encode(arr) {
|
|
35
|
-
assertUint8(arr)
|
|
36
|
-
return encodeWithChecksum(arr, await hashAlgo(arr))
|
|
37
|
-
},
|
|
38
|
-
async decode(str, format = 'uint8') {
|
|
39
|
-
const [payload, checksum] = decodeWithChecksum(str)
|
|
40
|
-
assertChecksum(checksum, await hashAlgo(payload))
|
|
41
|
-
return typedView(payload, format)
|
|
42
|
-
},
|
|
43
|
-
}
|
|
44
|
-
if (!hashAlgoSync) return apis
|
|
45
|
-
return {
|
|
46
|
-
...apis,
|
|
47
|
-
encodeSync(arr) {
|
|
48
|
-
assertUint8(arr)
|
|
49
|
-
return encodeWithChecksum(arr, hashAlgoSync(arr))
|
|
50
|
-
},
|
|
51
|
-
decodeSync(str, format = 'uint8') {
|
|
52
|
-
const [payload, checksum] = decodeWithChecksum(str)
|
|
53
|
-
assertChecksum(checksum, hashAlgoSync(payload))
|
|
54
|
-
return typedView(payload, format)
|
|
55
|
-
},
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
7
|
// eslint-disable-next-line @exodus/import/no-deprecated
|
|
60
|
-
const
|
|
8
|
+
const sha256 = (x) => hashSync('sha256', x, 'uint8')
|
|
9
|
+
const hash256sync = (x) => sha256(sha256(x))
|
|
61
10
|
const hash256 = hash256sync // See note at the top
|
|
62
11
|
const {
|
|
63
12
|
encode: toBase58check,
|
|
@@ -66,4 +15,5 @@ const {
|
|
|
66
15
|
decodeSync: fromBase58checkSync,
|
|
67
16
|
} = makeBase58check(hash256, hash256sync)
|
|
68
17
|
|
|
18
|
+
export { makeBase58check } from './fallback/base58check.js'
|
|
69
19
|
export { toBase58check, fromBase58check, toBase58checkSync, fromBase58checkSync }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { hash } from 'node:crypto'
|
|
2
|
+
import { makeBase58check } from './fallback/base58check.js'
|
|
3
|
+
|
|
4
|
+
const sha256 = (x) => hash('sha256', x, 'buffer')
|
|
5
|
+
const hash256 = (x) => sha256(sha256(x))
|
|
6
|
+
const {
|
|
7
|
+
encode: toBase58check,
|
|
8
|
+
decode: fromBase58check,
|
|
9
|
+
encodeSync: toBase58checkSync,
|
|
10
|
+
decodeSync: fromBase58checkSync,
|
|
11
|
+
} = makeBase58check(hash256, hash256)
|
|
12
|
+
|
|
13
|
+
export { makeBase58check } from './fallback/base58check.js'
|
|
14
|
+
export { toBase58check, fromBase58check, toBase58checkSync, fromBase58checkSync }
|
package/encoding-lite.js
CHANGED
package/encoding.js
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { typedView } from '@exodus/bytes/array.js'
|
|
2
|
+
import { toBase58, fromBase58 } from '@exodus/bytes/base58.js'
|
|
3
|
+
import { assertUint8 } from '../assert.js'
|
|
4
|
+
|
|
5
|
+
const E_CHECKSUM = 'Invalid checksum'
|
|
6
|
+
|
|
7
|
+
// checksum length is 4, i.e. only the first 4 bytes of the hash are used
|
|
8
|
+
|
|
9
|
+
function encodeWithChecksum(arr, checksum) {
|
|
10
|
+
// arr type in already validated in input
|
|
11
|
+
const res = new Uint8Array(arr.length + 4)
|
|
12
|
+
res.set(arr, 0)
|
|
13
|
+
res.set(checksum.subarray(0, 4), arr.length)
|
|
14
|
+
return toBase58(res)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function decodeWithChecksum(str) {
|
|
18
|
+
const arr = fromBase58(str) // checks input
|
|
19
|
+
const payloadSize = arr.length - 4
|
|
20
|
+
if (payloadSize < 0) throw new Error(E_CHECKSUM)
|
|
21
|
+
return [arr.subarray(0, payloadSize), arr.subarray(payloadSize)]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function assertChecksum(c, r) {
|
|
25
|
+
if ((c[0] ^ r[0]) | (c[1] ^ r[1]) | (c[2] ^ r[2]) | (c[3] ^ r[3])) throw new Error(E_CHECKSUM)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const makeBase58check = (hashAlgo, hashAlgoSync) => {
|
|
29
|
+
const apis = {
|
|
30
|
+
async encode(arr) {
|
|
31
|
+
assertUint8(arr)
|
|
32
|
+
return encodeWithChecksum(arr, await hashAlgo(arr))
|
|
33
|
+
},
|
|
34
|
+
async decode(str, format = 'uint8') {
|
|
35
|
+
const [payload, checksum] = decodeWithChecksum(str)
|
|
36
|
+
assertChecksum(checksum, await hashAlgo(payload))
|
|
37
|
+
return typedView(payload, format)
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
if (!hashAlgoSync) return apis
|
|
41
|
+
return {
|
|
42
|
+
...apis,
|
|
43
|
+
encodeSync(arr) {
|
|
44
|
+
assertUint8(arr)
|
|
45
|
+
return encodeWithChecksum(arr, hashAlgoSync(arr))
|
|
46
|
+
},
|
|
47
|
+
decodeSync(str, format = 'uint8') {
|
|
48
|
+
const [payload, checksum] = decodeWithChecksum(str)
|
|
49
|
+
assertChecksum(checksum, hashAlgoSync(payload))
|
|
50
|
+
return typedView(payload, format)
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
}
|
package/fallback/encoding.js
CHANGED
|
@@ -288,3 +288,16 @@ export function legacyHookDecode(input, fallbackEncoding = 'utf-8') {
|
|
|
288
288
|
|
|
289
289
|
return createSinglebyteDecoder(enc, true)(u8)
|
|
290
290
|
}
|
|
291
|
+
|
|
292
|
+
const uppercasePrefixes = new Set(['utf', 'iso', 'koi', 'euc', 'ibm', 'gbk'])
|
|
293
|
+
|
|
294
|
+
// Unlike normalizeEncoding, case-sensitive
|
|
295
|
+
// https://encoding.spec.whatwg.org/#names-and-labels
|
|
296
|
+
export function labelToName(label) {
|
|
297
|
+
const enc = normalizeEncoding(label)
|
|
298
|
+
if (!enc) return enc
|
|
299
|
+
if (uppercasePrefixes.has(enc.slice(0, 3))) return enc.toUpperCase()
|
|
300
|
+
if (enc === 'big5') return 'Big5'
|
|
301
|
+
if (enc === 'shift_jis') return 'Shift_JIS'
|
|
302
|
+
return enc
|
|
303
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/bytes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Various operations on Uint8Array data",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"lint": "eslint .",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"files": [
|
|
46
46
|
"/fallback/_utils.js",
|
|
47
47
|
"/fallback/base32.js",
|
|
48
|
+
"/fallback/base58check.js",
|
|
48
49
|
"/fallback/base64.js",
|
|
49
50
|
"/fallback/encoding.js",
|
|
50
51
|
"/fallback/encoding.labels.js",
|
|
@@ -65,6 +66,7 @@
|
|
|
65
66
|
"/base32.js",
|
|
66
67
|
"/base58.js",
|
|
67
68
|
"/base58check.js",
|
|
69
|
+
"/base58check.node.js",
|
|
68
70
|
"/base64.js",
|
|
69
71
|
"/base64.d.ts",
|
|
70
72
|
"/bech32.js",
|
|
@@ -92,7 +94,10 @@
|
|
|
92
94
|
},
|
|
93
95
|
"./base32.js": "./base32.js",
|
|
94
96
|
"./base58.js": "./base58.js",
|
|
95
|
-
"./base58check.js":
|
|
97
|
+
"./base58check.js": {
|
|
98
|
+
"node": "./base58check.node.js",
|
|
99
|
+
"default": "./base58check.js"
|
|
100
|
+
},
|
|
96
101
|
"./base64.js": {
|
|
97
102
|
"types": "./base64.d.ts",
|
|
98
103
|
"default": "./base64.js"
|
package/utf16.js
CHANGED
|
@@ -9,7 +9,7 @@ const decoderFatalBE = canDecoders ? new TextDecoder('utf-16be', { ignoreBOM, fa
|
|
|
9
9
|
const decoderLooseBE = canDecoders ? new TextDecoder('utf-16be', { ignoreBOM }) : null
|
|
10
10
|
const decoderFatal16 = isLE ? decoderFatalLE : decoderFatalBE
|
|
11
11
|
const decoderLoose16 = isLE ? decoderLooseLE : decoderFatalBE
|
|
12
|
-
const { isWellFormed } = String.prototype
|
|
12
|
+
const { isWellFormed, toWellFormed } = String.prototype
|
|
13
13
|
|
|
14
14
|
const { E_STRICT, E_STRICT_UNICODE } = js
|
|
15
15
|
|
|
@@ -61,8 +61,9 @@ function decode(input, loose = false, format = 'uint16') {
|
|
|
61
61
|
throw new TypeError('Unknown format')
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const str = js.decode(u16, loose, !loose && isWellFormed)
|
|
64
|
+
const str = js.decode(u16, loose, (!loose && isWellFormed) || (loose && toWellFormed))
|
|
65
65
|
if (!loose && isWellFormed && !isWellFormed.call(str)) throw new TypeError(E_STRICT)
|
|
66
|
+
if (loose && toWellFormed) return toWellFormed.call(str)
|
|
66
67
|
|
|
67
68
|
return str
|
|
68
69
|
}
|
package/utf16.node.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isDeno, isLE } from './fallback/_utils.js'
|
|
2
2
|
import { E_STRICT, E_STRICT_UNICODE } from './fallback/utf16.js'
|
|
3
3
|
|
|
4
4
|
if (Buffer.TYPED_ARRAY_SUPPORT) throw new Error('Unexpected Buffer polyfill')
|
|
5
5
|
|
|
6
|
-
const { isWellFormed } = String.prototype
|
|
6
|
+
const { isWellFormed, toWellFormed } = String.prototype
|
|
7
7
|
const to8 = (a) => new Uint8Array(a.buffer, a.byteOffset, a.byteLength)
|
|
8
8
|
|
|
9
9
|
// Unlike utf8, operates on Uint16Arrays by default
|
|
@@ -14,9 +14,10 @@ function encode(str, loose = false, format = 'uint16') {
|
|
|
14
14
|
throw new TypeError('Unknown format')
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
if (loose) {
|
|
18
|
+
str = toWellFormed.call(str) // Buffer doesn't do this with utf16 encoding
|
|
19
|
+
} else if (!isWellFormed.call(str)) {
|
|
20
|
+
throw new TypeError(E_STRICT_UNICODE)
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
const ble = Buffer.from(str, 'utf-16le')
|
|
@@ -36,6 +37,7 @@ const swapped = (x, swap) =>
|
|
|
36
37
|
swap ? Buffer.from(x).swap16() : Buffer.from(x.buffer, x.byteOffset, x.byteLength)
|
|
37
38
|
|
|
38
39
|
// We skip TextDecoder on Node.js, as it's is somewhy significantly slower than Buffer for utf16
|
|
40
|
+
// Also, it incorrectly misses replacements with Node.js is built without ICU, we fix that
|
|
39
41
|
function decodeNode(input, loose = false, format = 'uint16') {
|
|
40
42
|
let ble
|
|
41
43
|
if (format === 'uint16') {
|
|
@@ -50,9 +52,9 @@ function decodeNode(input, loose = false, format = 'uint16') {
|
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
const str = ble.ucs2Slice(0, ble.byteLength)
|
|
55
|
+
if (loose) return toWellFormed.call(str)
|
|
53
56
|
if (isWellFormed.call(str)) return str
|
|
54
|
-
|
|
55
|
-
return nativeDecoder.decode(Buffer.from(str)) // fixup (see above)
|
|
57
|
+
throw new TypeError(E_STRICT)
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
function decodeDecoder(input, loose = false, format = 'uint16') {
|
package/utf8.node.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { assertUint8 } from './assert.js'
|
|
2
2
|
import { typedView } from './array.js'
|
|
3
|
-
import { E_STRICT_UNICODE } from './fallback/utf8.js'
|
|
3
|
+
import { E_STRICT, E_STRICT_UNICODE } from './fallback/utf8.js'
|
|
4
4
|
import { isAscii } from 'node:buffer'
|
|
5
5
|
|
|
6
6
|
if (Buffer.TYPED_ARRAY_SUPPORT) throw new Error('Unexpected Buffer polyfill')
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
let decoderFatal
|
|
9
9
|
const decoderLoose = new TextDecoder('utf-8', { ignoreBOM: true })
|
|
10
10
|
const { isWellFormed } = String.prototype
|
|
11
11
|
const isDeno = Boolean(globalThis.Deno)
|
|
12
12
|
|
|
13
|
+
try {
|
|
14
|
+
decoderFatal = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true })
|
|
15
|
+
} catch {
|
|
16
|
+
// Without ICU, Node.js doesn't support fatal option for utf-8
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
function encode(str, loose = false) {
|
|
14
20
|
if (typeof str !== 'string') throw new TypeError('Input is not a string')
|
|
15
21
|
const strLength = str.length
|
|
@@ -45,7 +51,14 @@ function decode(arr, loose = false) {
|
|
|
45
51
|
return buf.latin1Slice(0, arr.byteLength) // .latin1Slice is faster than .asciiSlice
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
if (loose) return decoderLoose.decode(arr)
|
|
55
|
+
if (decoderFatal) return decoderFatal.decode(arr)
|
|
56
|
+
|
|
57
|
+
// We are in an env without native fatal decoder support (non-fixed Node.js without ICU)
|
|
58
|
+
// Well, just recheck against encode if it contains replacement then, this is still faster than js impl
|
|
59
|
+
const str = decoderLoose.decode(arr)
|
|
60
|
+
if (str.includes('\uFFFD') && !Buffer.from(str).equals(arr)) throw new TypeError(E_STRICT)
|
|
61
|
+
return str
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
export const utf8fromString = (str, format = 'uint8') => typedView(encode(str, false), format)
|