@atcute/uint8array 1.0.5 → 1.1.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 +7 -1
- package/dist/index.bun.d.ts +31 -7
- package/dist/index.bun.d.ts.map +1 -1
- package/dist/index.bun.js +134 -38
- package/dist/index.bun.js.map +1 -1
- package/dist/index.d.ts +31 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +197 -33
- package/dist/index.js.map +1 -1
- package/dist/index.node.d.ts +34 -7
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +136 -1
- package/dist/index.node.js.map +1 -1
- package/lib/index.bun.ts +114 -45
- package/lib/index.node.ts +119 -1
- package/lib/index.ts +178 -33
- package/package.json +9 -7
package/lib/index.ts
CHANGED
|
@@ -135,56 +135,192 @@ export const encodeUtf8Into = (to: Uint8Array, str: string, offset?: number, len
|
|
|
135
135
|
return result.written;
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
-
const
|
|
138
|
+
const _fromCharCode = String.fromCharCode;
|
|
139
|
+
|
|
140
|
+
// fully unrolled short string decoder, inspired by cbor-x
|
|
141
|
+
// returns null if non-ASCII byte encountered, signaling fallback to TextDecoder
|
|
142
|
+
const _shortString = (from: Uint8Array, p: number, length: number): string | null => {
|
|
143
|
+
if (length < 4) {
|
|
144
|
+
if (length < 2) {
|
|
145
|
+
if (length === 0) return '';
|
|
146
|
+
const a = from[p];
|
|
147
|
+
if (a & 0x80) return null;
|
|
148
|
+
return _fromCharCode(a);
|
|
149
|
+
}
|
|
150
|
+
const a = from[p];
|
|
151
|
+
const b = from[p + 1];
|
|
152
|
+
if ((a | b) & 0x80) return null;
|
|
153
|
+
if (length === 2) return _fromCharCode(a, b);
|
|
154
|
+
const c = from[p + 2];
|
|
155
|
+
if (c & 0x80) return null;
|
|
156
|
+
return _fromCharCode(a, b, c);
|
|
157
|
+
}
|
|
158
|
+
const a = from[p];
|
|
159
|
+
const b = from[p + 1];
|
|
160
|
+
const c = from[p + 2];
|
|
161
|
+
const d = from[p + 3];
|
|
162
|
+
if ((a | b | c | d) & 0x80) return null;
|
|
163
|
+
if (length < 8) {
|
|
164
|
+
if (length === 4) return _fromCharCode(a, b, c, d);
|
|
165
|
+
const e = from[p + 4];
|
|
166
|
+
if (e & 0x80) return null;
|
|
167
|
+
if (length === 5) return _fromCharCode(a, b, c, d, e);
|
|
168
|
+
const f = from[p + 5];
|
|
169
|
+
if (f & 0x80) return null;
|
|
170
|
+
if (length === 6) return _fromCharCode(a, b, c, d, e, f);
|
|
171
|
+
const g = from[p + 6];
|
|
172
|
+
if (g & 0x80) return null;
|
|
173
|
+
return _fromCharCode(a, b, c, d, e, f, g);
|
|
174
|
+
}
|
|
175
|
+
const e = from[p + 4];
|
|
176
|
+
const f = from[p + 5];
|
|
177
|
+
const g = from[p + 6];
|
|
178
|
+
const h = from[p + 7];
|
|
179
|
+
if ((e | f | g | h) & 0x80) return null;
|
|
180
|
+
if (length < 12) {
|
|
181
|
+
if (length === 8) return _fromCharCode(a, b, c, d, e, f, g, h);
|
|
182
|
+
const i = from[p + 8];
|
|
183
|
+
if (i & 0x80) return null;
|
|
184
|
+
if (length === 9) return _fromCharCode(a, b, c, d, e, f, g, h, i);
|
|
185
|
+
const j = from[p + 9];
|
|
186
|
+
if (j & 0x80) return null;
|
|
187
|
+
if (length === 10) return _fromCharCode(a, b, c, d, e, f, g, h, i, j);
|
|
188
|
+
const k = from[p + 10];
|
|
189
|
+
if (k & 0x80) return null;
|
|
190
|
+
return _fromCharCode(a, b, c, d, e, f, g, h, i, j, k);
|
|
191
|
+
}
|
|
192
|
+
const i = from[p + 8];
|
|
193
|
+
const j = from[p + 9];
|
|
194
|
+
const k = from[p + 10];
|
|
195
|
+
const l = from[p + 11];
|
|
196
|
+
if ((i | j | k | l) & 0x80) return null;
|
|
197
|
+
if (length === 12) return _fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l);
|
|
198
|
+
const m = from[p + 12];
|
|
199
|
+
if (m & 0x80) return null;
|
|
200
|
+
if (length === 13) return _fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m);
|
|
201
|
+
const n = from[p + 13];
|
|
202
|
+
if (n & 0x80) return null;
|
|
203
|
+
if (length === 14) return _fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n);
|
|
204
|
+
const o = from[p + 14];
|
|
205
|
+
if (o & 0x80) return null;
|
|
206
|
+
return _fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o);
|
|
207
|
+
};
|
|
139
208
|
|
|
140
209
|
/**
|
|
141
210
|
* decodes a UTF-8 string from a given buffer
|
|
211
|
+
* @param from source buffer
|
|
212
|
+
* @param offset byte offset to start reading from
|
|
213
|
+
* @param length number of bytes to read
|
|
214
|
+
* @returns decoded string
|
|
142
215
|
*/
|
|
143
|
-
export const decodeUtf8From = (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
buffer = from.subarray(offset, offset + length);
|
|
216
|
+
export const decodeUtf8From = (
|
|
217
|
+
from: Uint8Array,
|
|
218
|
+
offset: number = 0,
|
|
219
|
+
length: number = from.length,
|
|
220
|
+
): string => {
|
|
221
|
+
if (length <= 15) {
|
|
222
|
+
const result = _shortString(from, offset, length);
|
|
223
|
+
if (result !== null) return result;
|
|
152
224
|
}
|
|
225
|
+
return textDecoder.decode(from.subarray(offset, offset + length));
|
|
226
|
+
};
|
|
153
227
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
228
|
+
/**
|
|
229
|
+
* calculates the UTF-8 byte length of a string
|
|
230
|
+
* @param str string to measure
|
|
231
|
+
* @returns byte length when encoded as UTF-8
|
|
232
|
+
*/
|
|
233
|
+
export const getUtf8Length = (str: string): number => {
|
|
234
|
+
const len = str.length;
|
|
158
235
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
let idx = 0;
|
|
236
|
+
let u16pos = 0;
|
|
237
|
+
let u8pos = 0;
|
|
162
238
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
239
|
+
// ASCII fast-path: batch process 4 chars at a time
|
|
240
|
+
while (u16pos + 3 < len) {
|
|
241
|
+
const a = str.charCodeAt(u16pos);
|
|
242
|
+
const b = str.charCodeAt(u16pos + 1);
|
|
243
|
+
const c = str.charCodeAt(u16pos + 2);
|
|
244
|
+
const d = str.charCodeAt(u16pos + 3);
|
|
168
245
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
246
|
+
if ((a | b | c | d) >= 0x80) {
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
u16pos += 4;
|
|
251
|
+
u8pos += 4;
|
|
252
|
+
}
|
|
172
253
|
|
|
173
|
-
|
|
254
|
+
// handle remaining chars
|
|
255
|
+
while (u16pos < len) {
|
|
256
|
+
const code = str.charCodeAt(u16pos);
|
|
257
|
+
|
|
258
|
+
if (code < 0x80) {
|
|
259
|
+
u16pos += 1;
|
|
260
|
+
u8pos += 1;
|
|
261
|
+
} else if (code < 0x800) {
|
|
262
|
+
u16pos += 1;
|
|
263
|
+
u8pos += 2;
|
|
264
|
+
} else if (code < 0xd800 || code > 0xdbff) {
|
|
265
|
+
u16pos += 1;
|
|
266
|
+
u8pos += 3;
|
|
267
|
+
} else {
|
|
268
|
+
u16pos += 2;
|
|
269
|
+
u8pos += 4;
|
|
174
270
|
}
|
|
271
|
+
}
|
|
175
272
|
|
|
176
|
-
|
|
177
|
-
|
|
273
|
+
return u8pos;
|
|
274
|
+
};
|
|
178
275
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
276
|
+
/**
|
|
277
|
+
* checks if a string's UTF-8 byte length is within a given range.
|
|
278
|
+
* includes early-exit optimization when exceeding max length.
|
|
279
|
+
* @param str string to measure
|
|
280
|
+
* @param min minimum byte length (inclusive)
|
|
281
|
+
* @param max maximum byte length (inclusive)
|
|
282
|
+
* @returns true if byte length is within [min, max]
|
|
283
|
+
*/
|
|
284
|
+
export const isUtf8LengthInRange = (str: string, min: number, max: number): boolean => {
|
|
285
|
+
const len = str.length;
|
|
286
|
+
|
|
287
|
+
// fast path: if max possible UTF-8 length is below min, fail
|
|
288
|
+
if (len * 3 < min) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
182
291
|
|
|
183
|
-
|
|
292
|
+
// fast path: if UTF-16 length satisfies min and max possible satisfies max
|
|
293
|
+
if (len >= min && len * 3 <= max) {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
let u16pos = 0;
|
|
298
|
+
let u8pos = 0;
|
|
299
|
+
|
|
300
|
+
while (u16pos < len) {
|
|
301
|
+
const code = str.charCodeAt(u16pos);
|
|
302
|
+
|
|
303
|
+
if (code < 0x80) {
|
|
304
|
+
u16pos += 1;
|
|
305
|
+
u8pos += 1;
|
|
306
|
+
} else if (code < 0x800) {
|
|
307
|
+
u16pos += 1;
|
|
308
|
+
u8pos += 2;
|
|
309
|
+
} else if (code < 0xd800 || code > 0xdbff) {
|
|
310
|
+
u16pos += 1;
|
|
311
|
+
u8pos += 3;
|
|
312
|
+
} else {
|
|
313
|
+
u16pos += 2;
|
|
314
|
+
u8pos += 4;
|
|
184
315
|
}
|
|
185
316
|
|
|
186
|
-
|
|
317
|
+
// early exit once we exceed max
|
|
318
|
+
if (u8pos > max) {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
187
321
|
}
|
|
322
|
+
|
|
323
|
+
return u8pos >= min;
|
|
188
324
|
};
|
|
189
325
|
|
|
190
326
|
/**
|
|
@@ -193,3 +329,12 @@ export const decodeUtf8From = (from: Uint8Array, offset?: number, length?: numbe
|
|
|
193
329
|
export const toSha256 = async (buffer: Uint8Array<ArrayBuffer>): Promise<Uint8Array<ArrayBuffer>> => {
|
|
194
330
|
return new Uint8Array(await subtle.digest('SHA-256', buffer));
|
|
195
331
|
};
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* generates cryptographically secure random bytes
|
|
335
|
+
* @param size number of bytes to generate
|
|
336
|
+
* @returns buffer filled with random bytes
|
|
337
|
+
*/
|
|
338
|
+
export const randomBytes = (size: number): Uint8Array<ArrayBuffer> => {
|
|
339
|
+
return crypto.getRandomValues(new Uint8Array(size));
|
|
340
|
+
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"type": "module",
|
|
3
2
|
"name": "@atcute/uint8array",
|
|
4
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
5
4
|
"description": "uint8array utilities",
|
|
6
5
|
"license": "0BSD",
|
|
7
6
|
"repository": {
|
|
8
7
|
"url": "https://github.com/mary-ext/atcute",
|
|
9
|
-
"directory": "packages/
|
|
8
|
+
"directory": "packages/misc/uint8array"
|
|
10
9
|
},
|
|
11
10
|
"files": [
|
|
12
11
|
"dist/",
|
|
@@ -14,6 +13,8 @@
|
|
|
14
13
|
"!lib/**/*.bench.ts",
|
|
15
14
|
"!lib/**/*.test.ts"
|
|
16
15
|
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"sideEffects": false,
|
|
17
18
|
"exports": {
|
|
18
19
|
".": {
|
|
19
20
|
"bun": "./dist/index.bun.js",
|
|
@@ -21,13 +22,14 @@
|
|
|
21
22
|
"default": "./dist/index.js"
|
|
22
23
|
}
|
|
23
24
|
},
|
|
24
|
-
"
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
25
28
|
"devDependencies": {
|
|
26
|
-
"@types/bun": "^1.
|
|
29
|
+
"@types/bun": "^1.3.5"
|
|
27
30
|
},
|
|
28
31
|
"scripts": {
|
|
29
|
-
"build": "
|
|
30
|
-
"test": "bun test --coverage",
|
|
32
|
+
"build": "tsgo --project tsconfig.build.json",
|
|
31
33
|
"prepublish": "rm -rf dist; pnpm run build"
|
|
32
34
|
}
|
|
33
35
|
}
|