@basmilius/apple-encoding 0.5.3 → 0.6.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024-2025 Bas Milius
3
+ Copyright (c) 2024-present Bas Milius
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/dist/daap.d.ts ADDED
@@ -0,0 +1,95 @@
1
+ export declare const ContentCode: {
2
+ readonly mlit: "dmap.listingitem";
3
+ readonly mlcl: "dmap.listing";
4
+ readonly msrv: "dmap.serverinforesponse";
5
+ readonly mcon: "dmap.container";
6
+ readonly miid: "dmap.itemid";
7
+ readonly minm: "dmap.itemname";
8
+ readonly mikd: "dmap.itemkind";
9
+ readonly mper: "dmap.persistentid";
10
+ readonly asal: "daap.songalbum";
11
+ readonly asar: "daap.songartist";
12
+ readonly asaa: "daap.songalbumartist";
13
+ readonly ascp: "daap.songcomposer";
14
+ readonly asgn: "daap.songgenre";
15
+ readonly astm: "daap.songtime";
16
+ readonly astn: "daap.songtracknumber";
17
+ readonly asdc: "daap.songdisccount";
18
+ readonly asdn: "daap.songdiscnumber";
19
+ readonly astc: "daap.songtrackcount";
20
+ readonly asyr: "daap.songyear";
21
+ readonly asbr: "daap.songbitrate";
22
+ readonly assr: "daap.songsamplerate";
23
+ readonly assz: "daap.songsize";
24
+ readonly caps: "daap.songplaystatus";
25
+ readonly cash: "daap.songshufflestate";
26
+ readonly carp: "daap.songrepeatstate";
27
+ readonly cavs: "daap.songvisiblestate";
28
+ readonly aePP: "com.apple.itunes.photo-properties";
29
+ };
30
+ export declare const TagType: {
31
+ readonly mlit: 12;
32
+ readonly mlcl: 12;
33
+ readonly mcon: 12;
34
+ readonly msrv: 12;
35
+ readonly miid: 5;
36
+ readonly minm: 9;
37
+ readonly mikd: 1;
38
+ readonly mper: 7;
39
+ readonly asal: 9;
40
+ readonly asar: 9;
41
+ readonly asaa: 9;
42
+ readonly ascp: 9;
43
+ readonly asgn: 9;
44
+ readonly astm: 5;
45
+ readonly astn: 3;
46
+ readonly asdc: 3;
47
+ readonly asdn: 3;
48
+ readonly astc: 3;
49
+ readonly asyr: 3;
50
+ readonly asbr: 3;
51
+ readonly assr: 5;
52
+ readonly assz: 5;
53
+ readonly caps: 1;
54
+ readonly cash: 1;
55
+ readonly carp: 1;
56
+ readonly cavs: 1;
57
+ readonly aePP: 9;
58
+ };
59
+ export declare function encodeTag(tag: string, value: Buffer | string | number | bigint): Buffer;
60
+ export declare function encodeContainer(tag: string, content: Buffer): Buffer;
61
+ export declare function encodePlaybackStatus(status: PlaybackStatus): Buffer;
62
+ export declare function encodeTagWithSize(tag: string, value: number, byteSize: 1 | 2 | 4 | 8): Buffer;
63
+ export declare function encodeTrackMetadata(metadata: TrackMetadata): Buffer;
64
+ export declare function decode(buffer: Buffer): DecodedTag[];
65
+ export declare function decodeTag(buffer: Buffer): [DecodedTag, Buffer] | null;
66
+ export declare function decodeToObject(buffer: Buffer): Record<string, unknown>;
67
+ export declare function decodeTrackMetadata(buffer: Buffer): TrackMetadata;
68
+ export type ContentCodeKey = keyof typeof ContentCode;
69
+ export type DecodedTag = {
70
+ readonly tag: string;
71
+ readonly length: number;
72
+ readonly value: Buffer;
73
+ };
74
+ export type PlaybackStatus = {
75
+ readonly playing?: boolean;
76
+ readonly shuffle?: boolean;
77
+ readonly repeat?: "off" | "one" | "all";
78
+ };
79
+ export type TrackMetadata = {
80
+ readonly title?: string;
81
+ readonly artist?: string;
82
+ readonly albumArtist?: string;
83
+ readonly album?: string;
84
+ readonly composer?: string;
85
+ readonly genre?: string;
86
+ readonly duration?: number;
87
+ readonly trackNumber?: number;
88
+ readonly trackCount?: number;
89
+ readonly discNumber?: number;
90
+ readonly discCount?: number;
91
+ readonly year?: number;
92
+ readonly bitrate?: number;
93
+ readonly sampleRate?: number;
94
+ readonly size?: number;
95
+ };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * as DAAP from "./daap";
1
2
  export * as NTP from "./ntp";
2
3
  export * as OPack from "./opack";
3
4
  export * as Plist from "./plist";
package/dist/index.js CHANGED
@@ -9,6 +9,284 @@ var __export = (target, all) => {
9
9
  });
10
10
  };
11
11
 
