@corewire/core 0.0.0 → 1.0.0-next.2
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 +28 -1
- package/dist/chunk-wE0WeVzl.mjs +22 -0
- package/dist/crypto-CXSIS6si.mjs +3093 -0
- package/dist/crypto.d.mts +111 -0
- package/dist/crypto.mjs +3 -0
- package/dist/discovery.d.mts +110 -0
- package/dist/discovery.mjs +763 -0
- package/dist/encoding-BaLbwFQ0.mjs +1663 -0
- package/dist/encoding.d.mts +411 -0
- package/dist/encoding.mjs +3 -0
- package/dist/errors-DVv1n4fL.mjs +125 -0
- package/dist/index-BJKNwUmq.d.mts +125 -0
- package/dist/index.d.mts +82 -0
- package/dist/index.mjs +5 -0
- package/dist/pairing.d.mts +169 -0
- package/dist/pairing.mjs +2487 -0
- package/dist/reporter-DfM6vPT0.mjs +223 -0
- package/dist/reporter-Dn7n2TXN.d.mts +112 -0
- package/dist/transport-C4BMdD2J.mjs +270 -0
- package/dist/transport.d.mts +2 -0
- package/dist/transport.mjs +3 -0
- package/dist/types-qzabRJJ9.d.mts +5 -0
- package/dist/utils-DY5OKUuy.mjs +8 -0
- package/package.json +84 -18
|
@@ -0,0 +1,1663 @@
|
|
|
1
|
+
import { n as __exportAll } from "./chunk-wE0WeVzl.mjs";
|
|
2
|
+
import { h as TLV8PairingError } from "./errors-DVv1n4fL.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/encoding/daap.ts
|
|
5
|
+
var daap_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
ContentCode: () => ContentCode,
|
|
7
|
+
TagType: () => TagType,
|
|
8
|
+
decode: () => decode$4,
|
|
9
|
+
decodeTag: () => decodeTag,
|
|
10
|
+
decodeToObject: () => decodeToObject,
|
|
11
|
+
decodeTrackMetadata: () => decodeTrackMetadata,
|
|
12
|
+
encodeContainer: () => encodeContainer,
|
|
13
|
+
encodePlaybackStatus: () => encodePlaybackStatus,
|
|
14
|
+
encodeTag: () => encodeTag,
|
|
15
|
+
encodeTagWithSize: () => encodeTagWithSize,
|
|
16
|
+
encodeTrackMetadata: () => encodeTrackMetadata
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Maps four-character DAAP tag codes to their DMAP/DAAP content code names.
|
|
20
|
+
*/
|
|
21
|
+
const ContentCode = {
|
|
22
|
+
mlit: "dmap.listingitem",
|
|
23
|
+
mlcl: "dmap.listing",
|
|
24
|
+
msrv: "dmap.serverinforesponse",
|
|
25
|
+
mcon: "dmap.container",
|
|
26
|
+
miid: "dmap.itemid",
|
|
27
|
+
minm: "dmap.itemname",
|
|
28
|
+
mikd: "dmap.itemkind",
|
|
29
|
+
mper: "dmap.persistentid",
|
|
30
|
+
asal: "daap.songalbum",
|
|
31
|
+
asar: "daap.songartist",
|
|
32
|
+
asaa: "daap.songalbumartist",
|
|
33
|
+
ascp: "daap.songcomposer",
|
|
34
|
+
asgn: "daap.songgenre",
|
|
35
|
+
astm: "daap.songtime",
|
|
36
|
+
astn: "daap.songtracknumber",
|
|
37
|
+
asdc: "daap.songdisccount",
|
|
38
|
+
asdn: "daap.songdiscnumber",
|
|
39
|
+
astc: "daap.songtrackcount",
|
|
40
|
+
asyr: "daap.songyear",
|
|
41
|
+
asbr: "daap.songbitrate",
|
|
42
|
+
assr: "daap.songsamplerate",
|
|
43
|
+
assz: "daap.songsize",
|
|
44
|
+
caps: "daap.songplaystatus",
|
|
45
|
+
cash: "daap.songshufflestate",
|
|
46
|
+
carp: "daap.songrepeatstate",
|
|
47
|
+
cavs: "daap.songvisiblestate",
|
|
48
|
+
aePP: "com.apple.itunes.photo-properties"
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Maps four-character DAAP tag codes to the type the decoder reads their value as.
|
|
52
|
+
*
|
|
53
|
+
* Type values: 1=byte, 2=unsigned byte, 3=short, 4=unsigned short,
|
|
54
|
+
* 5=int, 6=unsigned int, 7=long, 8=unsigned long,
|
|
55
|
+
* 9=string, 10=date, 11=version, 12=container.
|
|
56
|
+
*/
|
|
57
|
+
const TagType = {
|
|
58
|
+
mlit: 12,
|
|
59
|
+
mlcl: 12,
|
|
60
|
+
mcon: 12,
|
|
61
|
+
msrv: 12,
|
|
62
|
+
miid: 5,
|
|
63
|
+
minm: 9,
|
|
64
|
+
mikd: 1,
|
|
65
|
+
mper: 7,
|
|
66
|
+
asal: 9,
|
|
67
|
+
asar: 9,
|
|
68
|
+
asaa: 9,
|
|
69
|
+
ascp: 9,
|
|
70
|
+
asgn: 9,
|
|
71
|
+
astm: 5,
|
|
72
|
+
astn: 3,
|
|
73
|
+
asdc: 3,
|
|
74
|
+
asdn: 3,
|
|
75
|
+
astc: 3,
|
|
76
|
+
asyr: 3,
|
|
77
|
+
asbr: 3,
|
|
78
|
+
assr: 5,
|
|
79
|
+
assz: 5,
|
|
80
|
+
caps: 1,
|
|
81
|
+
cash: 1,
|
|
82
|
+
carp: 1,
|
|
83
|
+
cavs: 1,
|
|
84
|
+
aePP: 9
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Encodes a single DAAP tag. A number takes the smallest big-endian size that fits.
|
|
88
|
+
*
|
|
89
|
+
* @param tag - Four-character ASCII tag code, such as `minm`.
|
|
90
|
+
* @param value - A string is written as UTF-8, a bigint as 8 bytes and a Buffer as is.
|
|
91
|
+
* @throws Error if the tag is not exactly 4 characters.
|
|
92
|
+
*/
|
|
93
|
+
function encodeTag(tag, value) {
|
|
94
|
+
if (tag.length !== 4) throw new Error(`Invalid DAAP tag: ${tag}. Tags must be exactly 4 characters.`);
|
|
95
|
+
const tagBuffer = Buffer.from(tag, "ascii");
|
|
96
|
+
let valueBuffer;
|
|
97
|
+
if (typeof value === "string") valueBuffer = Buffer.from(value, "utf8");
|
|
98
|
+
else if (typeof value === "bigint") {
|
|
99
|
+
valueBuffer = Buffer.alloc(8);
|
|
100
|
+
valueBuffer.writeBigUInt64BE(value, 0);
|
|
101
|
+
} else if (typeof value === "number") if (value <= 255 && value >= 0) {
|
|
102
|
+
valueBuffer = Buffer.alloc(1);
|
|
103
|
+
valueBuffer.writeUInt8(value, 0);
|
|
104
|
+
} else if (value <= 65535 && value >= 0) {
|
|
105
|
+
valueBuffer = Buffer.alloc(2);
|
|
106
|
+
valueBuffer.writeUInt16BE(value, 0);
|
|
107
|
+
} else if (value <= 4294967295 && value >= 0) {
|
|
108
|
+
valueBuffer = Buffer.alloc(4);
|
|
109
|
+
valueBuffer.writeUInt32BE(value, 0);
|
|
110
|
+
} else {
|
|
111
|
+
valueBuffer = Buffer.alloc(8);
|
|
112
|
+
valueBuffer.writeBigInt64BE(BigInt(value), 0);
|
|
113
|
+
}
|
|
114
|
+
else valueBuffer = value;
|
|
115
|
+
const lengthBuffer = Buffer.allocUnsafe(4);
|
|
116
|
+
lengthBuffer.writeUInt32BE(valueBuffer.length, 0);
|
|
117
|
+
return Buffer.concat([
|
|
118
|
+
tagBuffer,
|
|
119
|
+
lengthBuffer,
|
|
120
|
+
valueBuffer
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Encodes a DAAP container tag around tags that are already encoded.
|
|
125
|
+
*
|
|
126
|
+
* @param tag - Four-character ASCII container tag code, such as `mlit`.
|
|
127
|
+
* @throws Error if the tag is not exactly 4 characters.
|
|
128
|
+
*/
|
|
129
|
+
function encodeContainer(tag, content) {
|
|
130
|
+
if (tag.length !== 4) throw new Error(`Invalid DAAP tag: ${tag}. Tags must be exactly 4 characters.`);
|
|
131
|
+
const tagBuffer = Buffer.from(tag, "ascii");
|
|
132
|
+
const lengthBuffer = Buffer.alloc(4);
|
|
133
|
+
lengthBuffer.writeUInt32BE(content.length, 0);
|
|
134
|
+
return Buffer.concat([
|
|
135
|
+
tagBuffer,
|
|
136
|
+
lengthBuffer,
|
|
137
|
+
content
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Encodes the playback status into DAAP tags, one tag per defined field.
|
|
142
|
+
*/
|
|
143
|
+
function encodePlaybackStatus(status) {
|
|
144
|
+
const tags = [];
|
|
145
|
+
if (status.playing !== void 0) tags.push(encodeTagWithSize("caps", status.playing ? 4 : 3, 1));
|
|
146
|
+
if (status.shuffle !== void 0) tags.push(encodeTagWithSize("cash", status.shuffle ? 1 : 0, 1));
|
|
147
|
+
if (status.repeat !== void 0) {
|
|
148
|
+
let repeatValue = 0;
|
|
149
|
+
if (status.repeat === "one") repeatValue = 1;
|
|
150
|
+
else if (status.repeat === "all") repeatValue = 2;
|
|
151
|
+
tags.push(encodeTagWithSize("carp", repeatValue, 1));
|
|
152
|
+
}
|
|
153
|
+
return Buffer.concat(tags);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Encodes a numeric DAAP tag with a fixed value size, for tags whose size the protocol fixes.
|
|
157
|
+
*
|
|
158
|
+
* @param tag - Four-character ASCII tag code.
|
|
159
|
+
* @param byteSize - Size of the big-endian value in bytes.
|
|
160
|
+
* @throws Error if the tag is not exactly 4 characters.
|
|
161
|
+
*/
|
|
162
|
+
function encodeTagWithSize(tag, value, byteSize) {
|
|
163
|
+
if (tag.length !== 4) throw new Error(`Invalid DAAP tag: ${tag}. Tags must be exactly 4 characters.`);
|
|
164
|
+
const tagBuffer = Buffer.from(tag, "ascii");
|
|
165
|
+
const valueBuffer = Buffer.alloc(byteSize);
|
|
166
|
+
switch (byteSize) {
|
|
167
|
+
case 1:
|
|
168
|
+
valueBuffer.writeUInt8(value, 0);
|
|
169
|
+
break;
|
|
170
|
+
case 2:
|
|
171
|
+
valueBuffer.writeUInt16BE(value, 0);
|
|
172
|
+
break;
|
|
173
|
+
case 4:
|
|
174
|
+
valueBuffer.writeUInt32BE(value, 0);
|
|
175
|
+
break;
|
|
176
|
+
case 8:
|
|
177
|
+
valueBuffer.writeBigUInt64BE(BigInt(value), 0);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
const lengthBuffer = Buffer.alloc(4);
|
|
181
|
+
lengthBuffer.writeUInt32BE(byteSize, 0);
|
|
182
|
+
return Buffer.concat([
|
|
183
|
+
tagBuffer,
|
|
184
|
+
lengthBuffer,
|
|
185
|
+
valueBuffer
|
|
186
|
+
]);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Encodes track metadata into a DAAP listing item (`mlit`), one tag per defined field.
|
|
190
|
+
* The duration goes from seconds to the milliseconds of `astm`.
|
|
191
|
+
*/
|
|
192
|
+
function encodeTrackMetadata(metadata) {
|
|
193
|
+
const tags = [];
|
|
194
|
+
if (metadata.title !== void 0) tags.push(encodeTag("minm", metadata.title));
|
|
195
|
+
if (metadata.artist !== void 0) tags.push(encodeTag("asar", metadata.artist));
|
|
196
|
+
if (metadata.albumArtist !== void 0) tags.push(encodeTag("asaa", metadata.albumArtist));
|
|
197
|
+
if (metadata.album !== void 0) tags.push(encodeTag("asal", metadata.album));
|
|
198
|
+
if (metadata.composer !== void 0) tags.push(encodeTag("ascp", metadata.composer));
|
|
199
|
+
if (metadata.genre !== void 0) tags.push(encodeTag("asgn", metadata.genre));
|
|
200
|
+
if (metadata.duration !== void 0) tags.push(encodeTagWithSize("astm", Math.floor(metadata.duration * 1e3), 4));
|
|
201
|
+
if (metadata.trackNumber !== void 0) tags.push(encodeTagWithSize("astn", metadata.trackNumber, 2));
|
|
202
|
+
if (metadata.trackCount !== void 0) tags.push(encodeTagWithSize("astc", metadata.trackCount, 2));
|
|
203
|
+
if (metadata.discNumber !== void 0) tags.push(encodeTagWithSize("asdn", metadata.discNumber, 2));
|
|
204
|
+
if (metadata.discCount !== void 0) tags.push(encodeTagWithSize("asdc", metadata.discCount, 2));
|
|
205
|
+
if (metadata.year !== void 0) tags.push(encodeTagWithSize("asyr", metadata.year, 2));
|
|
206
|
+
if (metadata.bitrate !== void 0) tags.push(encodeTagWithSize("asbr", metadata.bitrate, 2));
|
|
207
|
+
if (metadata.sampleRate !== void 0) tags.push(encodeTagWithSize("assr", metadata.sampleRate, 4));
|
|
208
|
+
if (metadata.size !== void 0) tags.push(encodeTagWithSize("assz", metadata.size, 4));
|
|
209
|
+
return encodeContainer("mlit", Buffer.concat(tags));
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Decodes the DAAP tags in a buffer, up to its end or the first incomplete tag.
|
|
213
|
+
*/
|
|
214
|
+
function decode$4(buffer) {
|
|
215
|
+
const tags = [];
|
|
216
|
+
let remaining = buffer;
|
|
217
|
+
while (remaining.length > 0) {
|
|
218
|
+
const result = decodeTag(remaining);
|
|
219
|
+
if (!result) break;
|
|
220
|
+
const [tag, rest] = result;
|
|
221
|
+
tags.push(tag);
|
|
222
|
+
remaining = rest;
|
|
223
|
+
}
|
|
224
|
+
return tags;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Decodes the DAAP tag at the start of a buffer.
|
|
228
|
+
*
|
|
229
|
+
* @returns The tag and the rest of the buffer, or null when the buffer holds no complete tag.
|
|
230
|
+
*/
|
|
231
|
+
function decodeTag(buffer) {
|
|
232
|
+
if (buffer.length < 8) return null;
|
|
233
|
+
const tag = buffer.subarray(0, 4).toString("ascii");
|
|
234
|
+
const length = buffer.readUInt32BE(4);
|
|
235
|
+
if (buffer.length < 8 + length) return null;
|
|
236
|
+
const value = buffer.subarray(8, 8 + length);
|
|
237
|
+
const remaining = buffer.subarray(8 + length);
|
|
238
|
+
return [{
|
|
239
|
+
tag,
|
|
240
|
+
length,
|
|
241
|
+
value
|
|
242
|
+
}, remaining];
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Decodes a DAAP buffer into an object keyed by tag code, with values read as {@link TagType} says.
|
|
246
|
+
* Containers decode recursively; a tag of unknown type keeps its raw buffer.
|
|
247
|
+
*/
|
|
248
|
+
function decodeToObject(buffer) {
|
|
249
|
+
const result = {};
|
|
250
|
+
const tags = decode$4(buffer);
|
|
251
|
+
for (const { tag, value } of tags) {
|
|
252
|
+
const tagType = TagType[tag];
|
|
253
|
+
if (tagType === void 0) result[tag] = value;
|
|
254
|
+
else if (tagType === 12) result[tag] = decodeToObject(value);
|
|
255
|
+
else if (tagType === 9) result[tag] = value.toString("utf8");
|
|
256
|
+
else if (tagType === 1 || tagType === 2) result[tag] = value.readUInt8(0);
|
|
257
|
+
else if (tagType === 3 || tagType === 4) result[tag] = value.readUInt16BE(0);
|
|
258
|
+
else if (tagType === 5 || tagType === 6) result[tag] = value.readUInt32BE(0);
|
|
259
|
+
else if (tagType === 7 || tagType === 8) result[tag] = value.readBigUInt64BE(0);
|
|
260
|
+
else result[tag] = value;
|
|
261
|
+
}
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Decodes track metadata from a bare tag list or an `mlit` container.
|
|
266
|
+
* The duration goes from the milliseconds of `astm` back to seconds.
|
|
267
|
+
*/
|
|
268
|
+
function decodeTrackMetadata(buffer) {
|
|
269
|
+
const decoded = decodeToObject(buffer);
|
|
270
|
+
const mlit = decoded.mlit ?? decoded;
|
|
271
|
+
return {
|
|
272
|
+
title: mlit.minm,
|
|
273
|
+
artist: mlit.asar,
|
|
274
|
+
albumArtist: mlit.asaa,
|
|
275
|
+
album: mlit.asal,
|
|
276
|
+
composer: mlit.ascp,
|
|
277
|
+
genre: mlit.asgn,
|
|
278
|
+
duration: mlit.astm !== void 0 ? mlit.astm / 1e3 : void 0,
|
|
279
|
+
trackNumber: mlit.astn,
|
|
280
|
+
trackCount: mlit.astc,
|
|
281
|
+
discNumber: mlit.asdn,
|
|
282
|
+
discCount: mlit.asdc,
|
|
283
|
+
year: mlit.asyr,
|
|
284
|
+
bitrate: mlit.asbr,
|
|
285
|
+
sampleRate: mlit.assr,
|
|
286
|
+
size: mlit.assz
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region src/encoding/nskeyedarchiver.ts
|
|
292
|
+
var nskeyedarchiver_exports = /* @__PURE__ */ __exportAll({
|
|
293
|
+
decode: () => decode$3,
|
|
294
|
+
decodeAsArray: () => decodeAsArray
|
|
295
|
+
});
|
|
296
|
+
/**
|
|
297
|
+
* Decodes an NSKeyedArchiver plist into plain objects. It resolves `CF$UID` references, turns
|
|
298
|
+
* NSArray and NSDictionary into arrays and objects, and drops the class metadata.
|
|
299
|
+
*
|
|
300
|
+
* @param archive - The parsed plist, with `$objects` and `$top`.
|
|
301
|
+
* @returns The root object, or null when the archive lacks `$objects` or `$top`.
|
|
302
|
+
*/
|
|
303
|
+
function decode$3(archive) {
|
|
304
|
+
const objects = archive?.["$objects"];
|
|
305
|
+
const top = archive?.["$top"];
|
|
306
|
+
if (!objects || !top) return null;
|
|
307
|
+
const resolve = (ref) => {
|
|
308
|
+
if (ref && typeof ref === "object" && "CF$UID" in ref) return resolve(objects[ref["CF$UID"]]);
|
|
309
|
+
if (ref === "$null") return null;
|
|
310
|
+
if (ref && typeof ref === "object") {
|
|
311
|
+
const obj = ref;
|
|
312
|
+
if (Array.isArray(obj["NS.keys"]) && Array.isArray(obj["NS.objects"])) {
|
|
313
|
+
const keys = obj["NS.keys"].map(resolve);
|
|
314
|
+
const values = obj["NS.objects"].map(resolve);
|
|
315
|
+
const result = {};
|
|
316
|
+
for (let i = 0; i < keys.length; i++) result[keys[i]] = values[i];
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
if (Array.isArray(obj["NS.objects"])) return obj["NS.objects"].map(resolve);
|
|
320
|
+
const result = {};
|
|
321
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
322
|
+
if (key === "$class" || key === "$classname" || key === "$classes") continue;
|
|
323
|
+
result[key] = resolve(value);
|
|
324
|
+
}
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
return ref;
|
|
328
|
+
};
|
|
329
|
+
return resolve(top.root ?? top);
|
|
330
|
+
}
|
|
331
|
+
/** Like {@link decode}, but wraps a root that is not an array in a single-element array. */
|
|
332
|
+
function decodeAsArray(archive) {
|
|
333
|
+
const root = decode$3(archive);
|
|
334
|
+
return Array.isArray(root) ? root : [root];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/encoding/ntp.ts
|
|
339
|
+
var ntp_exports = /* @__PURE__ */ __exportAll({
|
|
340
|
+
decode: () => decode$2,
|
|
341
|
+
encode: () => encode$2,
|
|
342
|
+
now: () => now,
|
|
343
|
+
parts: () => parts
|
|
344
|
+
});
|
|
345
|
+
/** Seconds between the NTP epoch (1900-01-01) and the Unix epoch (1970-01-01). */
|
|
346
|
+
const EPOCH$1 = 2208988800n;
|
|
347
|
+
/**
|
|
348
|
+
* Returns the wall-clock time as a 64-bit NTP timestamp: whole seconds since 1900 in the upper
|
|
349
|
+
* 32 bits, the fraction in the lower 32 bits.
|
|
350
|
+
*
|
|
351
|
+
* It reads `Date.now()` instead of a monotonic clock, because Apple devices expect NTP
|
|
352
|
+
* timestamps anchored to real time.
|
|
353
|
+
*/
|
|
354
|
+
function now() {
|
|
355
|
+
const nowMs = BigInt(Date.now());
|
|
356
|
+
const seconds = nowMs / 1000n;
|
|
357
|
+
const frac = nowMs - seconds * 1000n;
|
|
358
|
+
return seconds + EPOCH$1 << 32n | (frac << 32n) / 1000n;
|
|
359
|
+
}
|
|
360
|
+
/** Splits a 64-bit NTP timestamp into `[seconds, fraction]`, both 32-bit unsigned integers. */
|
|
361
|
+
function parts(ntp) {
|
|
362
|
+
return [Number(ntp >> 32n), Number(ntp & 4294967295n)];
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Decodes an NTP timing packet. The send timestamp (bytes 24 to 31) reads as 0 when the packet
|
|
366
|
+
* stops before it.
|
|
367
|
+
*
|
|
368
|
+
* @throws {RangeError} When the packet is shorter than 24 bytes.
|
|
369
|
+
*/
|
|
370
|
+
function decode$2(buffer) {
|
|
371
|
+
if (buffer.length < 24) throw new RangeError(`NTP packet too small: expected at least 24 bytes, got ${buffer.length}`);
|
|
372
|
+
return {
|
|
373
|
+
proto: buffer.readUInt8(0),
|
|
374
|
+
type: buffer.readUInt8(1),
|
|
375
|
+
seqno: buffer.readUInt16BE(2),
|
|
376
|
+
padding: buffer.readUInt32BE(4),
|
|
377
|
+
reftime_sec: buffer.readUInt32BE(8),
|
|
378
|
+
reftime_frac: buffer.readUInt32BE(12),
|
|
379
|
+
recvtime_sec: buffer.readUInt32BE(16),
|
|
380
|
+
recvtime_frac: buffer.readUInt32BE(20),
|
|
381
|
+
sendtime_sec: buffer.length >= 28 ? buffer.readUInt32BE(24) : 0,
|
|
382
|
+
sendtime_frac: buffer.length >= 32 ? buffer.readUInt32BE(28) : 0
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/** Encodes a 32-byte NTP timing packet. */
|
|
386
|
+
function encode$2(fields) {
|
|
387
|
+
const buffer = Buffer.allocUnsafe(32);
|
|
388
|
+
buffer.writeUInt8(fields.proto, 0);
|
|
389
|
+
buffer.writeUInt8(fields.type, 1);
|
|
390
|
+
buffer.writeUInt16BE(fields.seqno, 2);
|
|
391
|
+
buffer.writeUInt32BE(fields.padding, 4);
|
|
392
|
+
buffer.writeUInt32BE(fields.reftime_sec, 8);
|
|
393
|
+
buffer.writeUInt32BE(fields.reftime_frac, 12);
|
|
394
|
+
buffer.writeUInt32BE(fields.recvtime_sec, 16);
|
|
395
|
+
buffer.writeUInt32BE(fields.recvtime_frac, 20);
|
|
396
|
+
buffer.writeUInt32BE(fields.sendtime_sec, 24);
|
|
397
|
+
buffer.writeUInt32BE(fields.sendtime_frac, 28);
|
|
398
|
+
return buffer;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
//#endregion
|
|
402
|
+
//#region src/encoding/opack.ts
|
|
403
|
+
var opack_exports = /* @__PURE__ */ __exportAll({
|
|
404
|
+
decode: () => decode$1,
|
|
405
|
+
encode: () => encode$1,
|
|
406
|
+
float: () => float,
|
|
407
|
+
int: () => int,
|
|
408
|
+
sizedInteger: () => sizedInteger
|
|
409
|
+
});
|
|
410
|
+
/**
|
|
411
|
+
* The OPack tag bytes. A tag holds the type of the value that follows, and for small
|
|
412
|
+
* values also its inline length.
|
|
413
|
+
*/
|
|
414
|
+
const TAG = {
|
|
415
|
+
TRUE: 1,
|
|
416
|
+
FALSE: 2,
|
|
417
|
+
TERMINATOR: 3,
|
|
418
|
+
NULL: 4,
|
|
419
|
+
UUID: 5,
|
|
420
|
+
DATE: 6,
|
|
421
|
+
INT_BASE: 8,
|
|
422
|
+
INT_INLINE_MIN: 7,
|
|
423
|
+
INT_INLINE_MAX: 47,
|
|
424
|
+
INT_SIZED: 48,
|
|
425
|
+
INT_SIZED_MAX: 52,
|
|
426
|
+
FLOAT32: 53,
|
|
427
|
+
FLOAT64: 54,
|
|
428
|
+
STR_BASE: 64,
|
|
429
|
+
STR_MAX_INLINE: 96,
|
|
430
|
+
STR_SIZED: 97,
|
|
431
|
+
STR_SIZED_MAX: 100,
|
|
432
|
+
STR_NUL_TERMINATED: 111,
|
|
433
|
+
BYTES_BASE: 112,
|
|
434
|
+
BYTES_MAX_INLINE: 144,
|
|
435
|
+
BYTES_SIZED: 145,
|
|
436
|
+
BYTES_SIZED_MAX: 148,
|
|
437
|
+
BYTES_CHUNKED: 159,
|
|
438
|
+
REF_BASE: 160,
|
|
439
|
+
REF_MAX_INLINE: 192,
|
|
440
|
+
REF_SIZED: 193,
|
|
441
|
+
REF_SIZED_MAX: 196,
|
|
442
|
+
ARRAY_BASE: 208,
|
|
443
|
+
ARRAY_VARIABLE: 223,
|
|
444
|
+
DICT_BASE: 224,
|
|
445
|
+
DICT_VARIABLE: 239
|
|
446
|
+
};
|
|
447
|
+
/** The widths in bytes of the sized integers 0x30 to 0x34. */
|
|
448
|
+
const INT_WIDTHS = [
|
|
449
|
+
1,
|
|
450
|
+
2,
|
|
451
|
+
4,
|
|
452
|
+
8,
|
|
453
|
+
16
|
|
454
|
+
];
|
|
455
|
+
/** The widths in bytes of the length of the sized strings 0x61 to 0x64 and bytes 0x91 to 0x94. */
|
|
456
|
+
const LENGTH_WIDTHS = [
|
|
457
|
+
1,
|
|
458
|
+
2,
|
|
459
|
+
4,
|
|
460
|
+
8
|
|
461
|
+
];
|
|
462
|
+
/** The widths in bytes of the index of the sized references 0xC1 to 0xC4. */
|
|
463
|
+
const REF_WIDTHS = [
|
|
464
|
+
1,
|
|
465
|
+
2,
|
|
466
|
+
3,
|
|
467
|
+
4
|
|
468
|
+
];
|
|
469
|
+
/** The deepest a value may sit in nested arrays and dictionaries; devices reject anything deeper. */
|
|
470
|
+
const MAX_DEPTH$1 = 32;
|
|
471
|
+
/** Dates travel as seconds since 2001-01-01 UTC; this is that moment in milliseconds since 1970. */
|
|
472
|
+
const DATE_EPOCH_MS = 9783072e5;
|
|
473
|
+
const textDecoder = new TextDecoder();
|
|
474
|
+
const textEncoder = new TextEncoder();
|
|
475
|
+
/**
|
|
476
|
+
* A number that OPack encodes as FLOAT64. A plain number with an integer value
|
|
477
|
+
* would encode as an OPack integer.
|
|
478
|
+
*/
|
|
479
|
+
var Float = class {
|
|
480
|
+
get value() {
|
|
481
|
+
return this.#value;
|
|
482
|
+
}
|
|
483
|
+
#value;
|
|
484
|
+
constructor(value) {
|
|
485
|
+
this.#value = value;
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
/**
|
|
489
|
+
* A number that OPack encodes as an integer in the smallest width that holds it.
|
|
490
|
+
*/
|
|
491
|
+
var Integer = class {
|
|
492
|
+
get value() {
|
|
493
|
+
return this.#value;
|
|
494
|
+
}
|
|
495
|
+
#value;
|
|
496
|
+
constructor(value) {
|
|
497
|
+
this.#value = value;
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
/**
|
|
501
|
+
* A signed integer with a fixed width on the wire. The decoder returns one for every sized
|
|
502
|
+
* integer, so encoding it again writes the same width.
|
|
503
|
+
*/
|
|
504
|
+
var SizedInteger = class {
|
|
505
|
+
/** The width of the integer on the wire in bytes: 1, 2, 4, 8 or 16. */
|
|
506
|
+
get size() {
|
|
507
|
+
return this.#size;
|
|
508
|
+
}
|
|
509
|
+
/** The value; a bigint when it lies outside the safe integer range of a number. */
|
|
510
|
+
get value() {
|
|
511
|
+
return this.#value;
|
|
512
|
+
}
|
|
513
|
+
#size;
|
|
514
|
+
#value;
|
|
515
|
+
constructor(value, size) {
|
|
516
|
+
this.#size = size;
|
|
517
|
+
this.#value = value;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Returns the value, so the integer works in arithmetic and comparisons.
|
|
521
|
+
*/
|
|
522
|
+
valueOf() {
|
|
523
|
+
return this.#value;
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
/**
|
|
527
|
+
* Wraps a number so OPack encodes it as FLOAT64, also when it is a whole number.
|
|
528
|
+
*/
|
|
529
|
+
function float(value) {
|
|
530
|
+
return new Float(value);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Wraps an integer so OPack encodes it as an integer in the smallest width that holds it.
|
|
534
|
+
*
|
|
535
|
+
* @throws RangeError if the value is not an integer.
|
|
536
|
+
*/
|
|
537
|
+
function int(value) {
|
|
538
|
+
if (typeof value === "number" && !Number.isInteger(value)) throw new RangeError(`OPack integer ${value} is not an integer`);
|
|
539
|
+
return new Integer(value);
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Wraps an integer so OPack encodes it with a fixed width.
|
|
543
|
+
*
|
|
544
|
+
* @param size - The width in bytes: 1, 2, 4, 8 or 16. The value must fit as a signed integer.
|
|
545
|
+
* @throws RangeError if the width is not one of these or the value does not fit in it.
|
|
546
|
+
*/
|
|
547
|
+
function sizedInteger(value, size) {
|
|
548
|
+
if (!INT_WIDTHS.includes(size)) throw new RangeError(`OPack integer width ${size} is not 1, 2, 4, 8 or 16`);
|
|
549
|
+
if (typeof value === "number" && !Number.isInteger(value)) throw new RangeError(`OPack integer ${value} is not an integer`);
|
|
550
|
+
if (!fitsSigned(BigInt(value), size)) throw new RangeError(`OPack integer ${value} does not fit in ${size} bytes`);
|
|
551
|
+
return new SizedInteger(value, size);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Decodes OPack bytes into a value. Inline integers come back as numbers, sized integers as
|
|
555
|
+
* {@link sizedInteger} values, dates as `Date`, UUIDs and byte strings as `Uint8Array`.
|
|
556
|
+
*
|
|
557
|
+
* @throws TypeError if the buffer ends early, nests deeper than 32 containers, refers to a
|
|
558
|
+
* value that does not exist or holds a tag OPack does not define.
|
|
559
|
+
*/
|
|
560
|
+
function decode$1(data) {
|
|
561
|
+
return _unpackAt(data, 0, [], 0).value;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Encodes a value as OPack. It takes null, booleans, numbers, bigints, strings, bytes, dates,
|
|
565
|
+
* arrays, plain objects and the wrappers {@link float}, {@link int} and {@link sizedInteger}.
|
|
566
|
+
* A repeated string, byte string of two bytes or more, number outside -1 to 39 or date becomes
|
|
567
|
+
* a reference to its first occurrence; arrays and objects are always written in full.
|
|
568
|
+
*
|
|
569
|
+
* @throws TypeError if the value has an unsupported type or nests deeper than 32 containers.
|
|
570
|
+
* @throws RangeError if an integer does not fit in 128 bits or a date is invalid.
|
|
571
|
+
*/
|
|
572
|
+
function encode$1(data) {
|
|
573
|
+
return _pack(data, {
|
|
574
|
+
values: [],
|
|
575
|
+
index: /* @__PURE__ */ new Map()
|
|
576
|
+
}, 0);
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Joins byte arrays into one.
|
|
580
|
+
*/
|
|
581
|
+
function concat$1(arrays) {
|
|
582
|
+
const total = arrays.reduce((sum, array) => sum + array.length, 0);
|
|
583
|
+
const out = new Uint8Array(total);
|
|
584
|
+
let offset = 0;
|
|
585
|
+
for (const array of arrays) {
|
|
586
|
+
out.set(array, offset);
|
|
587
|
+
offset += array.length;
|
|
588
|
+
}
|
|
589
|
+
return out;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Returns a byte array that holds one byte.
|
|
593
|
+
*/
|
|
594
|
+
function u8(byte) {
|
|
595
|
+
return Uint8Array.of(byte);
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Writes an integer as `byteLen` little-endian bytes, in two's complement when negative.
|
|
599
|
+
*/
|
|
600
|
+
function intToLEBytes(value, byteLen) {
|
|
601
|
+
const out = new Uint8Array(byteLen);
|
|
602
|
+
let remaining = BigInt(value);
|
|
603
|
+
for (let i = 0; i < byteLen; i++) {
|
|
604
|
+
out[i] = Number(remaining & 255n);
|
|
605
|
+
remaining >>= 8n;
|
|
606
|
+
}
|
|
607
|
+
return out;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Whether a value fits in `size` bytes as a signed integer.
|
|
611
|
+
*/
|
|
612
|
+
function fitsSigned(value, size) {
|
|
613
|
+
const limit = 1n << BigInt(size * 8 - 1);
|
|
614
|
+
return value >= -limit && value < limit;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Whether an integer has an inline tag (-1 to 39). Such integers never join the object list,
|
|
618
|
+
* also when they are written in a fixed width.
|
|
619
|
+
*/
|
|
620
|
+
function isInlineInteger(value) {
|
|
621
|
+
return value >= -1 && value <= 39;
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Returns an integer as a number when that is exact, otherwise as a bigint.
|
|
625
|
+
*/
|
|
626
|
+
function toInteger(value) {
|
|
627
|
+
return value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : value;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Checks that `length` bytes from `offset` lie within the buffer.
|
|
631
|
+
*
|
|
632
|
+
* @throws TypeError if they run past the end.
|
|
633
|
+
*/
|
|
634
|
+
function ensureAvailable(data, offset, length) {
|
|
635
|
+
if (length < 0 || offset + length > data.length) throw new TypeError("Truncated OPack value");
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Whether the byte at `offset` ends a container or chunked byte string.
|
|
639
|
+
*
|
|
640
|
+
* @throws TypeError if the buffer ends before it.
|
|
641
|
+
*/
|
|
642
|
+
function isTerminator(data, offset) {
|
|
643
|
+
ensureAvailable(data, offset, 1);
|
|
644
|
+
return data[offset] === TAG.TERMINATOR;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Reads a little-endian unsigned length or index of `width` bytes.
|
|
648
|
+
*
|
|
649
|
+
* @throws TypeError if it runs past the end of the buffer or exceeds the safe integer range.
|
|
650
|
+
*/
|
|
651
|
+
function readUnsigned(data, offset, width) {
|
|
652
|
+
ensureAvailable(data, offset, width);
|
|
653
|
+
let value = 0n;
|
|
654
|
+
for (let i = width - 1; i >= 0; i--) value = value << 8n | BigInt(data[offset + i]);
|
|
655
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER)) throw new TypeError("OPack length out of range");
|
|
656
|
+
return Number(value);
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Reads a little-endian signed integer of `width` bytes.
|
|
660
|
+
*/
|
|
661
|
+
function readSigned(data, offset, width) {
|
|
662
|
+
ensureAvailable(data, offset, width);
|
|
663
|
+
let value = 0n;
|
|
664
|
+
for (let i = width - 1; i >= 0; i--) value = value << 8n | BigInt(data[offset + i]);
|
|
665
|
+
return BigInt.asIntN(width * 8, value);
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Packs an integer in the smallest width that holds it.
|
|
669
|
+
*
|
|
670
|
+
* @throws RangeError if it does not fit in 128 bits.
|
|
671
|
+
*/
|
|
672
|
+
function packInteger(value) {
|
|
673
|
+
if (isInlineInteger(value)) return u8(TAG.INT_BASE + Number(value));
|
|
674
|
+
const size = INT_WIDTHS.find((width) => fitsSigned(value, width));
|
|
675
|
+
if (size === void 0) throw new RangeError(`OPack integer ${value} does not fit in 128 bits`);
|
|
676
|
+
return packSizedInteger(value, size);
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Packs an integer in a fixed width.
|
|
680
|
+
*/
|
|
681
|
+
function packSizedInteger(value, size) {
|
|
682
|
+
return concat$1([u8(TAG.INT_SIZED + INT_WIDTHS.indexOf(size)), intToLEBytes(value, size)]);
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Packs a string or byte string: inline up to 32 bytes, otherwise with a length of 1, 2, 4 or
|
|
686
|
+
* 8 bytes after the first sized tag.
|
|
687
|
+
*/
|
|
688
|
+
function packWithLength(inlineBase, sizedBase, payload) {
|
|
689
|
+
const length = payload.length;
|
|
690
|
+
if (length <= 32) return concat$1([u8(inlineBase + length), payload]);
|
|
691
|
+
const widthIndex = length <= 255 ? 0 : length <= 65535 ? 1 : length <= 4294967295 ? 2 : 3;
|
|
692
|
+
const width = LENGTH_WIDTHS[widthIndex];
|
|
693
|
+
return concat$1([
|
|
694
|
+
u8(sizedBase + widthIndex),
|
|
695
|
+
intToLEBytes(length, width),
|
|
696
|
+
payload
|
|
697
|
+
]);
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Packs a reference to the value at `index` in the object list.
|
|
701
|
+
*
|
|
702
|
+
* @throws RangeError if the index does not fit in 4 bytes.
|
|
703
|
+
*/
|
|
704
|
+
function packReference(index) {
|
|
705
|
+
if (index <= TAG.REF_MAX_INLINE - TAG.REF_BASE) return u8(TAG.REF_BASE + index);
|
|
706
|
+
const widthIndex = REF_WIDTHS.findIndex((width) => index < 2 ** (width * 8));
|
|
707
|
+
if (widthIndex < 0) throw new RangeError(`OPack reference index ${index} does not fit in 4 bytes`);
|
|
708
|
+
return concat$1([u8(TAG.REF_SIZED + widthIndex), intToLEBytes(index, REF_WIDTHS[widthIndex])]);
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Packs the items of an array or the keys and values of a dictionary behind their tag. Up to
|
|
712
|
+
* 14 entries the tag holds the count, from 15 a terminator ends the list.
|
|
713
|
+
*/
|
|
714
|
+
function packContainer(base, variable, count, parts) {
|
|
715
|
+
if (count < 15) return concat$1([u8(base + count), ...parts]);
|
|
716
|
+
return concat$1([
|
|
717
|
+
u8(variable),
|
|
718
|
+
...parts,
|
|
719
|
+
u8(TAG.TERMINATOR)
|
|
720
|
+
]);
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Packs a value and its children, without looking at the object list for the value itself.
|
|
724
|
+
*
|
|
725
|
+
* @throws TypeError if the value has an unsupported type or nests too deep.
|
|
726
|
+
* @throws RangeError if an integer does not fit in 128 bits or a date is invalid.
|
|
727
|
+
*/
|
|
728
|
+
function _packValue(data, objectList, depth) {
|
|
729
|
+
if (data === null || data === void 0) return {
|
|
730
|
+
packed: u8(TAG.NULL),
|
|
731
|
+
shareable: false
|
|
732
|
+
};
|
|
733
|
+
if (typeof data === "boolean") return {
|
|
734
|
+
packed: u8(data ? TAG.TRUE : TAG.FALSE),
|
|
735
|
+
shareable: false
|
|
736
|
+
};
|
|
737
|
+
if (data instanceof Float || typeof data === "number" && !Number.isInteger(data)) {
|
|
738
|
+
const packed = new Uint8Array(9);
|
|
739
|
+
packed[0] = TAG.FLOAT64;
|
|
740
|
+
new DataView(packed.buffer).setFloat64(1, data instanceof Float ? data.value : data, true);
|
|
741
|
+
return {
|
|
742
|
+
packed,
|
|
743
|
+
shareable: true
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
if (typeof data === "number") {
|
|
747
|
+
const value = BigInt(data);
|
|
748
|
+
return {
|
|
749
|
+
packed: value < 0n && fitsSigned(value, 8) ? packSizedInteger(value, 8) : packInteger(value),
|
|
750
|
+
shareable: !isInlineInteger(value)
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
if (typeof data === "bigint" || data instanceof Integer) {
|
|
754
|
+
const value = BigInt(data instanceof Integer ? data.value : data);
|
|
755
|
+
return {
|
|
756
|
+
packed: packInteger(value),
|
|
757
|
+
shareable: !isInlineInteger(value)
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
if (data instanceof SizedInteger) return {
|
|
761
|
+
packed: packSizedInteger(data.value, data.size),
|
|
762
|
+
shareable: !isInlineInteger(data.value)
|
|
763
|
+
};
|
|
764
|
+
if (typeof data === "string") {
|
|
765
|
+
const packed = packWithLength(TAG.STR_BASE, TAG.STR_SIZED, textEncoder.encode(data));
|
|
766
|
+
return {
|
|
767
|
+
packed,
|
|
768
|
+
shareable: packed.length > 1
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
if (data instanceof Uint8Array) return {
|
|
772
|
+
packed: packWithLength(TAG.BYTES_BASE, TAG.BYTES_SIZED, data),
|
|
773
|
+
shareable: data.length >= 2
|
|
774
|
+
};
|
|
775
|
+
if (data instanceof Date) {
|
|
776
|
+
const time = data.getTime();
|
|
777
|
+
if (Number.isNaN(time)) throw new RangeError("OPack cannot encode an invalid date");
|
|
778
|
+
const packed = new Uint8Array(9);
|
|
779
|
+
packed[0] = TAG.DATE;
|
|
780
|
+
new DataView(packed.buffer).setFloat64(1, (time - DATE_EPOCH_MS) / 1e3, true);
|
|
781
|
+
return {
|
|
782
|
+
packed,
|
|
783
|
+
shareable: true
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
if (Array.isArray(data)) {
|
|
787
|
+
const parts = data.map((item) => _pack(item, objectList, depth + 1));
|
|
788
|
+
return {
|
|
789
|
+
packed: packContainer(TAG.ARRAY_BASE, TAG.ARRAY_VARIABLE, data.length, parts),
|
|
790
|
+
shareable: false
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
if (typeof data === "object") {
|
|
794
|
+
const keys = Object.keys(data);
|
|
795
|
+
const parts = [];
|
|
796
|
+
for (const key of keys) parts.push(_pack(key, objectList, depth + 1), _pack(data[key], objectList, depth + 1));
|
|
797
|
+
return {
|
|
798
|
+
packed: packContainer(TAG.DICT_BASE, TAG.DICT_VARIABLE, keys.length, parts),
|
|
799
|
+
shareable: false
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
throw new TypeError(`OPack cannot encode a value of type ${typeof data}`);
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Packs a value and its children. A shareable value already in the object list becomes a
|
|
806
|
+
* reference to it; the first occurrence joins the list.
|
|
807
|
+
*
|
|
808
|
+
* @throws TypeError if the value has an unsupported type or nests too deep.
|
|
809
|
+
* @throws RangeError if an integer does not fit in 128 bits or a date is invalid.
|
|
810
|
+
*/
|
|
811
|
+
function _pack(data, objectList, depth) {
|
|
812
|
+
if (depth > MAX_DEPTH$1) throw new TypeError(`OPack nesting deeper than ${MAX_DEPTH$1} containers`);
|
|
813
|
+
const { packed, shareable } = _packValue(data, objectList, depth);
|
|
814
|
+
if (!shareable) return packed;
|
|
815
|
+
let hash = 2166136261;
|
|
816
|
+
for (const byte of packed) hash = Math.imul(hash ^ byte, 16777619);
|
|
817
|
+
const candidates = objectList.index.get(hash);
|
|
818
|
+
const existing = candidates?.find((index) => {
|
|
819
|
+
const value = objectList.values[index];
|
|
820
|
+
return value.length === packed.length && value.every((byte, offset) => byte === packed[offset]);
|
|
821
|
+
});
|
|
822
|
+
if (existing !== void 0) return packReference(existing);
|
|
823
|
+
const index = objectList.values.length;
|
|
824
|
+
objectList.values.push(packed);
|
|
825
|
+
if (candidates) candidates.push(index);
|
|
826
|
+
else objectList.index.set(hash, [index]);
|
|
827
|
+
return packed;
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Unpacks the items of a byte string in chunks (0x9F), which ends at a terminator.
|
|
831
|
+
*
|
|
832
|
+
* @throws TypeError if a chunk is not a byte string or the terminator is missing.
|
|
833
|
+
*/
|
|
834
|
+
function _unpackChunks(data, offset) {
|
|
835
|
+
const chunks = [];
|
|
836
|
+
let pos = offset;
|
|
837
|
+
while (!isTerminator(data, pos)) {
|
|
838
|
+
const tag = data[pos];
|
|
839
|
+
let length;
|
|
840
|
+
let start;
|
|
841
|
+
if (tag >= TAG.BYTES_BASE && tag <= TAG.BYTES_MAX_INLINE) {
|
|
842
|
+
length = tag - TAG.BYTES_BASE;
|
|
843
|
+
start = pos + 1;
|
|
844
|
+
} else if (tag >= TAG.BYTES_SIZED && tag <= TAG.BYTES_SIZED_MAX) {
|
|
845
|
+
const width = LENGTH_WIDTHS[tag - TAG.BYTES_SIZED];
|
|
846
|
+
length = readUnsigned(data, pos + 1, width);
|
|
847
|
+
start = pos + 1 + width;
|
|
848
|
+
} else throw new TypeError(`Invalid OPack data chunk 0x${tag.toString(16)}`);
|
|
849
|
+
ensureAvailable(data, start, length);
|
|
850
|
+
chunks.push(data.subarray(start, start + length));
|
|
851
|
+
pos = start + length;
|
|
852
|
+
}
|
|
853
|
+
return {
|
|
854
|
+
value: concat$1(chunks),
|
|
855
|
+
offset: pos + 1
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Unpacks the OPack value at `offset`. Strings, byte strings of two bytes or more, numbers
|
|
860
|
+
* outside -1 to 39, dates and UUIDs join the object list in the order they appear, so later
|
|
861
|
+
* references can point to them. Arrays, dictionaries and references never join it.
|
|
862
|
+
*
|
|
863
|
+
* @throws TypeError if the buffer ends early, nests too deep, refers to a value that does not
|
|
864
|
+
* exist or holds a tag OPack does not define.
|
|
865
|
+
*/
|
|
866
|
+
function _unpackAt(data, offset, objectList, depth) {
|
|
867
|
+
if (depth > MAX_DEPTH$1) throw new TypeError(`OPack nesting deeper than ${MAX_DEPTH$1} containers`);
|
|
868
|
+
ensureAvailable(data, offset, 1);
|
|
869
|
+
const tag = data[offset];
|
|
870
|
+
let shareable = false;
|
|
871
|
+
let value;
|
|
872
|
+
let newOffset;
|
|
873
|
+
if (tag === TAG.TRUE) {
|
|
874
|
+
value = true;
|
|
875
|
+
newOffset = offset + 1;
|
|
876
|
+
} else if (tag === TAG.FALSE) {
|
|
877
|
+
value = false;
|
|
878
|
+
newOffset = offset + 1;
|
|
879
|
+
} else if (tag === TAG.NULL) {
|
|
880
|
+
value = null;
|
|
881
|
+
newOffset = offset + 1;
|
|
882
|
+
} else if (tag === TAG.UUID) {
|
|
883
|
+
ensureAvailable(data, offset + 1, 16);
|
|
884
|
+
value = data.subarray(offset + 1, offset + 17);
|
|
885
|
+
newOffset = offset + 17;
|
|
886
|
+
shareable = true;
|
|
887
|
+
} else if (tag === TAG.DATE) {
|
|
888
|
+
ensureAvailable(data, offset + 1, 8);
|
|
889
|
+
const seconds = new DataView(data.buffer, data.byteOffset + offset + 1, 8).getFloat64(0, true);
|
|
890
|
+
value = /* @__PURE__ */ new Date(DATE_EPOCH_MS + seconds * 1e3);
|
|
891
|
+
newOffset = offset + 9;
|
|
892
|
+
shareable = true;
|
|
893
|
+
} else if (tag >= TAG.INT_INLINE_MIN && tag <= TAG.INT_INLINE_MAX) {
|
|
894
|
+
value = tag - TAG.INT_BASE;
|
|
895
|
+
newOffset = offset + 1;
|
|
896
|
+
} else if (tag >= TAG.INT_SIZED && tag <= TAG.INT_SIZED_MAX) {
|
|
897
|
+
const size = INT_WIDTHS[tag - TAG.INT_SIZED];
|
|
898
|
+
const integer = readSigned(data, offset + 1, size);
|
|
899
|
+
value = sizedInteger(toInteger(integer), size);
|
|
900
|
+
newOffset = offset + 1 + size;
|
|
901
|
+
shareable = !isInlineInteger(integer);
|
|
902
|
+
} else if (tag === TAG.FLOAT32) {
|
|
903
|
+
ensureAvailable(data, offset + 1, 4);
|
|
904
|
+
value = new DataView(data.buffer, data.byteOffset + offset + 1, 4).getFloat32(0, true);
|
|
905
|
+
newOffset = offset + 5;
|
|
906
|
+
shareable = true;
|
|
907
|
+
} else if (tag === TAG.FLOAT64) {
|
|
908
|
+
ensureAvailable(data, offset + 1, 8);
|
|
909
|
+
value = new DataView(data.buffer, data.byteOffset + offset + 1, 8).getFloat64(0, true);
|
|
910
|
+
newOffset = offset + 9;
|
|
911
|
+
shareable = true;
|
|
912
|
+
} else if (tag >= TAG.STR_BASE && tag <= TAG.STR_MAX_INLINE) {
|
|
913
|
+
const length = tag - TAG.STR_BASE;
|
|
914
|
+
ensureAvailable(data, offset + 1, length);
|
|
915
|
+
value = textDecoder.decode(data.subarray(offset + 1, offset + 1 + length));
|
|
916
|
+
newOffset = offset + 1 + length;
|
|
917
|
+
shareable = length > 0;
|
|
918
|
+
} else if (tag >= TAG.STR_SIZED && tag <= TAG.STR_SIZED_MAX) {
|
|
919
|
+
const width = LENGTH_WIDTHS[tag - TAG.STR_SIZED];
|
|
920
|
+
const length = readUnsigned(data, offset + 1, width);
|
|
921
|
+
const start = offset + 1 + width;
|
|
922
|
+
ensureAvailable(data, start, length);
|
|
923
|
+
value = textDecoder.decode(data.subarray(start, start + length));
|
|
924
|
+
newOffset = start + length;
|
|
925
|
+
shareable = length > 0;
|
|
926
|
+
} else if (tag === TAG.STR_NUL_TERMINATED) {
|
|
927
|
+
const end = data.indexOf(0, offset + 1);
|
|
928
|
+
if (end < 0) throw new TypeError("Truncated OPack value");
|
|
929
|
+
value = textDecoder.decode(data.subarray(offset + 1, end));
|
|
930
|
+
newOffset = end + 1;
|
|
931
|
+
shareable = end > offset + 1;
|
|
932
|
+
} else if (tag >= TAG.BYTES_BASE && tag <= TAG.BYTES_MAX_INLINE) {
|
|
933
|
+
const length = tag - TAG.BYTES_BASE;
|
|
934
|
+
ensureAvailable(data, offset + 1, length);
|
|
935
|
+
value = data.subarray(offset + 1, offset + 1 + length);
|
|
936
|
+
newOffset = offset + 1 + length;
|
|
937
|
+
shareable = length >= 2;
|
|
938
|
+
} else if (tag >= TAG.BYTES_SIZED && tag <= TAG.BYTES_SIZED_MAX) {
|
|
939
|
+
const width = LENGTH_WIDTHS[tag - TAG.BYTES_SIZED];
|
|
940
|
+
const length = readUnsigned(data, offset + 1, width);
|
|
941
|
+
const start = offset + 1 + width;
|
|
942
|
+
ensureAvailable(data, start, length);
|
|
943
|
+
value = data.subarray(start, start + length);
|
|
944
|
+
newOffset = start + length;
|
|
945
|
+
shareable = length >= 2;
|
|
946
|
+
} else if (tag === TAG.BYTES_CHUNKED) {
|
|
947
|
+
const result = _unpackChunks(data, offset + 1);
|
|
948
|
+
value = result.value;
|
|
949
|
+
newOffset = result.offset;
|
|
950
|
+
shareable = value.length >= 2;
|
|
951
|
+
} else if (tag >= TAG.REF_BASE && tag <= TAG.REF_SIZED_MAX) {
|
|
952
|
+
const inline = tag <= TAG.REF_MAX_INLINE;
|
|
953
|
+
const width = inline ? 0 : REF_WIDTHS[tag - TAG.REF_SIZED];
|
|
954
|
+
const index = inline ? tag - TAG.REF_BASE : readUnsigned(data, offset + 1, width);
|
|
955
|
+
if (index >= objectList.length) throw new TypeError(`OPack reference index ${index} out of range`);
|
|
956
|
+
value = objectList[index];
|
|
957
|
+
newOffset = offset + 1 + width;
|
|
958
|
+
} else if ((tag & 240) === TAG.ARRAY_BASE) {
|
|
959
|
+
const items = [];
|
|
960
|
+
let pos = offset + 1;
|
|
961
|
+
if (tag === TAG.ARRAY_VARIABLE) {
|
|
962
|
+
while (!isTerminator(data, pos)) {
|
|
963
|
+
const result = _unpackAt(data, pos, objectList, depth + 1);
|
|
964
|
+
items.push(result.value);
|
|
965
|
+
pos = result.offset;
|
|
966
|
+
}
|
|
967
|
+
pos++;
|
|
968
|
+
} else for (let i = 0; i < (tag & 15); i++) {
|
|
969
|
+
const result = _unpackAt(data, pos, objectList, depth + 1);
|
|
970
|
+
items.push(result.value);
|
|
971
|
+
pos = result.offset;
|
|
972
|
+
}
|
|
973
|
+
value = items;
|
|
974
|
+
newOffset = pos;
|
|
975
|
+
} else if ((tag & 240) === TAG.DICT_BASE) {
|
|
976
|
+
const dictionary = {};
|
|
977
|
+
let pos = offset + 1;
|
|
978
|
+
const unpackEntry = () => {
|
|
979
|
+
const keyResult = _unpackAt(data, pos, objectList, depth + 1);
|
|
980
|
+
const valueResult = _unpackAt(data, keyResult.offset, objectList, depth + 1);
|
|
981
|
+
Object.defineProperty(dictionary, keyResult.value, {
|
|
982
|
+
value: valueResult.value,
|
|
983
|
+
enumerable: true,
|
|
984
|
+
configurable: true,
|
|
985
|
+
writable: true
|
|
986
|
+
});
|
|
987
|
+
pos = valueResult.offset;
|
|
988
|
+
};
|
|
989
|
+
if (tag === TAG.DICT_VARIABLE) {
|
|
990
|
+
while (!isTerminator(data, pos)) unpackEntry();
|
|
991
|
+
pos++;
|
|
992
|
+
} else for (let i = 0; i < (tag & 15); i++) unpackEntry();
|
|
993
|
+
value = dictionary;
|
|
994
|
+
newOffset = pos;
|
|
995
|
+
} else throw new TypeError(`Unsupported OPack tag 0x${tag.toString(16)}`);
|
|
996
|
+
if (shareable) objectList.push(value);
|
|
997
|
+
return {
|
|
998
|
+
value,
|
|
999
|
+
offset: newOffset
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
//#endregion
|
|
1004
|
+
//#region ../../node_modules/.bun/@plist+common@1.1.0/node_modules/@plist/common/lib/esm/constants.js
|
|
1005
|
+
const EPOCH = 9783072e5;
|
|
1006
|
+
const HEADER_BINARY = "bplist00";
|
|
1007
|
+
var PlistFormat;
|
|
1008
|
+
(function(PlistFormat) {
|
|
1009
|
+
PlistFormat[PlistFormat["BINARY"] = 0] = "BINARY";
|
|
1010
|
+
PlistFormat[PlistFormat["XML"] = 1] = "XML";
|
|
1011
|
+
PlistFormat[PlistFormat["OPENSTEP"] = 2] = "OPENSTEP";
|
|
1012
|
+
})(PlistFormat || (PlistFormat = {}));
|
|
1013
|
+
|
|
1014
|
+
//#endregion
|
|
1015
|
+
//#region ../../node_modules/.bun/@plist+binary.serialize@1.1.0/node_modules/@plist/binary.serialize/lib/esm/index.js
|
|
1016
|
+
const encoder = new TextEncoder();
|
|
1017
|
+
const nullBytes = new Uint8Array([
|
|
1018
|
+
0,
|
|
1019
|
+
0,
|
|
1020
|
+
0,
|
|
1021
|
+
0,
|
|
1022
|
+
0,
|
|
1023
|
+
0
|
|
1024
|
+
]);
|
|
1025
|
+
const fromHexString = (hexString) => Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
|
|
1026
|
+
const isUID = (value) => !!value && typeof value === "object" && Object.keys(value).length == 1 && typeof value.CF$UID === "number";
|
|
1027
|
+
const toUTF16 = (string) => {
|
|
1028
|
+
const buf = /* @__PURE__ */ new ArrayBuffer(string.length * 2);
|
|
1029
|
+
const bufView = new Uint16Array(buf);
|
|
1030
|
+
for (let i = 0, strLen = string.length; i < strLen; i++) bufView[i] = string.charCodeAt(i);
|
|
1031
|
+
return new Uint8Array(buf);
|
|
1032
|
+
};
|
|
1033
|
+
const concat = (first, second) => {
|
|
1034
|
+
const third = new Uint8Array(first.length + second.length);
|
|
1035
|
+
third.set(first);
|
|
1036
|
+
third.set(second, first.length);
|
|
1037
|
+
return third;
|
|
1038
|
+
};
|
|
1039
|
+
const writeUInt = (buffer, int, size) => {
|
|
1040
|
+
const output = new Uint8Array(buffer.length + size);
|
|
1041
|
+
const dataView = new DataView(output.buffer);
|
|
1042
|
+
output.set(buffer);
|
|
1043
|
+
switch (size) {
|
|
1044
|
+
case 1:
|
|
1045
|
+
dataView.setUint8(buffer.length, Number(int));
|
|
1046
|
+
break;
|
|
1047
|
+
case 2:
|
|
1048
|
+
dataView.setUint16(buffer.length, Number(int), false);
|
|
1049
|
+
break;
|
|
1050
|
+
case 4:
|
|
1051
|
+
dataView.setUint32(buffer.length, Number(int), false);
|
|
1052
|
+
break;
|
|
1053
|
+
case 8:
|
|
1054
|
+
dataView.setBigUint64(buffer.length, BigInt(int), false);
|
|
1055
|
+
break;
|
|
1056
|
+
default: throw new Error("Unsupported int size");
|
|
1057
|
+
}
|
|
1058
|
+
return output;
|
|
1059
|
+
};
|
|
1060
|
+
const writeInt = (buffer, int, size) => {
|
|
1061
|
+
const output = new Uint8Array(buffer.length + size);
|
|
1062
|
+
const dataView = new DataView(output.buffer);
|
|
1063
|
+
output.set(buffer);
|
|
1064
|
+
switch (size) {
|
|
1065
|
+
case 1:
|
|
1066
|
+
dataView.setInt8(buffer.length, Number(int));
|
|
1067
|
+
break;
|
|
1068
|
+
case 2:
|
|
1069
|
+
dataView.setInt16(buffer.length, Number(int), false);
|
|
1070
|
+
break;
|
|
1071
|
+
case 4:
|
|
1072
|
+
dataView.setInt32(buffer.length, Number(int), false);
|
|
1073
|
+
break;
|
|
1074
|
+
case 8:
|
|
1075
|
+
dataView.setBigInt64(buffer.length, BigInt(int), false);
|
|
1076
|
+
break;
|
|
1077
|
+
default: throw new Error("Unsupported int size");
|
|
1078
|
+
}
|
|
1079
|
+
return output;
|
|
1080
|
+
};
|
|
1081
|
+
const writeDouble = (buffer, double) => {
|
|
1082
|
+
const output = new Uint8Array(buffer.length + 8);
|
|
1083
|
+
const dataView = new DataView(output.buffer);
|
|
1084
|
+
output.set(buffer);
|
|
1085
|
+
dataView.setFloat64(buffer.length, double);
|
|
1086
|
+
return output;
|
|
1087
|
+
};
|
|
1088
|
+
const serialize = (value) => {
|
|
1089
|
+
let buffer = encoder.encode(HEADER_BINARY);
|
|
1090
|
+
if (value instanceof Array && value.length === 1) value = value[0];
|
|
1091
|
+
let entries = toEntries(value);
|
|
1092
|
+
const idSizeInBytes = computeIdSizeInBytes(entries.length);
|
|
1093
|
+
const offsets = [];
|
|
1094
|
+
let offsetSizeInBytes;
|
|
1095
|
+
let offsetTableOffset;
|
|
1096
|
+
updateEntryIds();
|
|
1097
|
+
entries.forEach((entry, entryIdx) => {
|
|
1098
|
+
offsets[entryIdx] = buffer.byteLength;
|
|
1099
|
+
if (typeof entry === "undefined" || entry === null) buffer = writeUInt(buffer, 0, 1);
|
|
1100
|
+
else write(entry);
|
|
1101
|
+
});
|
|
1102
|
+
writeOffsetTable();
|
|
1103
|
+
writeTrailer();
|
|
1104
|
+
return buffer.buffer;
|
|
1105
|
+
function updateEntryIds() {
|
|
1106
|
+
const strings = {};
|
|
1107
|
+
let entryId = 0;
|
|
1108
|
+
entries.forEach((entry) => {
|
|
1109
|
+
if (entry.id) return;
|
|
1110
|
+
if (typeof entry.value === "string") if (strings.hasOwnProperty(entry.value)) {
|
|
1111
|
+
entry.type = "stringref";
|
|
1112
|
+
entry.id = strings[entry.value];
|
|
1113
|
+
} else strings[entry.value] = entry.id = entryId++;
|
|
1114
|
+
else entry.id = entryId++;
|
|
1115
|
+
});
|
|
1116
|
+
entries = entries.filter((entry) => {
|
|
1117
|
+
return entry.type !== "stringref";
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
function writeTrailer() {
|
|
1121
|
+
buffer = concat(buffer, nullBytes);
|
|
1122
|
+
buffer = concat(buffer, new Uint8Array([offsetSizeInBytes, idSizeInBytes]));
|
|
1123
|
+
buffer = writeUInt(buffer, BigInt(entries.length), 8);
|
|
1124
|
+
buffer = writeUInt(buffer, BigInt("0"), 8);
|
|
1125
|
+
buffer = writeUInt(buffer, BigInt(offsetTableOffset), 8);
|
|
1126
|
+
}
|
|
1127
|
+
function writeOffsetTable() {
|
|
1128
|
+
offsetTableOffset = buffer.byteLength;
|
|
1129
|
+
offsetSizeInBytes = computeOffsetSizeInBytes(offsetTableOffset);
|
|
1130
|
+
offsets.forEach((offset) => {
|
|
1131
|
+
buffer = writeUInt(buffer, offset, offsetSizeInBytes);
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
function write(entry) {
|
|
1135
|
+
if (entry.type === "primitive") {
|
|
1136
|
+
const value = entry.value;
|
|
1137
|
+
switch (typeof value) {
|
|
1138
|
+
case "number":
|
|
1139
|
+
case "bigint":
|
|
1140
|
+
writeNumber(value);
|
|
1141
|
+
break;
|
|
1142
|
+
case "string":
|
|
1143
|
+
writeString(value);
|
|
1144
|
+
break;
|
|
1145
|
+
case "boolean":
|
|
1146
|
+
writeBoolean(value);
|
|
1147
|
+
break;
|
|
1148
|
+
}
|
|
1149
|
+
if (value instanceof Date) writeDate(value);
|
|
1150
|
+
else if (value instanceof ArrayBuffer) writeData(value);
|
|
1151
|
+
else if (isUID(value)) writeUID(value.CF$UID);
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
switch (entry.type) {
|
|
1155
|
+
case "dict":
|
|
1156
|
+
writeDict(entry);
|
|
1157
|
+
break;
|
|
1158
|
+
case "array":
|
|
1159
|
+
writeArray(entry);
|
|
1160
|
+
break;
|
|
1161
|
+
default: throw new Error("unhandled entry type: " + entry.type);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
function writeDate(value) {
|
|
1165
|
+
buffer = writeUInt(buffer, 51, 1);
|
|
1166
|
+
const date = (value.getTime() - EPOCH) / 1e3;
|
|
1167
|
+
buffer = writeDouble(buffer, date);
|
|
1168
|
+
}
|
|
1169
|
+
function writeDict(entry) {
|
|
1170
|
+
writeIntHeader(13, entry.entryKeys.length);
|
|
1171
|
+
entry.entryKeys.forEach((entry) => {
|
|
1172
|
+
writeID(entry.id);
|
|
1173
|
+
});
|
|
1174
|
+
entry.entryValues.forEach((entry) => {
|
|
1175
|
+
writeID(entry.id);
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
function writeNumber(value) {
|
|
1179
|
+
if (typeof value === "bigint") {
|
|
1180
|
+
const width = 16;
|
|
1181
|
+
const buf = fromHexString(value.toString(16).padStart(width * 2, "0").slice(0, width * 2));
|
|
1182
|
+
buffer = writeUInt(buffer, 20, 1);
|
|
1183
|
+
buffer = concat(buffer, buf);
|
|
1184
|
+
} else if (Number.isInteger(value)) if (value < 0) {
|
|
1185
|
+
buffer = writeUInt(buffer, 19, 1);
|
|
1186
|
+
buffer = writeInt(buffer, value, 8);
|
|
1187
|
+
} else if (value <= 255) {
|
|
1188
|
+
buffer = writeUInt(buffer, 16, 1);
|
|
1189
|
+
buffer = writeUInt(buffer, value, 1);
|
|
1190
|
+
} else if (value <= 65535) {
|
|
1191
|
+
buffer = writeUInt(buffer, 17, 1);
|
|
1192
|
+
buffer = writeUInt(buffer, value, 2);
|
|
1193
|
+
} else if (value <= 4294967295) {
|
|
1194
|
+
buffer = writeUInt(buffer, 18, 1);
|
|
1195
|
+
buffer = writeUInt(buffer, value, 4);
|
|
1196
|
+
} else {
|
|
1197
|
+
buffer = writeUInt(buffer, 19, 1);
|
|
1198
|
+
buffer = writeUInt(buffer, value, 8);
|
|
1199
|
+
}
|
|
1200
|
+
else {
|
|
1201
|
+
buffer = writeUInt(buffer, 35, 1);
|
|
1202
|
+
buffer = writeDouble(buffer, value);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
function writeUID(uid) {
|
|
1206
|
+
writeIntHeader(8, 0);
|
|
1207
|
+
writeID(uid);
|
|
1208
|
+
}
|
|
1209
|
+
function writeArray(entry) {
|
|
1210
|
+
writeIntHeader(10, entry.entries.length);
|
|
1211
|
+
entry.entries.forEach((e) => {
|
|
1212
|
+
writeID(e.id);
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
function writeBoolean(value) {
|
|
1216
|
+
buffer = writeUInt(buffer, value ? 9 : 8, 1);
|
|
1217
|
+
}
|
|
1218
|
+
function writeString(value) {
|
|
1219
|
+
if (mustBeUtf16(value)) {
|
|
1220
|
+
const utf16 = toUTF16(value);
|
|
1221
|
+
writeIntHeader(6, utf16.length / 2);
|
|
1222
|
+
for (let i = 0; i < utf16.length; i += 2) {
|
|
1223
|
+
const t = utf16[i + 0];
|
|
1224
|
+
utf16[i + 0] = utf16[i + 1];
|
|
1225
|
+
utf16[i + 1] = t;
|
|
1226
|
+
}
|
|
1227
|
+
buffer = concat(buffer, utf16);
|
|
1228
|
+
} else {
|
|
1229
|
+
const utf8 = encoder.encode(value);
|
|
1230
|
+
writeIntHeader(5, utf8.length);
|
|
1231
|
+
buffer = concat(buffer, utf8);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
function writeData(data) {
|
|
1235
|
+
writeIntHeader(4, data.byteLength);
|
|
1236
|
+
buffer = concat(buffer, new Uint8Array(data));
|
|
1237
|
+
}
|
|
1238
|
+
function writeIntHeader(kind, value) {
|
|
1239
|
+
if (value < 15) buffer = writeUInt(buffer, (kind << 4) + value, 1);
|
|
1240
|
+
else {
|
|
1241
|
+
buffer = writeUInt(buffer, (kind << 4) + 15, 1);
|
|
1242
|
+
writeNumber(value);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
function writeID(id) {
|
|
1246
|
+
buffer = writeUInt(buffer, id, idSizeInBytes);
|
|
1247
|
+
}
|
|
1248
|
+
function mustBeUtf16(string) {
|
|
1249
|
+
return encoder.encode(string).byteLength != string.length;
|
|
1250
|
+
}
|
|
1251
|
+
};
|
|
1252
|
+
const typeofPrimitive = [
|
|
1253
|
+
"string",
|
|
1254
|
+
"number",
|
|
1255
|
+
"boolean",
|
|
1256
|
+
"bigint"
|
|
1257
|
+
];
|
|
1258
|
+
function toEntries(value) {
|
|
1259
|
+
if (typeofPrimitive.includes(typeof value) || value instanceof ArrayBuffer || value instanceof Date || isUID(value)) return [{
|
|
1260
|
+
type: "primitive",
|
|
1261
|
+
value
|
|
1262
|
+
}];
|
|
1263
|
+
if (value != null && typeof value === "object") return Array.isArray(value) ? toEntriesArray(value) : toEntriesObject(value);
|
|
1264
|
+
throw new Error("unhandled entry: " + value);
|
|
1265
|
+
}
|
|
1266
|
+
function toEntriesArray(array) {
|
|
1267
|
+
const entries = array.map(toEntries);
|
|
1268
|
+
return [{
|
|
1269
|
+
type: "array",
|
|
1270
|
+
value: void 0,
|
|
1271
|
+
entries: entries.map((entries) => entries[0])
|
|
1272
|
+
}, ...entries.flat()];
|
|
1273
|
+
}
|
|
1274
|
+
function toEntriesObject(dict) {
|
|
1275
|
+
const entryKeys = Object.keys(dict).map(toEntries).flat(1);
|
|
1276
|
+
const entryValues = Object.values(dict).map(toEntries);
|
|
1277
|
+
return [
|
|
1278
|
+
{
|
|
1279
|
+
type: "dict",
|
|
1280
|
+
value: void 0,
|
|
1281
|
+
entryKeys,
|
|
1282
|
+
entryValues: entryValues.map((entries) => entries[0])
|
|
1283
|
+
},
|
|
1284
|
+
...entryKeys,
|
|
1285
|
+
...entryValues.flat()
|
|
1286
|
+
];
|
|
1287
|
+
}
|
|
1288
|
+
function computeOffsetSizeInBytes(maxOffset) {
|
|
1289
|
+
if (maxOffset < 256) return 1;
|
|
1290
|
+
if (maxOffset < 65536) return 2;
|
|
1291
|
+
if (maxOffset < 4294967296) return 4;
|
|
1292
|
+
return 8;
|
|
1293
|
+
}
|
|
1294
|
+
function computeIdSizeInBytes(numberOfIds) {
|
|
1295
|
+
if (numberOfIds < 256) return 1;
|
|
1296
|
+
if (numberOfIds < 65536) return 2;
|
|
1297
|
+
return 4;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
//#endregion
|
|
1301
|
+
//#region src/encoding/plist.ts
|
|
1302
|
+
var plist_exports = /* @__PURE__ */ __exportAll({
|
|
1303
|
+
parse: () => parse,
|
|
1304
|
+
serialize: () => serialize
|
|
1305
|
+
});
|
|
1306
|
+
const HEADER = "bplist00";
|
|
1307
|
+
const TRAILER_SIZE = 32;
|
|
1308
|
+
const MAX_OBJECT_COUNT = 32768;
|
|
1309
|
+
const MAX_DEPTH = 256;
|
|
1310
|
+
/** Milliseconds between the Unix epoch and the Cocoa epoch (2001-01-01 GMT). */
|
|
1311
|
+
const COCOA_EPOCH = 9783072e5;
|
|
1312
|
+
const UTF8 = new TextDecoder("utf-8");
|
|
1313
|
+
const UTF16_BE = new TextDecoder("utf-16be");
|
|
1314
|
+
/**
|
|
1315
|
+
* Parses a binary plist.
|
|
1316
|
+
*
|
|
1317
|
+
* Integers of 1, 2 and 4 bytes are unsigned; only 8-byte integers carry a sign. A signed
|
|
1318
|
+
* read turns 200 into -56 and 44100 into -21436. An 8-byte integer comes back as a `bigint`.
|
|
1319
|
+
*
|
|
1320
|
+
* @throws Error when the buffer is not a well-formed binary plist.
|
|
1321
|
+
*/
|
|
1322
|
+
function parse(buffer) {
|
|
1323
|
+
const bytes = new Uint8Array(buffer);
|
|
1324
|
+
const view = new DataView(buffer);
|
|
1325
|
+
if (bytes.byteLength < 40 || UTF8.decode(bytes.subarray(0, 8)) !== HEADER) throw new Error(`Invalid binary plist. Expected '${HEADER}' at offset 0.`);
|
|
1326
|
+
const trailer = bytes.byteLength - TRAILER_SIZE;
|
|
1327
|
+
const offsetSize = view.getUint8(trailer + 6);
|
|
1328
|
+
const refSize = view.getUint8(trailer + 7);
|
|
1329
|
+
const objectCount = Number(view.getBigUint64(trailer + 8));
|
|
1330
|
+
const topObject = Number(view.getBigUint64(trailer + 16));
|
|
1331
|
+
const offsetTable = Number(view.getBigUint64(trailer + 24));
|
|
1332
|
+
if (objectCount > MAX_OBJECT_COUNT) throw new Error("Binary plist has too many objects.");
|
|
1333
|
+
const readUInt = (offset, size) => {
|
|
1334
|
+
if (offset < 0 || offset + size > bytes.byteLength) throw new Error("Binary plist points outside the buffer.");
|
|
1335
|
+
let value = 0;
|
|
1336
|
+
for (let i = 0; i < size; i++) value = value * 256 + bytes[offset + i];
|
|
1337
|
+
return value;
|
|
1338
|
+
};
|
|
1339
|
+
/** Reads a count that is either the low nibble or, for 0xF, an integer object that follows. */
|
|
1340
|
+
const readCount = (offset, info) => {
|
|
1341
|
+
if (info !== 15) return [info, offset + 1];
|
|
1342
|
+
const size = 1 << (view.getUint8(offset + 1) & 15);
|
|
1343
|
+
return [readUInt(offset + 2, size), offset + 2 + size];
|
|
1344
|
+
};
|
|
1345
|
+
const readInteger = (offset, size) => {
|
|
1346
|
+
if (size === 8) return view.getBigInt64(offset, false);
|
|
1347
|
+
if (size === 16) return view.getBigUint64(offset + 8, false);
|
|
1348
|
+
return readUInt(offset, size);
|
|
1349
|
+
};
|
|
1350
|
+
const readReal = (offset, size) => {
|
|
1351
|
+
if (size === 4) return view.getFloat32(offset, false);
|
|
1352
|
+
if (size === 8) return view.getFloat64(offset, false);
|
|
1353
|
+
throw new Error(`Invalid real length: ${size}`);
|
|
1354
|
+
};
|
|
1355
|
+
const readObject = (index, depth) => {
|
|
1356
|
+
if (index >= objectCount || depth > MAX_DEPTH) throw new Error("Binary plist has an invalid object reference.");
|
|
1357
|
+
const offset = readUInt(offsetTable + index * offsetSize, offsetSize);
|
|
1358
|
+
const marker = readUInt(offset, 1);
|
|
1359
|
+
const type = marker >> 4;
|
|
1360
|
+
const info = marker & 15;
|
|
1361
|
+
switch (type) {
|
|
1362
|
+
case 0:
|
|
1363
|
+
if (info === 8 || info === 9) return info === 9;
|
|
1364
|
+
if (info === 0 || info === 15) return null;
|
|
1365
|
+
throw new Error(`Unhandled simple type 0x${info.toString(16)}`);
|
|
1366
|
+
case 1: return readInteger(offset + 1, 1 << info);
|
|
1367
|
+
case 2: return readReal(offset + 1, 1 << info);
|
|
1368
|
+
case 3: return /* @__PURE__ */ new Date(COCOA_EPOCH + 1e3 * view.getFloat64(offset + 1, false));
|
|
1369
|
+
case 4: {
|
|
1370
|
+
const [length, start] = readCount(offset, info);
|
|
1371
|
+
readUInt(start + length, 0);
|
|
1372
|
+
return buffer.slice(start, start + length);
|
|
1373
|
+
}
|
|
1374
|
+
case 5: {
|
|
1375
|
+
const [length, start] = readCount(offset, info);
|
|
1376
|
+
readUInt(start + length, 0);
|
|
1377
|
+
return UTF8.decode(bytes.subarray(start, start + length));
|
|
1378
|
+
}
|
|
1379
|
+
case 6: {
|
|
1380
|
+
const [length, start] = readCount(offset, info);
|
|
1381
|
+
readUInt(start + length * 2, 0);
|
|
1382
|
+
return UTF16_BE.decode(bytes.subarray(start, start + length * 2));
|
|
1383
|
+
}
|
|
1384
|
+
case 8: return { CF$UID: readUInt(offset + 1, info + 1) };
|
|
1385
|
+
case 10: {
|
|
1386
|
+
const [length, start] = readCount(offset, info);
|
|
1387
|
+
const items = [];
|
|
1388
|
+
for (let i = 0; i < length; i++) items.push(readObject(readUInt(start + i * refSize, refSize), depth + 1));
|
|
1389
|
+
return items;
|
|
1390
|
+
}
|
|
1391
|
+
case 13: {
|
|
1392
|
+
const [length, start] = readCount(offset, info);
|
|
1393
|
+
const dictionary = {};
|
|
1394
|
+
for (let i = 0; i < length; i++) {
|
|
1395
|
+
const key = readObject(readUInt(start + i * refSize, refSize), depth + 1);
|
|
1396
|
+
if (typeof key !== "string") throw new Error("Invalid key type.");
|
|
1397
|
+
if (key === "__proto__") throw new Error("Attempted prototype pollution");
|
|
1398
|
+
dictionary[key] = readObject(readUInt(start + (length + i) * refSize, refSize), depth + 1);
|
|
1399
|
+
}
|
|
1400
|
+
return dictionary;
|
|
1401
|
+
}
|
|
1402
|
+
default: throw new Error(`Unhandled type 0x${type.toString(16)}`);
|
|
1403
|
+
}
|
|
1404
|
+
};
|
|
1405
|
+
return readObject(topObject, 0);
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
//#endregion
|
|
1409
|
+
//#region src/encoding/tlv8.ts
|
|
1410
|
+
var tlv8_exports = /* @__PURE__ */ __exportAll({
|
|
1411
|
+
ErrorCode: () => ErrorCode,
|
|
1412
|
+
Flags: () => Flags,
|
|
1413
|
+
Method: () => Method,
|
|
1414
|
+
State: () => State,
|
|
1415
|
+
Value: () => Value,
|
|
1416
|
+
bail: () => bail,
|
|
1417
|
+
decode: () => decode,
|
|
1418
|
+
decodeEntries: () => decodeEntries,
|
|
1419
|
+
encode: () => encode
|
|
1420
|
+
});
|
|
1421
|
+
/**
|
|
1422
|
+
* TLV8 pairing flags used during HAP pair-setup and pair-verify.
|
|
1423
|
+
* Sent as part of the TLV8 Flags (0x13) value.
|
|
1424
|
+
*/
|
|
1425
|
+
const Flags = { TransientPairing: 16 };
|
|
1426
|
+
/**
|
|
1427
|
+
* TLV8 error codes returned by the accessory during pairing.
|
|
1428
|
+
* Included in the Error (0x07) TLV value.
|
|
1429
|
+
*/
|
|
1430
|
+
const ErrorCode = {
|
|
1431
|
+
Unknown: 1,
|
|
1432
|
+
Authentication: 2,
|
|
1433
|
+
BackOff: 3,
|
|
1434
|
+
MaxPeers: 4,
|
|
1435
|
+
MaxTries: 5,
|
|
1436
|
+
Unavailable: 6,
|
|
1437
|
+
Busy: 7
|
|
1438
|
+
};
|
|
1439
|
+
/**
|
|
1440
|
+
* HAP pairing method identifiers. Sent in the Method (0x00) TLV value
|
|
1441
|
+
* to indicate which pairing operation is being performed.
|
|
1442
|
+
*/
|
|
1443
|
+
const Method = {
|
|
1444
|
+
PairSetup: 0,
|
|
1445
|
+
PairSetupWithAuth: 1,
|
|
1446
|
+
PairVerify: 2,
|
|
1447
|
+
AddPairing: 3,
|
|
1448
|
+
RemovePairing: 4,
|
|
1449
|
+
ListPairing: 5
|
|
1450
|
+
};
|
|
1451
|
+
/**
|
|
1452
|
+
* HAP pairing state machine steps (M1 through M6).
|
|
1453
|
+
* Each state corresponds to a message in the SRP pair-setup or pair-verify flow.
|
|
1454
|
+
*/
|
|
1455
|
+
const State = {
|
|
1456
|
+
M1: 1,
|
|
1457
|
+
M2: 2,
|
|
1458
|
+
M3: 3,
|
|
1459
|
+
M4: 4,
|
|
1460
|
+
M5: 5,
|
|
1461
|
+
M6: 6
|
|
1462
|
+
};
|
|
1463
|
+
/**
|
|
1464
|
+
* TLV8 type identifiers for the fields exchanged during HAP pairing.
|
|
1465
|
+
* Each value is the type byte that precedes the length and data in a TLV8 entry.
|
|
1466
|
+
*/
|
|
1467
|
+
const Value = {
|
|
1468
|
+
Method: 0,
|
|
1469
|
+
Identifier: 1,
|
|
1470
|
+
Salt: 2,
|
|
1471
|
+
PublicKey: 3,
|
|
1472
|
+
Proof: 4,
|
|
1473
|
+
EncryptedData: 5,
|
|
1474
|
+
State: 6,
|
|
1475
|
+
Error: 7,
|
|
1476
|
+
BackOff: 8,
|
|
1477
|
+
Certificate: 9,
|
|
1478
|
+
Signature: 10,
|
|
1479
|
+
Permissions: 11,
|
|
1480
|
+
FragmentData: 12,
|
|
1481
|
+
FragmentLast: 13,
|
|
1482
|
+
Name: 17,
|
|
1483
|
+
Flags: 19
|
|
1484
|
+
};
|
|
1485
|
+
/** Throws the {@link TLV8PairingError} for the error or back-off in a decoded pairing response. */
|
|
1486
|
+
function bail(data) {
|
|
1487
|
+
if (data.has(Value.BackOff)) {
|
|
1488
|
+
const buffer = data.get(Value.BackOff);
|
|
1489
|
+
throw new TLV8PairingError(`Device is busy, try again in ${buffer.readUintLE(0, buffer.length)} seconds.`, ErrorCode.BackOff);
|
|
1490
|
+
}
|
|
1491
|
+
if (data.has(Value.Error)) {
|
|
1492
|
+
const code = data.get(Value.Error).readUint8();
|
|
1493
|
+
const errorCode = Object.entries(ErrorCode).find(([, value]) => value === code);
|
|
1494
|
+
if (!errorCode) throw new TLV8PairingError(`Device returned an unknown error code: ${code}`, code);
|
|
1495
|
+
throw new TLV8PairingError(`Device returned an error code: ${errorCode[0]}`, code);
|
|
1496
|
+
}
|
|
1497
|
+
throw new TLV8PairingError("Invalid response");
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Encodes `[type, value]` entries; a number value is a single byte. A value longer than 255 bytes
|
|
1501
|
+
* becomes consecutive fragments of the same type, as TLV8 requires.
|
|
1502
|
+
*/
|
|
1503
|
+
function encode(entries) {
|
|
1504
|
+
let totalSize = 0;
|
|
1505
|
+
for (const [, valueRaw] of entries) {
|
|
1506
|
+
const len = typeof valueRaw === "number" ? 1 : valueRaw.length;
|
|
1507
|
+
const chunks = Math.max(1, Math.ceil(len / 255));
|
|
1508
|
+
totalSize += chunks * 2 + len;
|
|
1509
|
+
}
|
|
1510
|
+
const result = Buffer.allocUnsafe(totalSize);
|
|
1511
|
+
let pos = 0;
|
|
1512
|
+
for (const [type, valueRaw] of entries) {
|
|
1513
|
+
let value;
|
|
1514
|
+
let valueLen;
|
|
1515
|
+
if (typeof valueRaw === "number") {
|
|
1516
|
+
value = Buffer.allocUnsafe(1);
|
|
1517
|
+
value[0] = valueRaw;
|
|
1518
|
+
valueLen = 1;
|
|
1519
|
+
} else {
|
|
1520
|
+
value = valueRaw;
|
|
1521
|
+
valueLen = value.length;
|
|
1522
|
+
}
|
|
1523
|
+
let offset = 0;
|
|
1524
|
+
do {
|
|
1525
|
+
const len = Math.min(valueLen - offset, 255);
|
|
1526
|
+
result[pos++] = type;
|
|
1527
|
+
result[pos++] = len;
|
|
1528
|
+
if (len > 0) {
|
|
1529
|
+
if (value instanceof Buffer) value.copy(result, pos, offset, offset + len);
|
|
1530
|
+
else result.set(value.subarray(offset, offset + len), pos);
|
|
1531
|
+
pos += len;
|
|
1532
|
+
}
|
|
1533
|
+
offset += len;
|
|
1534
|
+
} while (offset < valueLen);
|
|
1535
|
+
}
|
|
1536
|
+
return result;
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Decodes a TLV8 buffer into a map from type to value, for messages that hold each type once,
|
|
1540
|
+
* such as pairing messages. Adjacent entries of the same type are concatenated, which reassembles
|
|
1541
|
+
* fragmented values. When a type appears again after another type, the first value wins.
|
|
1542
|
+
*
|
|
1543
|
+
* @throws {RangeError} When an entry is truncated.
|
|
1544
|
+
*/
|
|
1545
|
+
function decode(buf) {
|
|
1546
|
+
const map = /* @__PURE__ */ new Map();
|
|
1547
|
+
for (const [type, value] of decodeEntries(buf)) if (!map.has(type)) map.set(type, value);
|
|
1548
|
+
return map;
|
|
1549
|
+
}
|
|
1550
|
+
/**
|
|
1551
|
+
* Decodes a TLV8 buffer into its `[type, value]` entries in order, for lists in which a type
|
|
1552
|
+
* repeats. Adjacent entries of the same type are concatenated into one value, which reassembles
|
|
1553
|
+
* fragmented values; a separator entry between two items keeps them apart.
|
|
1554
|
+
*
|
|
1555
|
+
* @throws {RangeError} When an entry is truncated.
|
|
1556
|
+
*/
|
|
1557
|
+
function decodeEntries(buf) {
|
|
1558
|
+
const entries = [];
|
|
1559
|
+
let i = 0;
|
|
1560
|
+
while (i < buf.length) {
|
|
1561
|
+
if (buf.length - i < 2) throw new RangeError("Truncated TLV8 header");
|
|
1562
|
+
const type = buf[i++];
|
|
1563
|
+
const len = buf[i++];
|
|
1564
|
+
if (len > buf.length - i) throw new RangeError("Truncated TLV8 value");
|
|
1565
|
+
const value = buf.subarray(i, i + len);
|
|
1566
|
+
const last = entries.at(-1);
|
|
1567
|
+
if (last && last[0] === type) last[1] = Buffer.concat([last[1], value]);
|
|
1568
|
+
else entries.push([type, value]);
|
|
1569
|
+
i += len;
|
|
1570
|
+
}
|
|
1571
|
+
return entries;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
//#endregion
|
|
1575
|
+
//#region src/encoding/rti.ts
|
|
1576
|
+
var rti_exports = /* @__PURE__ */ __exportAll({
|
|
1577
|
+
decodeSession: () => decodeSession,
|
|
1578
|
+
encodeOperation: () => encodeOperation
|
|
1579
|
+
});
|
|
1580
|
+
/** Reads RTIKeyedArchiver roots without exposing bytes outside the supplied view. */
|
|
1581
|
+
function decodeSession(data) {
|
|
1582
|
+
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
1583
|
+
const archive = parse(Uint8Array.from(bytes).buffer);
|
|
1584
|
+
const objects = archive?.$objects;
|
|
1585
|
+
if (!Array.isArray(objects) || !archive?.$top) throw new Error("Invalid RTI archive.");
|
|
1586
|
+
const resolve = (value, depth = 0) => {
|
|
1587
|
+
if (depth > 64) throw new Error("Invalid RTI archive reference cycle.");
|
|
1588
|
+
if (value === "$null") return null;
|
|
1589
|
+
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return value;
|
|
1590
|
+
if (!value || typeof value !== "object") return value;
|
|
1591
|
+
if ("CF$UID" in value) {
|
|
1592
|
+
const index = value["CF$UID"];
|
|
1593
|
+
if (!Number.isInteger(index) || index < 0 || index >= objects.length) throw new Error("Invalid RTI archive reference.");
|
|
1594
|
+
return resolve(objects[index], depth + 1);
|
|
1595
|
+
}
|
|
1596
|
+
if (Array.isArray(value)) return value.map((item) => resolve(item, depth + 1));
|
|
1597
|
+
const result = {};
|
|
1598
|
+
for (const [key, item] of Object.entries(value)) if (key !== "$class") result[key] = resolve(item, depth + 1);
|
|
1599
|
+
return result;
|
|
1600
|
+
};
|
|
1601
|
+
const roots = resolve(archive.$top);
|
|
1602
|
+
const root = roots.root ?? roots;
|
|
1603
|
+
const uuidValue = root.sessionUUID?.["NS.uuidbytes"] ?? root.sessionUUID;
|
|
1604
|
+
const uuid = uuidValue instanceof ArrayBuffer ? new Uint8Array(uuidValue) : uuidValue instanceof Uint8Array ? uuidValue : null;
|
|
1605
|
+
if (!uuid || uuid.byteLength !== 16) throw new Error("Invalid RTI session UUID.");
|
|
1606
|
+
const document = root.documentState ?? {};
|
|
1607
|
+
const traits = root.documentTraits ?? {};
|
|
1608
|
+
const text = document.docSt ?? document.documentContextBeforeInput ?? "";
|
|
1609
|
+
const documentText = typeof text === "string" ? text : text?.["NS.string"] ?? "";
|
|
1610
|
+
return {
|
|
1611
|
+
uuid: Uint8Array.from(uuid),
|
|
1612
|
+
documentText: typeof documentText === "string" ? documentText : "",
|
|
1613
|
+
isSecure: !!traits.secureTextEntry,
|
|
1614
|
+
keyboardType: Number(traits.keyboardType ?? 0),
|
|
1615
|
+
autocorrection: Number(traits.autocorrectionType ?? 0) === 2,
|
|
1616
|
+
autocapitalization: Number(traits.autocapitalizationType ?? 0) !== 0
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
function uid(index) {
|
|
1620
|
+
return { "CF$UID": index };
|
|
1621
|
+
}
|
|
1622
|
+
/** Encodes an RTITextOperations archive that inserts `text`, or clears the field when `clear` is set. */
|
|
1623
|
+
function encodeOperation(sessionUUID, text, clear) {
|
|
1624
|
+
if (sessionUUID.byteLength !== 16) throw new Error("Invalid RTI session UUID.");
|
|
1625
|
+
return serialize({
|
|
1626
|
+
"$version": 1e5,
|
|
1627
|
+
"$archiver": "RTIKeyedArchiver",
|
|
1628
|
+
"$top": { textOperations: uid(1) },
|
|
1629
|
+
"$objects": [
|
|
1630
|
+
"$null",
|
|
1631
|
+
{
|
|
1632
|
+
$class: uid(7),
|
|
1633
|
+
targetSessionUUID: uid(5),
|
|
1634
|
+
keyboardOutput: uid(2),
|
|
1635
|
+
...clear ? { textToAssert: uid(3) } : {}
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
$class: uid(4),
|
|
1639
|
+
...clear ? {} : { insertionText: uid(3) }
|
|
1640
|
+
},
|
|
1641
|
+
clear ? "" : text,
|
|
1642
|
+
{
|
|
1643
|
+
$classname: "TIKeyboardOutput",
|
|
1644
|
+
$classes: ["TIKeyboardOutput", "NSObject"]
|
|
1645
|
+
},
|
|
1646
|
+
{
|
|
1647
|
+
"NS.uuidbytes": Uint8Array.from(sessionUUID).buffer,
|
|
1648
|
+
$class: uid(6)
|
|
1649
|
+
},
|
|
1650
|
+
{
|
|
1651
|
+
$classname: "NSUUID",
|
|
1652
|
+
$classes: ["NSUUID", "NSObject"]
|
|
1653
|
+
},
|
|
1654
|
+
{
|
|
1655
|
+
$classname: "RTITextOperations",
|
|
1656
|
+
$classes: ["RTITextOperations", "NSObject"]
|
|
1657
|
+
}
|
|
1658
|
+
]
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
//#endregion
|
|
1663
|
+
export { Value as a, encode as c, encode$1 as d, opack_exports as f, daap_exports as h, State as i, tlv8_exports as l, nskeyedarchiver_exports as m, Flags as n, bail as o, ntp_exports as p, Method as r, decode as s, rti_exports as t, plist_exports as u };
|