bplist-lossless 0.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/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +111 -0
- package/bun.lock +176 -0
- package/package.json +55 -0
- package/readme.md +170 -0
- package/src/classes/plist-date.ts +489 -0
- package/src/classes/uid.ts +38 -0
- package/src/classes/utf16-string.ts +54 -0
- package/src/exports/main.ts +5 -0
- package/src/utils/parse.ts +312 -0
- package/src/utils/serialize.ts +536 -0
- package/test/plist.fuzz.test.ts +298 -0
- package/tsconfig.json +30 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import { PlistDate } from '../classes/plist-date.js';
|
|
2
|
+
import { UID } from '../classes/uid.js';
|
|
3
|
+
import { Utf16String } from '../classes/utf16-string.js';
|
|
4
|
+
|
|
5
|
+
export function serializeBplist(dicts: unknown) {
|
|
6
|
+
var buffer = new WritableStreamBuffer();
|
|
7
|
+
buffer.write(Buffer.from("bplist00"));
|
|
8
|
+
|
|
9
|
+
var entries = toEntries(dicts);
|
|
10
|
+
var idSizeInBytes = computeIdSizeInBytes(entries.length);
|
|
11
|
+
var offsets: number[] = [];
|
|
12
|
+
var offsetSizeInBytes: number;
|
|
13
|
+
var offsetTableOffset: number;
|
|
14
|
+
|
|
15
|
+
updateEntryIds();
|
|
16
|
+
|
|
17
|
+
entries.forEach(function(entry, entryIdx) {
|
|
18
|
+
offsets[entryIdx] = buffer.size();
|
|
19
|
+
if (!entry) {
|
|
20
|
+
buffer.write(0x00);
|
|
21
|
+
} else {
|
|
22
|
+
write(entry);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
writeOffsetTable();
|
|
27
|
+
writeTrailer();
|
|
28
|
+
return buffer.getContents();
|
|
29
|
+
|
|
30
|
+
function updateEntryIds() {
|
|
31
|
+
var strings: Record<string, any> = {};
|
|
32
|
+
var entryId = 0;
|
|
33
|
+
entries.forEach(function(entry) {
|
|
34
|
+
if (entry.id) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (entry.type === 'string') {
|
|
38
|
+
if (!entry.bplistOverride && strings.hasOwnProperty(entry.value)) {
|
|
39
|
+
entry.type = 'stringref';
|
|
40
|
+
entry.id = strings[entry.value];
|
|
41
|
+
} else {
|
|
42
|
+
strings[entry.value] = entry.id = entryId++;
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
entry.id = entryId++;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
entries = entries.filter(function(entry) {
|
|
50
|
+
return (entry.type !== 'stringref');
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function writeTrailer() {
|
|
55
|
+
// 6 null bytes
|
|
56
|
+
buffer.write(Buffer.from([0, 0, 0, 0, 0, 0]));
|
|
57
|
+
|
|
58
|
+
// size of an offset
|
|
59
|
+
writeByte(offsetSizeInBytes);
|
|
60
|
+
|
|
61
|
+
// size of a ref
|
|
62
|
+
writeByte(idSizeInBytes);
|
|
63
|
+
|
|
64
|
+
// number of objects
|
|
65
|
+
writeLong(entries.length);
|
|
66
|
+
|
|
67
|
+
// top object
|
|
68
|
+
writeLong(0);
|
|
69
|
+
|
|
70
|
+
// offset table offset
|
|
71
|
+
writeLong(offsetTableOffset);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function writeOffsetTable() {
|
|
75
|
+
offsetTableOffset = buffer.size();
|
|
76
|
+
offsetSizeInBytes = computeOffsetSizeInBytes(offsetTableOffset);
|
|
77
|
+
offsets.forEach(function(offset) {
|
|
78
|
+
writeBytes(offset, offsetSizeInBytes);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function write(entry: any) {
|
|
83
|
+
switch (entry.type) {
|
|
84
|
+
case 'dict':
|
|
85
|
+
writeDict(entry);
|
|
86
|
+
break;
|
|
87
|
+
case 'number':
|
|
88
|
+
case 'double':
|
|
89
|
+
writeNumber(entry);
|
|
90
|
+
break;
|
|
91
|
+
case 'UID':
|
|
92
|
+
writeUID(entry);
|
|
93
|
+
break;
|
|
94
|
+
case 'array':
|
|
95
|
+
writeArray(entry);
|
|
96
|
+
break;
|
|
97
|
+
case 'boolean':
|
|
98
|
+
writeBoolean(entry);
|
|
99
|
+
break;
|
|
100
|
+
case 'string':
|
|
101
|
+
case 'string-utf16':
|
|
102
|
+
writeString(entry);
|
|
103
|
+
break;
|
|
104
|
+
case 'date':
|
|
105
|
+
writeDate(entry);
|
|
106
|
+
break;
|
|
107
|
+
case 'data':
|
|
108
|
+
writeData(entry);
|
|
109
|
+
break;
|
|
110
|
+
case 'null':
|
|
111
|
+
writeNull()
|
|
112
|
+
break;
|
|
113
|
+
default:
|
|
114
|
+
throw new Error("unhandled entry type: " + entry.type);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function writeDate(entry: any) {
|
|
119
|
+
writeByte(0x33);
|
|
120
|
+
|
|
121
|
+
const raw = PlistDate.from(entry.value).toBuffer();
|
|
122
|
+
buffer.write(raw);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function writeDict(entry: any) {
|
|
126
|
+
writeIntHeader(0xD, entry.entryKeys.length);
|
|
127
|
+
entry.entryKeys.forEach(function(entry: any) {
|
|
128
|
+
writeID(entry.id);
|
|
129
|
+
});
|
|
130
|
+
entry.entryValues.forEach(function(entry: any) {
|
|
131
|
+
writeID(entry.id);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function writeNumber(entry: any) {
|
|
136
|
+
if (typeof entry.value === 'bigint') {
|
|
137
|
+
const size = getIntSize(entry.value);
|
|
138
|
+
const header = 0x10 | Math.log2(size);
|
|
139
|
+
|
|
140
|
+
writeByte(header);
|
|
141
|
+
|
|
142
|
+
const buf = bigintToBuffer(entry.value, size);
|
|
143
|
+
buffer.write(buf);
|
|
144
|
+
} else if (entry.type !== 'double' && parseFloat(entry.value).toFixed() == entry.value) {
|
|
145
|
+
if (entry.value < 0) {
|
|
146
|
+
writeByte(0x13);
|
|
147
|
+
writeBytes(entry.value, 8, true);
|
|
148
|
+
} else if (entry.value <= 0xff) {
|
|
149
|
+
writeByte(0x10);
|
|
150
|
+
writeBytes(entry.value, 1);
|
|
151
|
+
} else if (entry.value <= 0xffff) {
|
|
152
|
+
writeByte(0x11);
|
|
153
|
+
writeBytes(entry.value, 2);
|
|
154
|
+
} else if (entry.value <= 0xffffffff) {
|
|
155
|
+
writeByte(0x12);
|
|
156
|
+
writeBytes(entry.value, 4);
|
|
157
|
+
} else {
|
|
158
|
+
writeByte(0x13);
|
|
159
|
+
writeBytes(entry.value, 8);
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
writeByte(0x23);
|
|
163
|
+
writeDouble(entry.value);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function writeUID(entry: any) {
|
|
168
|
+
let raw: Buffer;
|
|
169
|
+
|
|
170
|
+
if (entry.value instanceof UID) {
|
|
171
|
+
raw = Buffer.from(
|
|
172
|
+
entry.value.buffer,
|
|
173
|
+
entry.value.byteOffset,
|
|
174
|
+
entry.value.byteLength,
|
|
175
|
+
);
|
|
176
|
+
} else if (typeof entry.value === "bigint") {
|
|
177
|
+
if (entry.value < 0n) {
|
|
178
|
+
throw new TypeError("UID must be unsigned");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let hex = entry.value.toString(16);
|
|
182
|
+
if (hex.length % 2 !== 0) hex = "0" + hex;
|
|
183
|
+
raw = hex.length === 0 ? Buffer.from([0]) : Buffer.from(hex || "00", "hex");
|
|
184
|
+
} else if (
|
|
185
|
+
typeof entry.value === "number" &&
|
|
186
|
+
Number.isInteger(entry.value) &&
|
|
187
|
+
entry.value >= 0
|
|
188
|
+
) {
|
|
189
|
+
let n = BigInt(entry.value);
|
|
190
|
+
let hex = n.toString(16);
|
|
191
|
+
if (hex.length % 2 !== 0) hex = "0" + hex;
|
|
192
|
+
raw = Buffer.from(hex || "00", "hex");
|
|
193
|
+
} else {
|
|
194
|
+
throw new TypeError("UID value must be a UID, bigint, or unsigned integer number");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Canonical: strip leading zero bytes, but keep at least one byte.
|
|
198
|
+
let start = 0;
|
|
199
|
+
while (start < raw.length - 1 && raw[start] === 0) start++;
|
|
200
|
+
raw = raw.subarray(start);
|
|
201
|
+
|
|
202
|
+
if (raw.length < 1 || raw.length > 16) {
|
|
203
|
+
throw new RangeError(`UID must be between 1 and 16 bytes, got ${raw.length}`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
writeByte(0x80 | (raw.length - 1));
|
|
207
|
+
buffer.write(raw);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function writeArray(entry: any) {
|
|
211
|
+
writeIntHeader(0xA, entry.entries.length);
|
|
212
|
+
entry.entries.forEach(function(e: any) {
|
|
213
|
+
writeID(e.id);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function writeBoolean(entry: any) {
|
|
218
|
+
writeByte(entry.value ? 0x09 : 0x08);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function writeNull() {
|
|
222
|
+
writeByte(0x00);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
function writeString(entry: any) {
|
|
227
|
+
if (entry.type === 'string-utf16') {
|
|
228
|
+
let utf16: Buffer;
|
|
229
|
+
|
|
230
|
+
if (Utf16String.isUtf16String(entry.value)) {
|
|
231
|
+
// ✅ USE RAW BYTES DIRECTLY
|
|
232
|
+
utf16 = Buffer.from(
|
|
233
|
+
entry.value.buffer,
|
|
234
|
+
entry.value.byteOffset,
|
|
235
|
+
entry.value.byteLength
|
|
236
|
+
);
|
|
237
|
+
} else {
|
|
238
|
+
// string → UTF-16LE → convert to BE
|
|
239
|
+
const le = Buffer.from(entry.value, 'ucs2');
|
|
240
|
+
utf16 = Buffer.alloc(le.length);
|
|
241
|
+
|
|
242
|
+
for (let i = 0; i < le.length; i += 2) {
|
|
243
|
+
utf16[i] = le[i + 1]!;
|
|
244
|
+
utf16[i + 1] = le[i]!;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
writeIntHeader(0x6, utf16.length / 2);
|
|
249
|
+
buffer.write(utf16);
|
|
250
|
+
} else {
|
|
251
|
+
const ascii = Buffer.from(entry.value, 'latin1');
|
|
252
|
+
writeIntHeader(0x5, ascii.length);
|
|
253
|
+
buffer.write(ascii);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function writeData(entry: any) {
|
|
258
|
+
writeIntHeader(0x4, entry.value.length);
|
|
259
|
+
buffer.write(entry.value);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function writeLong(l: number) {
|
|
263
|
+
writeBytes(l, 8);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function writeByte(b: number) {
|
|
267
|
+
buffer.write(Buffer.from([b]));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function writeDouble(v: number) {
|
|
271
|
+
var buf = Buffer.alloc(8);
|
|
272
|
+
buf.writeDoubleBE(v, 0);
|
|
273
|
+
buffer.write(buf);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function writeIntHeader(kind: number, value: number) {
|
|
277
|
+
if (value < 15) {
|
|
278
|
+
writeByte((kind << 4) + value);
|
|
279
|
+
} else if (value < 256) {
|
|
280
|
+
writeByte((kind << 4) + 15);
|
|
281
|
+
writeByte(0x10);
|
|
282
|
+
writeBytes(value, 1);
|
|
283
|
+
} else if (value < 65536) {
|
|
284
|
+
writeByte((kind << 4) + 15);
|
|
285
|
+
writeByte(0x11);
|
|
286
|
+
writeBytes(value, 2);
|
|
287
|
+
} else {
|
|
288
|
+
writeByte((kind << 4) + 15);
|
|
289
|
+
writeByte(0x12);
|
|
290
|
+
writeBytes(value, 4);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function writeID(id: number) {
|
|
295
|
+
writeBytes(id, idSizeInBytes);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function writeBytes(value: number, bytes: number, is_signedint = false) {
|
|
299
|
+
// write low-order bytes big-endian style
|
|
300
|
+
var buf = Buffer.alloc(bytes);
|
|
301
|
+
var z = 0;
|
|
302
|
+
|
|
303
|
+
// javascript doesn't handle large numbers
|
|
304
|
+
while (bytes > 4) {
|
|
305
|
+
buf[z++] = is_signedint ? 0xff : 0;
|
|
306
|
+
bytes--;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
for (var i = bytes - 1; i >= 0; i--) {
|
|
310
|
+
buf[z++] = value >> (8 * i);
|
|
311
|
+
}
|
|
312
|
+
buffer.write(buf);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
function toEntries(dicts: any) {
|
|
317
|
+
if (dicts === null) {
|
|
318
|
+
return [
|
|
319
|
+
{
|
|
320
|
+
type: 'null',
|
|
321
|
+
value: null
|
|
322
|
+
}
|
|
323
|
+
];
|
|
324
|
+
} else if (typeof dicts === 'boolean') {
|
|
325
|
+
return [
|
|
326
|
+
{
|
|
327
|
+
type: 'boolean',
|
|
328
|
+
value: dicts
|
|
329
|
+
}
|
|
330
|
+
];
|
|
331
|
+
} else if (typeof dicts === 'bigint') {
|
|
332
|
+
return [
|
|
333
|
+
{
|
|
334
|
+
type: 'number',
|
|
335
|
+
value: dicts
|
|
336
|
+
}
|
|
337
|
+
];
|
|
338
|
+
} else if (typeof dicts === 'number') {
|
|
339
|
+
return [
|
|
340
|
+
{
|
|
341
|
+
type: 'double',
|
|
342
|
+
value: dicts
|
|
343
|
+
}
|
|
344
|
+
];
|
|
345
|
+
} else if (typeof dicts === 'string') {
|
|
346
|
+
return [
|
|
347
|
+
{
|
|
348
|
+
type: mustBeUtf16(dicts) ? 'string-utf16' : 'string',
|
|
349
|
+
value: dicts
|
|
350
|
+
}
|
|
351
|
+
];
|
|
352
|
+
} else if (Utf16String.isUtf16String(dicts)) {
|
|
353
|
+
return [
|
|
354
|
+
{
|
|
355
|
+
type: 'string-utf16',
|
|
356
|
+
value: dicts
|
|
357
|
+
}
|
|
358
|
+
]
|
|
359
|
+
} else if (UID.isUID(dicts)) {
|
|
360
|
+
return [
|
|
361
|
+
{
|
|
362
|
+
type: 'UID',
|
|
363
|
+
value: dicts
|
|
364
|
+
}
|
|
365
|
+
]
|
|
366
|
+
} else if (Buffer.isBuffer((dicts))) {
|
|
367
|
+
return [
|
|
368
|
+
{
|
|
369
|
+
type: 'data',
|
|
370
|
+
value: dicts
|
|
371
|
+
}
|
|
372
|
+
];
|
|
373
|
+
} else if (
|
|
374
|
+
PlistDate.isPlistDate(dicts) ||
|
|
375
|
+
Object.prototype.toString.call(dicts) === '[object Date]'
|
|
376
|
+
) {
|
|
377
|
+
return [
|
|
378
|
+
{
|
|
379
|
+
type: 'date',
|
|
380
|
+
value: dicts
|
|
381
|
+
}
|
|
382
|
+
]
|
|
383
|
+
} else if (Array.isArray(dicts)) {
|
|
384
|
+
return toEntriesArray(dicts);
|
|
385
|
+
} else if (isPlainObject(dicts)) {
|
|
386
|
+
return toEntriesObject(dicts);
|
|
387
|
+
} else {
|
|
388
|
+
throw new Error('unhandled entry: ' + dicts);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function toEntriesArray(arr: unknown[]) {
|
|
393
|
+
var results = [
|
|
394
|
+
{
|
|
395
|
+
type: 'array',
|
|
396
|
+
entries: [] as unknown[]
|
|
397
|
+
}
|
|
398
|
+
];
|
|
399
|
+
arr.forEach(function(v) {
|
|
400
|
+
var entry = toEntries(v);
|
|
401
|
+
results[0]!.entries.push(entry[0]);
|
|
402
|
+
results = results.concat(entry);
|
|
403
|
+
});
|
|
404
|
+
return results;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function toEntriesObject(dict: Record<string, unknown>) {
|
|
408
|
+
const result = {
|
|
409
|
+
type: 'dict',
|
|
410
|
+
entryKeys: [] as unknown[],
|
|
411
|
+
entryValues: [] as unknown[],
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const results: any[] = [result];
|
|
415
|
+
|
|
416
|
+
for (const key of Reflect.ownKeys(dict)) {
|
|
417
|
+
if (typeof key !== "string") continue;
|
|
418
|
+
|
|
419
|
+
const entryKey = toEntries(key);
|
|
420
|
+
const entryValue = toEntries((dict as any)[key]);
|
|
421
|
+
|
|
422
|
+
result.entryKeys.push(entryKey[0]!);
|
|
423
|
+
result.entryValues.push(entryValue[0]!);
|
|
424
|
+
|
|
425
|
+
results.push(...entryKey);
|
|
426
|
+
results.push(...entryValue);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return results;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function computeOffsetSizeInBytes(maxOffset: number) {
|
|
433
|
+
if (maxOffset < 256) {
|
|
434
|
+
return 1;
|
|
435
|
+
}
|
|
436
|
+
if (maxOffset < 65536) {
|
|
437
|
+
return 2;
|
|
438
|
+
}
|
|
439
|
+
if (maxOffset < 4294967296) {
|
|
440
|
+
return 4;
|
|
441
|
+
}
|
|
442
|
+
return 8;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function computeIdSizeInBytes(numberOfIds: number) {
|
|
446
|
+
if (numberOfIds < 256) {
|
|
447
|
+
return 1;
|
|
448
|
+
}
|
|
449
|
+
if (numberOfIds < 65536) {
|
|
450
|
+
return 2;
|
|
451
|
+
}
|
|
452
|
+
return 4;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
456
|
+
if (Object.prototype.toString.call(value) !== '[object Object]') {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const proto = Object.getPrototypeOf(value);
|
|
461
|
+
return proto === null || proto === Object.prototype;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
class WritableStreamBuffer {
|
|
465
|
+
_chunks: Buffer[];
|
|
466
|
+
_size: number;
|
|
467
|
+
|
|
468
|
+
constructor() {
|
|
469
|
+
this._chunks = [];
|
|
470
|
+
this._size = 0;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
write(chunk: unknown, encoding?: any) {
|
|
474
|
+
let buf;
|
|
475
|
+
|
|
476
|
+
if (typeof chunk === 'number') {
|
|
477
|
+
buf = Buffer.from([chunk & 0xff]);
|
|
478
|
+
} else if (Buffer.isBuffer(chunk)) {
|
|
479
|
+
// copy to mirror stream-buffers behavior more closely
|
|
480
|
+
buf = Buffer.from(chunk);
|
|
481
|
+
} else if (chunk instanceof Uint8Array) {
|
|
482
|
+
buf = Buffer.from(chunk);
|
|
483
|
+
} else if (typeof chunk === 'string') {
|
|
484
|
+
buf = Buffer.from(chunk, encoding);
|
|
485
|
+
} else {
|
|
486
|
+
throw new TypeError('Unsupported chunk type passed to write()');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
this._chunks.push(buf);
|
|
490
|
+
this._size += buf.length;
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
size() {
|
|
495
|
+
return this._size;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
getContents() {
|
|
499
|
+
return Buffer.concat(this._chunks, this._size);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
function bigintToBuffer(value: bigint, size: number): Buffer {
|
|
505
|
+
const buf = Buffer.alloc(size);
|
|
506
|
+
|
|
507
|
+
let temp = value;
|
|
508
|
+
|
|
509
|
+
// handle negative via two's complement
|
|
510
|
+
if (value < 0) {
|
|
511
|
+
temp = (1n << BigInt(size * 8)) + value;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
for (let i = size - 1; i >= 0; i--) {
|
|
515
|
+
buf[i] = Number(temp & 0xffn);
|
|
516
|
+
temp >>= 8n;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return buf;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
function getIntSize(value: bigint): number {
|
|
524
|
+
if (value >= -0x80n && value <= 0x7fn) return 1;
|
|
525
|
+
if (value >= -0x8000n && value <= 0x7fffn) return 2;
|
|
526
|
+
if (value >= -0x80000000n && value <= 0x7fffffffn) return 4;
|
|
527
|
+
if (value >= -0x8000000000000000n && value <= 0x7fffffffffffffffn) return 8;
|
|
528
|
+
return 16;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function mustBeUtf16(str: string) {
|
|
532
|
+
for (let i = 0; i < str.length; i++) {
|
|
533
|
+
if (str.charCodeAt(i) > 0x7f) return true;
|
|
534
|
+
}
|
|
535
|
+
return false;
|
|
536
|
+
}
|