12
+ // src/daap.ts
13
+ var exports_daap = {};
14
+ __export(exports_daap, {
15
+ encodeTrackMetadata: () => encodeTrackMetadata,
16
+ encodeTagWithSize: () => encodeTagWithSize,
17
+ encodeTag: () => encodeTag,
18
+ encodePlaybackStatus: () => encodePlaybackStatus,
19
+ encodeContainer: () => encodeContainer,
20
+ decodeTrackMetadata: () => decodeTrackMetadata,
21
+ decodeToObject: () => decodeToObject,
22
+ decodeTag: () => decodeTag,
23
+ decode: () => decode,
24
+ TagType: () => TagType,
25
+ ContentCode: () => ContentCode
26
+ });
27
+ var ContentCode = {
28
+ mlit: "dmap.listingitem",
29
+ mlcl: "dmap.listing",
30
+ msrv: "dmap.serverinforesponse",
31
+ mcon: "dmap.container",
32
+ miid: "dmap.itemid",
33
+ minm: "dmap.itemname",
34
+ mikd: "dmap.itemkind",
35
+ mper: "dmap.persistentid",
36
+ asal: "daap.songalbum",
37
+ asar: "daap.songartist",
38
+ asaa: "daap.songalbumartist",
39
+ ascp: "daap.songcomposer",
40
+ asgn: "daap.songgenre",
41
+ astm: "daap.songtime",
42
+ astn: "daap.songtracknumber",
43
+ asdc: "daap.songdisccount",
44
+ asdn: "daap.songdiscnumber",
45
+ astc: "daap.songtrackcount",
46
+ asyr: "daap.songyear",
47
+ asbr: "daap.songbitrate",
48
+ assr: "daap.songsamplerate",
49
+ assz: "daap.songsize",
50
+ caps: "daap.songplaystatus",
51
+ cash: "daap.songshufflestate",
52
+ carp: "daap.songrepeatstate",
53
+ cavs: "daap.songvisiblestate",
54
+ aePP: "com.apple.itunes.photo-properties"
55
+ };
56
+ var TagType = {
57
+ mlit: 12,
58
+ mlcl: 12,
59
+ mcon: 12,
60
+ msrv: 12,
61
+ miid: 5,
62
+ minm: 9,
63
+ mikd: 1,
64
+ mper: 7,
65
+ asal: 9,
66
+ asar: 9,
67
+ asaa: 9,
68
+ ascp: 9,
69
+ asgn: 9,
70
+ astm: 5,
71
+ astn: 3,
72
+ asdc: 3,
73
+ asdn: 3,
74
+ astc: 3,
75
+ asyr: 3,
76
+ asbr: 3,
77
+ assr: 5,
78
+ assz: 5,
79
+ caps: 1,
80
+ cash: 1,
81
+ carp: 1,
82
+ cavs: 1,
83
+ aePP: 9
84
+ };
85
+ function encodeTag(tag, value) {
86
+ if (tag.length !== 4) {
87
+ throw new Error(`Invalid DAAP tag: ${tag}. Tags must be exactly 4 characters.`);
88
+ }
89
+ const tagBuffer = Buffer.from(tag, "ascii");
90
+ let valueBuffer;
91
+ if (typeof value === "string") {
92
+ valueBuffer = Buffer.from(value, "utf8");
93
+ } else if (typeof value === "bigint") {
94
+ valueBuffer = Buffer.alloc(8);
95
+ valueBuffer.writeBigUInt64BE(value, 0);
96
+ } else if (typeof value === "number") {
97
+ if (value <= 255 && value >= 0) {
98
+ valueBuffer = Buffer.alloc(1);
99
+ valueBuffer.writeUInt8(value, 0);
100
+ } else if (value <= 65535 && value >= 0) {
101
+ valueBuffer = Buffer.alloc(2);
102
+ valueBuffer.writeUInt16BE(value, 0);
103
+ } else if (value <= 4294967295 && value >= 0) {
104
+ valueBuffer = Buffer.alloc(4);
105
+ valueBuffer.writeUInt32BE(value, 0);
106
+ } else {
107
+ valueBuffer = Buffer.alloc(8);
108
+ valueBuffer.writeBigInt64BE(BigInt(value), 0);
109
+ }
110
+ } else {
111
+ valueBuffer = value;
112
+ }
113
+ const lengthBuffer = Buffer.alloc(4);
114
+ lengthBuffer.writeUInt32BE(valueBuffer.length, 0);
115
+ return Buffer.concat([tagBuffer, lengthBuffer, valueBuffer]);
116
+ }
117
+ function encodeContainer(tag, content) {
118
+ if (tag.length !== 4) {
119
+ throw new Error(`Invalid DAAP tag: ${tag}. Tags must be exactly 4 characters.`);
120
+ }
121
+ const tagBuffer = Buffer.from(tag, "ascii");
122
+ const lengthBuffer = Buffer.alloc(4);
123
+ lengthBuffer.writeUInt32BE(content.length, 0);
124
+ return Buffer.concat([tagBuffer, lengthBuffer, content]);
125
+ }
126
+ function encodePlaybackStatus(status) {
127
+ const tags = [];
128
+ if (status.playing !== undefined) {
129
+ tags.push(encodeTagWithSize("caps", status.playing ? 4 : 3, 1));
130
+ }
131
+ if (status.shuffle !== undefined) {
132
+ tags.push(encodeTagWithSize("cash", status.shuffle ? 1 : 0, 1));
133
+ }
134
+ if (status.repeat !== undefined) {
135
+ let repeatValue = 0;
136
+ if (status.repeat === "one")
137
+ repeatValue = 1;
138
+ else if (status.repeat === "all")
139
+ repeatValue = 2;
140
+ tags.push(encodeTagWithSize("carp", repeatValue, 1));
141
+ }
142
+ return Buffer.concat(tags);
143
+ }
144
+ function encodeTagWithSize(tag, value, byteSize) {
145
+ if (tag.length !== 4) {
146
+ throw new Error(`Invalid DAAP tag: ${tag}. Tags must be exactly 4 characters.`);
147
+ }
148
+ const tagBuffer = Buffer.from(tag, "ascii");
149
+ const valueBuffer = Buffer.alloc(byteSize);
150
+ switch (byteSize) {
151
+ case 1:
152
+ valueBuffer.writeUInt8(value, 0);
153
+ break;
154
+ case 2:
155
+ valueBuffer.writeUInt16BE(value, 0);
156
+ break;
157
+ case 4:
158
+ valueBuffer.writeUInt32BE(value, 0);
159
+ break;
160
+ case 8:
161
+ valueBuffer.writeBigUInt64BE(BigInt(value), 0);
162
+ break;
163
+ }
164
+ const lengthBuffer = Buffer.alloc(4);
165
+ lengthBuffer.writeUInt32BE(byteSize, 0);
166
+ return Buffer.concat([tagBuffer, lengthBuffer, valueBuffer]);
167
+ }
168
+ function encodeTrackMetadata(metadata) {
169
+ const tags = [];
170
+ if (metadata.title !== undefined) {
171
+ tags.push(encodeTag("minm", metadata.title));
172
+ }
173
+ if (metadata.artist !== undefined) {
174
+ tags.push(encodeTag("asar", metadata.artist));
175
+ }
176
+ if (metadata.albumArtist !== undefined) {
177
+ tags.push(encodeTag("asaa", metadata.albumArtist));
178
+ }
179
+ if (metadata.album !== undefined) {
180
+ tags.push(encodeTag("asal", metadata.album));
181
+ }
182
+ if (metadata.composer !== undefined) {
183
+ tags.push(encodeTag("ascp", metadata.composer));
184
+ }
185
+ if (metadata.genre !== undefined) {
186
+ tags.push(encodeTag("asgn", metadata.genre));
187
+ }
188
+ if (metadata.duration !== undefined) {
189
+ tags.push(encodeTagWithSize("astm", Math.floor(metadata.duration * 1000), 4));
190
+ }
191
+ if (metadata.trackNumber !== undefined) {
192
+ tags.push(encodeTagWithSize("astn", metadata.trackNumber, 2));
193
+ }
194
+ if (metadata.trackCount !== undefined) {
195
+ tags.push(encodeTagWithSize("astc", metadata.trackCount, 2));
196
+ }
197
+ if (metadata.discNumber !== undefined) {
198
+ tags.push(encodeTagWithSize("asdn", metadata.discNumber, 2));
199
+ }
200
+ if (metadata.discCount !== undefined) {
201
+ tags.push(encodeTagWithSize("asdc", metadata.discCount, 2));
202
+ }
203
+ if (metadata.year !== undefined) {
204
+ tags.push(encodeTagWithSize("asyr", metadata.year, 2));
205
+ }
206
+ if (metadata.bitrate !== undefined) {
207
+ tags.push(encodeTagWithSize("asbr", metadata.bitrate, 2));
208
+ }
209
+ if (metadata.sampleRate !== undefined) {
210
+ tags.push(encodeTagWithSize("assr", metadata.sampleRate, 4));
211
+ }
212
+ if (metadata.size !== undefined) {
213
+ tags.push(encodeTagWithSize("assz", metadata.size, 4));
214
+ }
215
+ const content = Buffer.concat(tags);
216
+ return encodeContainer("mlit", content);
217
+ }
218
+ function decode(buffer) {
219
+ const tags = [];
220
+ let remaining = buffer;
221
+ while (remaining.length > 0) {
222
+ const result = decodeTag(remaining);
223
+ if (!result)
224
+ break;
225
+ const [tag, rest] = result;
226
+ tags.push(tag);
227
+ remaining = rest;
228
+ }
229
+ return tags;
230
+ }
231
+ function decodeTag(buffer) {
232
+ if (buffer.length < 8) {
233
+ return null;
234
+ }
235
+ const tag = buffer.subarray(0, 4).toString("ascii");
236
+ const length = buffer.readUInt32BE(4);
237
+ if (buffer.length < 8 + length) {
238
+ return null;
239
+ }
240
+ const value = buffer.subarray(8, 8 + length);
241
+ const remaining = buffer.subarray(8 + length);
242
+ return [{ tag, length, value }, remaining];
243
+ }
244
+ function decodeToObject(buffer) {
245
+ const result = {};
246
+ const tags = decode(buffer);
247
+ for (const { tag, value } of tags) {
248
+ const tagType = TagType[tag];
249
+ if (tagType === undefined) {
250
+ result[tag] = value;
251
+ } else if (tagType === 12) {
252
+ result[tag] = decodeToObject(value);
253
+ } else if (tagType === 9) {
254
+ result[tag] = value.toString("utf8");
255
+ } else if (tagType === 1 || tagType === 2) {
256
+ result[tag] = value.readUInt8(0);
257
+ } else if (tagType === 3 || tagType === 4) {
258
+ result[tag] = value.readUInt16BE(0);
259
+ } else if (tagType === 5 || tagType === 6) {
260
+ result[tag] = value.readUInt32BE(0);
261
+ } else if (tagType === 7 || tagType === 8) {
262
+ result[tag] = value.readBigUInt64BE(0);
263
+ } else {
264
+ result[tag] = value;
265
+ }
266
+ }
267
+ return result;
268
+ }
269
+ function decodeTrackMetadata(buffer) {
270
+ const obj = decodeToObject(buffer);
271
+ const mlit = obj.mlit ?? obj;
272
+ return {
273
+ title: mlit.minm,
274
+ artist: mlit.asar,
275
+ albumArtist: mlit.asaa,
276
+ album: mlit.asal,
277
+ composer: mlit.ascp,
278
+ genre: mlit.asgn,
279
+ duration: mlit.astm !== undefined ? mlit.astm / 1000 : undefined,
280
+ trackNumber: mlit.astn,
281
+ trackCount: mlit.astc,
282
+ discNumber: mlit.asdn,
283
+ discCount: mlit.asdc,
284
+ year: mlit.asyr,
285
+ bitrate: mlit.asbr,
286
+ sampleRate: mlit.assr,
287
+ size: mlit.assz
288
+ };
289
+ }
12
290
  // src/ntp.ts
13
291
  var exports_ntp = {};
14
292
  __export(exports_ntp, {
@@ -16,7 +294,7 @@ __export(exports_ntp, {
16
294
  ns: () => ns,
17
295
  now: () => now,
18
296
  encode: () => encode,
19
- decode: () => decode
297
+ decode: () => decode2
20
298
  });
21
299
  var EPOCH = 0x83AA7E80n;
22
300
  function now() {
@@ -34,7 +312,7 @@ function parts(ntp) {
34
312
  Number(ntp & 0xFFFFFFFFn)
35
313
  ];
36
314
  }
37
- function decode(buffer) {
315
+ function decode2(buffer) {
38
316
  if (buffer.length < 24) {
39
317
  throw new RangeError(`NTP packet too small: expected at least 24 bytes, got ${buffer.length}`);
40
318
  }
@@ -72,7 +350,7 @@ __export(exports_opack, {
72
350
  int: () => int,
73
351
  float: () => float,
74
352
  encode: () => encode2,
75
- decode: () => decode2
353
+ decode: () => decode3
76
354
  });
77
355
  var TAG = {
78
356
  TRUE: 1,
@@ -160,7 +438,7 @@ function int(value) {
160
438
  function sizedInteger(value, size) {
161
439
  return new SizedInteger(value, size);
162
440
  }
163
- function decode2(data) {
441
+ function decode3(data) {
164
442
  const [value] = _unpack(data, []);
165
443
  return value;
166
444
  }
@@ -453,8 +731,611 @@ __export(exports_plist, {
453
731
  serialize: () => serialize,
454
732
  parse: () => parse
455
733
  });
456
- import { parse } from "@plist/binary.parse";
457
- import { serialize } from "@plist/binary.serialize";
734
+ // ../../node_modules/@plist/common/lib/esm/constants.js
735
+ var EPOCH2 = 978307200000;
736
+ var HEADER_BINARY = "bplist00";
737
+ var PlistFormat;
738
+ (function(PlistFormat2) {
739
+ PlistFormat2[PlistFormat2["BINARY"] = 0] = "BINARY";
740
+ PlistFormat2[PlistFormat2["XML"] = 1] = "XML";
741
+ PlistFormat2[PlistFormat2["OPENSTEP"] = 2] = "OPENSTEP";
742
+ })(PlistFormat || (PlistFormat = {}));
743
+ // ../../node_modules/@plist/binary.parse/lib/esm/index.js
744
+ var maxObjectSize = 100 * 1000 * 1000;
745
+ var maxObjectCount = 32768;
746
+ var DECODER_UTF8 = new TextDecoder("utf-8");
747
+ var DECODER_UTF16 = new TextDecoder("utf-16");
748
+ function readDouble(buffer, start = 0) {
749
+ return new DataView(buffer).getFloat64(start, false);
750
+ }
751
+ function readFloat(buffer, start = 0) {
752
+ return new DataView(buffer).getFloat32(start, false);
753
+ }
754
+ function readUInt8(buffer, start = 0) {
755
+ return new DataView(buffer).getUint8(start);
756
+ }
757
+ function readUInt16(buffer, start = 0) {
758
+ return new DataView(buffer).getUint16(start, false);
759
+ }
760
+ function readUInt32(buffer, start = 0) {
761
+ return new DataView(buffer).getUint32(start, false);
762
+ }
763
+ function readUInt64(buffer, start = 0) {
764
+ return new DataView(buffer).getBigUint64(start, false);
765
+ }
766
+ function readUInt(buffer) {
767
+ switch (buffer.byteLength) {
768
+ case 1:
769
+ return readUInt8(buffer);
770
+ case 2:
771
+ return readUInt16(buffer);
772
+ case 4:
773
+ return readUInt32(buffer);
774
+ case 8:
775
+ return readUInt64(buffer);
776
+ case 16:
777
+ return readUInt64(buffer, 8);
778
+ }
779
+ throw new Error(`Invalid unsigned int length: ${buffer.byteLength}`);
780
+ }
781
+ function readInt8(buffer, start = 0) {
782
+ return new DataView(buffer).getInt8(start);
783
+ }
784
+ function readInt16(buffer, start = 0) {
785
+ return new DataView(buffer).getInt16(start, false);
786
+ }
787
+ function readInt32(buffer, start = 0) {
788
+ return new DataView(buffer).getInt32(start, false);
789
+ }
790
+ function readInt64(buffer, start = 0) {
791
+ return new DataView(buffer).getBigInt64(start, false);
792
+ }
793
+ function readInt(buffer) {
794
+ switch (buffer.byteLength) {
795
+ case 1:
796
+ return readInt8(buffer);
797
+ case 2:
798
+ return readInt16(buffer);
799
+ case 4:
800
+ return readInt32(buffer);
801
+ case 8:
802
+ return readInt64(buffer);
803
+ case 16:
804
+ return readUInt64(buffer, 8);
805
+ }
806
+ throw new Error(`Invalid int length: ${buffer.byteLength}`);
807
+ }
808
+ function swapBytes(buffer) {
809
+ const array = new Uint8Array(buffer);
810
+ for (let i = 0;i < array.length; i += 2) {
811
+ const a = array[i];
812
+ array[i] = array[i + 1];
813
+ array[i + 1] = a;
814
+ }
815
+ return array.buffer;
816
+ }
817
+ var parse = (buffer) => {
818
+ const headerBytes = buffer.slice(0, HEADER_BINARY.length);
819
+ if (DECODER_UTF8.decode(headerBytes) !== HEADER_BINARY) {
820
+ throw new Error(`Invalid binary plist. Expected '${HEADER_BINARY}' at offset 0.`);
821
+ }
822
+ const trailer = buffer.slice(buffer.byteLength - 32, buffer.byteLength);
823
+ const offsetSize = readUInt8(trailer, 6);
824
+ const objectRefSize = readUInt8(trailer, 7);
825
+ const numObjects = Number(readUInt64(trailer, 8));
826
+ const topObject = Number(readUInt64(trailer, 16));
827
+ const offsetTableOffset = Number(readUInt64(trailer, 24));
828
+ if (numObjects > maxObjectCount) {
829
+ throw new Error("maxObjectCount exceeded");
830
+ }
831
+ const offsetTable = [];
832
+ for (let i = 0;i < numObjects; i++) {
833
+ const offsetBytes = buffer.slice(offsetTableOffset + i * offsetSize, offsetTableOffset + (i + 1) * offsetSize);
834
+ offsetTable[i] = Number(readUInt(offsetBytes));
835
+ }
836
+ function parseObject(tableOffset) {
837
+ const offset = offsetTable[tableOffset];
838
+ const type = readUInt8(buffer, offset);
839
+ const objType = (type & 240) >> 4;
840
+ const objInfo = type & 15;
841
+ switch (objType) {
842
+ case 0:
843
+ return parseSimple();
844
+ case 1:
845
+ return parseInteger();
846
+ case 8:
847
+ return parseUID();
848
+ case 2:
849
+ return parseReal();
850
+ case 3:
851
+ return parseDate();
852
+ case 4:
853
+ return parseData();
854
+ case 5:
855
+ return parsePlistString();
856
+ case 6:
857
+ return parsePlistString(true);
858
+ case 10:
859
+ return parseArray();
860
+ case 13:
861
+ return parseDictionary();
862
+ default:
863
+ throw new Error("Unhandled type 0x" + objType.toString(16));
864
+ }
865
+ function parseSimple() {
866
+ switch (objInfo) {
867
+ case 0:
868
+ return null;
869
+ case 8:
870
+ return false;
871
+ case 9:
872
+ return true;
873
+ case 15:
874
+ return null;
875
+ default:
876
+ throw new Error("Unhandled simple type 0x" + objType.toString(16));
877
+ }
878
+ }
879
+ function parseInteger() {
880
+ const length = Math.pow(2, objInfo);
881
+ if (length < maxObjectSize) {
882
+ const data = buffer.slice(offset + 1, offset + 1 + length);
883
+ return readInt(data);
884
+ }
885
+ throw new Error("Too little heap space available! Wanted to read " + length + " bytes, but only " + maxObjectSize + " are available.");
886
+ }
887
+ function parseUID() {
888
+ const length = objInfo + 1;
889
+ if (length < maxObjectSize) {
890
+ return {
891
+ CF$UID: readUInt(buffer.slice(offset + 1, offset + 1 + length))
892
+ };
893
+ }
894
+ throw new Error("Too little heap space available! Wanted to read " + length + " bytes, but only " + maxObjectSize + " are available.");
895
+ }
896
+ function parseReal() {
897
+ const length = Math.pow(2, objInfo);
898
+ if (length < maxObjectSize) {
899
+ const realBuffer = buffer.slice(offset + 1, offset + 1 + length);
900
+ if (length === 4) {
901
+ return readFloat(realBuffer);
902
+ } else if (length === 8) {
903
+ return readDouble(realBuffer);
904
+ }
905
+ throw new Error(`Invalid real length: ${length}`);
906
+ } else {
907
+ throw new Error("Too little heap space available! Wanted to read " + length + " bytes, but only " + maxObjectSize + " are available.");
908
+ }
909
+ }
910
+ function parseDate() {
911
+ if (objInfo != 3) {
912
+ console.error("Unknown date type :" + objInfo + ". Parsing anyway...");
913
+ }
914
+ const dateBuffer = buffer.slice(offset + 1, offset + 9);
915
+ return new Date(EPOCH2 + 1000 * readDouble(dateBuffer));
916
+ }
917
+ function parseData() {
918
+ let dataoffset = 1;
919
+ let length = objInfo;
920
+ if (objInfo == 15) {
921
+ const int_type = readInt8(buffer, offset + 1);
922
+ const intType = (int_type & 240) / 16;
923
+ if (intType != 1) {
924
+ console.error("0x4: UNEXPECTED LENGTH-INT TYPE! " + intType);
925
+ }
926
+ const intInfo = int_type & 15;
927
+ const intLength = Math.pow(2, intInfo);
928
+ dataoffset = 2 + intLength;
929
+ length = Number(readUInt(buffer.slice(offset + 2, offset + 2 + intLength)));
930
+ }
931
+ if (length < maxObjectSize) {
932
+ return buffer.slice(offset + dataoffset, offset + dataoffset + Number(length));
933
+ }
934
+ throw new Error("Too little heap space available! Wanted to read " + length + " bytes, but only " + maxObjectSize + " are available.");
935
+ }
936
+ function parsePlistString(isUtf16 = false) {
937
+ let length = objInfo;
938
+ let stroffset = 1;
939
+ if (objInfo == 15) {
940
+ const int_type = readUInt8(buffer, offset + 1);
941
+ const intType = (int_type & 240) / 16;
942
+ if (intType != 1) {
943
+ console.error("UNEXPECTED LENGTH-INT TYPE! " + intType);
944
+ }
945
+ const intInfo = int_type & 15;
946
+ const intLength = Math.pow(2, intInfo);
947
+ stroffset = 2 + intLength;
948
+ length = Number(readUInt(buffer.slice(offset + 2, offset + 2 + intLength)));
949
+ }
950
+ length *= isUtf16 ? 2 : 1;
951
+ if (length < maxObjectSize) {
952
+ let plistString = buffer.slice(offset + stroffset, offset + stroffset + length);
953
+ if (isUtf16) {
954
+ plistString = swapBytes(plistString);
955
+ return DECODER_UTF16.decode(plistString);
956
+ } else {
957
+ return DECODER_UTF8.decode(plistString);
958
+ }
959
+ }
960
+ throw new Error("Too little heap space available! Wanted to read " + length + " bytes, but only " + maxObjectSize + " are available.");
961
+ }
962
+ function parseArray() {
963
+ let length = objInfo;
964
+ let arrayoffset = 1;
965
+ if (objInfo == 15) {
966
+ const int_type = readUInt8(buffer, offset + 1);
967
+ const intType = (int_type & 240) / 16;
968
+ if (intType != 1) {
969
+ console.error("0xa: UNEXPECTED LENGTH-INT TYPE! " + intType);
970
+ }
971
+ const intInfo = int_type & 15;
972
+ const intLength = Math.pow(2, intInfo);
973
+ arrayoffset = 2 + intLength;
974
+ length = Number(readUInt(buffer.slice(offset + 2, offset + 2 + intLength)));
975
+ }
976
+ if (length * objectRefSize > maxObjectSize) {
977
+ throw new Error("Too little heap space available!");
978
+ }
979
+ const array = [];
980
+ for (let i = 0;i < length; i++) {
981
+ const objRef = Number(readUInt(buffer.slice(offset + arrayoffset + i * objectRefSize, offset + arrayoffset + (i + 1) * objectRefSize)));
982
+ array[i] = parseObject(objRef);
983
+ }
984
+ return array;
985
+ }
986
+ function parseDictionary() {
987
+ let length = objInfo;
988
+ let dictoffset = 1;
989
+ if (objInfo == 15) {
990
+ const int_type = readUInt8(buffer, offset + 1);
991
+ const intType = (int_type & 240) / 16;
992
+ if (intType != 1) {
993
+ console.error("0xD: UNEXPECTED LENGTH-INT TYPE! " + intType);
994
+ }
995
+ const intInfo = int_type & 15;
996
+ const intLength = Math.pow(2, intInfo);
997
+ dictoffset = 2 + intLength;
998
+ length = Number(readUInt(buffer.slice(offset + 2, offset + 2 + intLength)));
999
+ }
1000
+ if (length * 2 * objectRefSize > maxObjectSize) {
1001
+ throw new Error("Too little heap space available!");
1002
+ }
1003
+ const dict = {};
1004
+ for (let i = 0;i < length; i++) {
1005
+ const keyRef = Number(readUInt(buffer.slice(offset + dictoffset + i * objectRefSize, offset + dictoffset + (i + 1) * objectRefSize)));
1006
+ const valRef = Number(readUInt(buffer.slice(offset + dictoffset + length * objectRefSize + i * objectRefSize, offset + dictoffset + length * objectRefSize + (i + 1) * objectRefSize)));
1007
+ const key = parseObject(keyRef);
1008
+ if (typeof key !== "string") {
1009
+ throw new Error("Invalid key type.");
1010
+ }
1011
+ if (key === "__proto__") {
1012
+ throw new Error("Attempted prototype pollution");
1013
+ }
1014
+ const val = parseObject(valRef);
1015
+ dict[key] = val;
1016
+ }
1017
+ return dict;
1018
+ }
1019
+ }
1020
+ return parseObject(topObject);
1021
+ };
1022
+ // ../../node_modules/@plist/binary.serialize/lib/esm/index.js
1023
+ var encoder = new TextEncoder;
1024
+ var nullBytes = new Uint8Array([0, 0, 0, 0, 0, 0]);
1025
+ var fromHexString = (hexString) => Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
1026
+ var isUID = (value) => !!value && typeof value === "object" && Object.keys(value).length == 1 && typeof value.CF$UID === "number";
1027
+ var toUTF16 = (string) => {
1028
+ const buf = new ArrayBuffer(string.length * 2);
1029
+ const bufView = new Uint16Array(buf);
1030
+ for (let i = 0, strLen = string.length;i < strLen; i++) {
1031
+ bufView[i] = string.charCodeAt(i);
1032
+ }
1033
+ return new Uint8Array(buf);
1034
+ };
1035
+ var concat2 = (first, second) => {
1036
+ const third = new Uint8Array(first.length + second.length);
1037
+ third.set(first);
1038
+ third.set(second, first.length);
1039
+ return third;
1040
+ };
1041
+ var writeUInt = (buffer, int2, size) => {
1042
+ const output = new Uint8Array(buffer.length + size);
1043
+ const dataView = new DataView(output.buffer);
1044
+ output.set(buffer);
1045
+ switch (size) {
1046
+ case 1:
1047
+ dataView.setUint8(buffer.length, Number(int2));
1048
+ break;
1049
+ case 2:
1050
+ dataView.setUint16(buffer.length, Number(int2), false);
1051
+ break;
1052
+ case 4:
1053
+ dataView.setUint32(buffer.length, Number(int2), false);
1054
+ break;
1055
+ case 8:
1056
+ dataView.setBigUint64(buffer.length, BigInt(int2), false);
1057
+ break;
1058
+ default:
1059
+ throw new Error("Unsupported int size");
1060
+ }
1061
+ return output;
1062
+ };
1063
+ var writeInt = (buffer, int2, size) => {
1064
+ const output = new Uint8Array(buffer.length + size);
1065
+ const dataView = new DataView(output.buffer);
1066
+ output.set(buffer);
1067
+ switch (size) {
1068
+ case 1:
1069
+ dataView.setInt8(buffer.length, Number(int2));
1070
+ break;
1071
+ case 2:
1072
+ dataView.setInt16(buffer.length, Number(int2), false);
1073
+ break;
1074
+ case 4:
1075
+ dataView.setInt32(buffer.length, Number(int2), false);
1076
+ break;
1077
+ case 8:
1078
+ dataView.setBigInt64(buffer.length, BigInt(int2), false);
1079
+ break;
1080
+ default:
1081
+ throw new Error("Unsupported int size");
1082
+ }
1083
+ return output;
1084
+ };
1085
+ var writeDouble = (buffer, double) => {
1086
+ const output = new Uint8Array(buffer.length + 8);
1087
+ const dataView = new DataView(output.buffer);
1088
+ output.set(buffer);
1089
+ dataView.setFloat64(buffer.length, double);
1090
+ return output;
1091
+ };
1092
+ var serialize = (value) => {
1093
+ let buffer = encoder.encode(HEADER_BINARY);
1094
+ if (value instanceof Array && value.length === 1) {
1095
+ value = value[0];
1096
+ }
1097
+ let entries = toEntries(value);
1098
+ const idSizeInBytes = computeIdSizeInBytes(entries.length);
1099
+ const offsets = [];
1100
+ let offsetSizeInBytes;
1101
+ let offsetTableOffset;
1102
+ updateEntryIds();
1103
+ entries.forEach((entry, entryIdx) => {
1104
+ offsets[entryIdx] = buffer.byteLength;
1105
+ if (typeof entry === "undefined" || entry === null) {
1106
+ buffer = writeUInt(buffer, 0, 1);
1107
+ } else {
1108
+ write(entry);
1109
+ }
1110
+ });
1111
+ writeOffsetTable();
1112
+ writeTrailer();
1113
+ return buffer.buffer;
1114
+ function updateEntryIds() {
1115
+ const strings = {};
1116
+ let entryId = 0;
1117
+ entries.forEach((entry) => {
1118
+ if (entry.id) {
1119
+ return;
1120
+ }
1121
+ if (typeof entry.value === "string") {
1122
+ if (strings.hasOwnProperty(entry.value)) {
1123
+ entry.type = "stringref";
1124
+ entry.id = strings[entry.value];
1125
+ } else {
1126
+ strings[entry.value] = entry.id = entryId++;
1127
+ }
1128
+ } else {
1129
+ entry.id = entryId++;
1130
+ }
1131
+ });
1132
+ entries = entries.filter((entry) => {
1133
+ return entry.type !== "stringref";
1134
+ });
1135
+ }
1136
+ function writeTrailer() {
1137
+ buffer = concat2(buffer, nullBytes);
1138
+ buffer = concat2(buffer, new Uint8Array([offsetSizeInBytes, idSizeInBytes]));
1139
+ buffer = writeUInt(buffer, BigInt(entries.length), 8);
1140
+ buffer = writeUInt(buffer, BigInt("0"), 8);
1141
+ buffer = writeUInt(buffer, BigInt(offsetTableOffset), 8);
1142
+ }
1143
+ function writeOffsetTable() {
1144
+ offsetTableOffset = buffer.byteLength;
1145
+ offsetSizeInBytes = computeOffsetSizeInBytes(offsetTableOffset);
1146
+ offsets.forEach((offset) => {
1147
+ buffer = writeUInt(buffer, offset, offsetSizeInBytes);
1148
+ });
1149
+ }
1150
+ function write(entry) {
1151
+ if (entry.type === "primitive") {
1152
+ const value2 = entry.value;
1153
+ switch (typeof value2) {
1154
+ case "number":
1155
+ case "bigint":
1156
+ writeNumber(value2);
1157
+ break;
1158
+ case "string":
1159
+ writeString(value2);
1160
+ break;
1161
+ case "boolean":
1162
+ writeBoolean(value2);
1163
+ break;
1164
+ }
1165
+ if (value2 instanceof Date) {
1166
+ writeDate(value2);
1167
+ } else if (value2 instanceof ArrayBuffer) {
1168
+ writeData(value2);
1169
+ } else if (isUID(value2)) {
1170
+ writeUID(value2.CF$UID);
1171
+ }
1172
+ return;
1173
+ }
1174
+ switch (entry.type) {
1175
+ case "dict":
1176
+ writeDict(entry);
1177
+ break;
1178
+ case "array":
1179
+ writeArray(entry);
1180
+ break;
1181
+ default:
1182
+ throw new Error("unhandled entry type: " + entry.type);
1183
+ }
1184
+ }
1185
+ function writeDate(value2) {
1186
+ buffer = writeUInt(buffer, 51, 1);
1187
+ const date = (value2.getTime() - EPOCH2) / 1000;
1188
+ buffer = writeDouble(buffer, date);
1189
+ }
1190
+ function writeDict(entry) {
1191
+ writeIntHeader(13, entry.entryKeys.length);
1192
+ entry.entryKeys.forEach((entry2) => {
1193
+ writeID(entry2.id);
1194
+ });
1195
+ entry.entryValues.forEach((entry2) => {
1196
+ writeID(entry2.id);
1197
+ });
1198
+ }
1199
+ function writeNumber(value2) {
1200
+ if (typeof value2 === "bigint") {
1201
+ const width = 16;
1202
+ const hex = value2.toString(16);
1203
+ const buf = fromHexString(hex.padStart(width * 2, "0").slice(0, width * 2));
1204
+ buffer = writeUInt(buffer, 20, 1);
1205
+ buffer = concat2(buffer, buf);
1206
+ } else {
1207
+ if (Number.isInteger(value2)) {
1208
+ if (value2 < 0) {
1209
+ buffer = writeUInt(buffer, 19, 1);
1210
+ buffer = writeInt(buffer, value2, 8);
1211
+ } else if (value2 <= 255) {
1212
+ buffer = writeUInt(buffer, 16, 1);
1213
+ buffer = writeUInt(buffer, value2, 1);
1214
+ } else if (value2 <= 65535) {
1215
+ buffer = writeUInt(buffer, 17, 1);
1216
+ buffer = writeUInt(buffer, value2, 2);
1217
+ } else if (value2 <= 4294967295) {
1218
+ buffer = writeUInt(buffer, 18, 1);
1219
+ buffer = writeUInt(buffer, value2, 4);
1220
+ } else {
1221
+ buffer = writeUInt(buffer, 19, 1);
1222
+ buffer = writeUInt(buffer, value2, 8);
1223
+ }
1224
+ } else {
1225
+ buffer = writeUInt(buffer, 35, 1);
1226
+ buffer = writeDouble(buffer, value2);
1227
+ }
1228
+ }
1229
+ }
1230
+ function writeUID(uid) {
1231
+ writeIntHeader(8, 0);
1232
+ writeID(uid);
1233
+ }
1234
+ function writeArray(entry) {
1235
+ writeIntHeader(10, entry.entries.length);
1236
+ entry.entries.forEach((e) => {
1237
+ writeID(e.id);
1238
+ });
1239
+ }
1240
+ function writeBoolean(value2) {
1241
+ buffer = writeUInt(buffer, value2 ? 9 : 8, 1);
1242
+ }
1243
+ function writeString(value2) {
1244
+ if (mustBeUtf16(value2)) {
1245
+ const utf16 = toUTF16(value2);
1246
+ writeIntHeader(6, utf16.length / 2);
1247
+ for (let i = 0;i < utf16.length; i += 2) {
1248
+ const t = utf16[i + 0];
1249
+ utf16[i + 0] = utf16[i + 1];
1250
+ utf16[i + 1] = t;
1251
+ }
1252
+ buffer = concat2(buffer, utf16);
1253
+ } else {
1254
+ const utf8 = encoder.encode(value2);
1255
+ writeIntHeader(5, utf8.length);
1256
+ buffer = concat2(buffer, utf8);
1257
+ }
1258
+ }
1259
+ function writeData(data) {
1260
+ writeIntHeader(4, data.byteLength);
1261
+ buffer = concat2(buffer, new Uint8Array(data));
1262
+ }
1263
+ function writeIntHeader(kind, value2) {
1264
+ if (value2 < 15) {
1265
+ buffer = writeUInt(buffer, (kind << 4) + value2, 1);
1266
+ } else {
1267
+ buffer = writeUInt(buffer, (kind << 4) + 15, 1);
1268
+ writeNumber(value2);
1269
+ }
1270
+ }
1271
+ function writeID(id) {
1272
+ buffer = writeUInt(buffer, id, idSizeInBytes);
1273
+ }
1274
+ function mustBeUtf16(string) {
1275
+ return encoder.encode(string).byteLength != string.length;
1276
+ }
1277
+ };
1278
+ var typeofPrimitive = ["string", "number", "boolean", "bigint"];
1279
+ function toEntries(value) {
1280
+ if (typeofPrimitive.includes(typeof value) || value instanceof ArrayBuffer || value instanceof Date || isUID(value)) {
1281
+ return [
1282
+ {
1283
+ type: "primitive",
1284
+ value
1285
+ }
1286
+ ];
1287
+ }
1288
+ if (value != null && typeof value === "object") {
1289
+ return Array.isArray(value) ? toEntriesArray(value) : toEntriesObject(value);
1290
+ }
1291
+ throw new Error("unhandled entry: " + value);
1292
+ }
1293
+ function toEntriesArray(array) {
1294
+ const entries = array.map(toEntries);
1295
+ return [
1296
+ {
1297
+ type: "array",
1298
+ value: undefined,
1299
+ entries: entries.map((entries2) => entries2[0])
1300
+ },
1301
+ ...entries.flat()
1302
+ ];
1303
+ }
1304
+ function toEntriesObject(dict) {
1305
+ const entryKeys = Object.keys(dict).map(toEntries).flat(1);
1306
+ const entryValues = Object.values(dict).map(toEntries);
1307
+ return [
1308
+ {
1309
+ type: "dict",
1310
+ value: undefined,
1311
+ entryKeys,
1312
+ entryValues: entryValues.map((entries) => entries[0])
1313
+ },
1314
+ ...entryKeys,
1315
+ ...entryValues.flat()
1316
+ ];
1317
+ }
1318
+ function computeOffsetSizeInBytes(maxOffset) {
1319
+ if (maxOffset < 256) {
1320
+ return 1;
1321
+ }
1322
+ if (maxOffset < 65536) {
1323
+ return 2;
1324
+ }
1325
+ if (maxOffset < 4294967296) {
1326
+ return 4;
1327
+ }
1328
+ return 8;
1329
+ }
1330
+ function computeIdSizeInBytes(numberOfIds) {
1331
+ if (numberOfIds < 256) {
1332
+ return 1;
1333
+ }
1334
+ if (numberOfIds < 65536) {
1335
+ return 2;
1336
+ }
1337
+ return 4;
1338
+ }
458
1339
  // src/rtsp.ts
459
1340
  var exports_rtsp = {};
460
1341
  __export(exports_rtsp, {
@@ -569,7 +1450,7 @@ function parseResponseHeaders(buffer) {
569
1450
  var exports_tlv8 = {};
570
1451
  __export(exports_tlv8, {
571
1452
  encode: () => encode3,
572
- decode: () => decode3,
1453
+ decode: () => decode4,
573
1454
  bail: () => bail,
574
1455
  Value: () => Value,
575
1456
  State: () => State,
@@ -664,7 +1545,7 @@ function encode3(entries) {
664
1545
  }
665
1546
  return Buffer.from(chunks);
666
1547
  }
667
- function decode3(buf) {
1548
+ function decode4(buf) {
668
1549
  const map = new Map;
669
1550
  let i = 0;
670
1551
  while (i < buf.length) {
@@ -686,5 +1567,6 @@ export {
686
1567
  exports_rtsp as RTSP,
687
1568
  exports_plist as Plist,
688
1569
  exports_opack as OPack,
689
- exports_ntp as NTP
1570
+ exports_ntp as NTP,
1571
+ exports_daap as DAAP
690
1572
  };
package/dist/rtsp.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type Method = "GET" | "OPTIONS" | "POST" | "PUT" | "GET_PARAMETER" | "SET_PARAMETER" | "ANNOUNCE" | "RECORD" | "SETUP" | "TEARDOWN";
1
+ export type Method = "GET" | "OPTIONS" | "POST" | "PUT" | "GET_PARAMETER" | "SET_PARAMETER" | "ANNOUNCE" | "FLUSH" | "RECORD" | "SETUP" | "TEARDOWN";
2
2
  export declare function makeHeader(method: Method, path: string, headers: HeadersInit, cseq: number, activeRemote: string, dacpId: string, sessionId: string): string;
3
3
  export declare function makeRequest(buffer: Buffer): HttpRequest | null;
4
4
  export declare function makeResponse(buffer: Buffer): HttpResponse | null;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@basmilius/apple-encoding",
3
3
  "description": "Common encoding utilities for Apple Protocols.",
4
- "version": "0.5.3",
4
+ "version": "0.6.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -38,12 +38,10 @@
38
38
  "default": "./dist/index.js"
39
39
  }
40
40
  },
41
- "dependencies": {
42
- "@plist/binary.parse": "^1.1.0",
43
- "@plist/binary.serialize": "^1.1.0"
44
- },
45
41
  "devDependencies": {
46
42
  "@basmilius/tools": "^2.23.0",
43
+ "@plist/binary.parse": "^1.1.0",
44
+ "@plist/binary.serialize": "^1.1.0",
47
45
  "@types/bun": "^1.3.8"
48
46
  }
49
47
  }