appium-ios-remotexpc 0.0.3 → 0.0.4
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/CHANGELOG.md +6 -0
- package/build/src/base-plist-service.d.ts +51 -0
- package/build/src/base-plist-service.d.ts.map +1 -0
- package/build/src/base-plist-service.js +61 -0
- package/build/src/base-socket-service.d.ts +15 -0
- package/build/src/base-socket-service.d.ts.map +1 -0
- package/build/src/base-socket-service.js +46 -0
- package/build/src/index.d.ts +9 -0
- package/build/src/index.d.ts.map +1 -0
- package/build/src/index.js +7 -0
- package/build/src/lib/apple-tv/constants.d.ts +49 -0
- package/build/src/lib/apple-tv/constants.d.ts.map +1 -0
- package/build/src/lib/apple-tv/constants.js +71 -0
- package/build/src/lib/apple-tv/errors.d.ts +17 -0
- package/build/src/lib/apple-tv/errors.d.ts.map +1 -0
- package/build/src/lib/apple-tv/errors.js +30 -0
- package/build/src/lib/apple-tv/tlv/decoder.d.ts +19 -0
- package/build/src/lib/apple-tv/tlv/decoder.d.ts.map +1 -0
- package/build/src/lib/apple-tv/tlv/decoder.js +49 -0
- package/build/src/lib/apple-tv/tlv/encoder.d.ts +10 -0
- package/build/src/lib/apple-tv/tlv/encoder.d.ts.map +1 -0
- package/build/src/lib/apple-tv/tlv/encoder.js +20 -0
- package/build/src/lib/apple-tv/tlv/index.d.ts +4 -0
- package/build/src/lib/apple-tv/tlv/index.d.ts.map +1 -0
- package/build/src/lib/apple-tv/tlv/index.js +3 -0
- package/build/src/lib/apple-tv/tlv/pairing-tlv.d.ts +14 -0
- package/build/src/lib/apple-tv/tlv/pairing-tlv.d.ts.map +1 -0
- package/build/src/lib/apple-tv/tlv/pairing-tlv.js +27 -0
- package/build/src/lib/apple-tv/types.d.ts +36 -0
- package/build/src/lib/apple-tv/types.d.ts.map +1 -0
- package/build/src/lib/apple-tv/types.js +1 -0
- package/build/src/lib/apple-tv/utils/buffer-utils.d.ts +40 -0
- package/build/src/lib/apple-tv/utils/buffer-utils.d.ts.map +1 -0
- package/build/src/lib/apple-tv/utils/buffer-utils.js +76 -0
- package/build/src/lib/apple-tv/utils/index.d.ts +3 -0
- package/build/src/lib/apple-tv/utils/index.d.ts.map +1 -0
- package/build/src/lib/apple-tv/utils/index.js +2 -0
- package/build/src/lib/apple-tv/utils/uuid-generator.d.ts +9 -0
- package/build/src/lib/apple-tv/utils/uuid-generator.d.ts.map +1 -0
- package/build/src/lib/apple-tv/utils/uuid-generator.js +36 -0
- package/build/src/lib/lockdown/index.d.ts +87 -0
- package/build/src/lib/lockdown/index.d.ts.map +1 -0
- package/build/src/lib/lockdown/index.js +324 -0
- package/build/src/lib/pair-record/index.d.ts +3 -0
- package/build/src/lib/pair-record/index.d.ts.map +1 -0
- package/build/src/lib/pair-record/index.js +2 -0
- package/build/src/lib/pair-record/pair-record.d.ts +48 -0
- package/build/src/lib/pair-record/pair-record.d.ts.map +1 -0
- package/build/src/lib/pair-record/pair-record.js +85 -0
- package/build/src/lib/plist/binary-plist-creator.d.ts +14 -0
- package/build/src/lib/plist/binary-plist-creator.d.ts.map +1 -0
- package/build/src/lib/plist/binary-plist-creator.js +475 -0
- package/build/src/lib/plist/binary-plist-parser.d.ts +14 -0
- package/build/src/lib/plist/binary-plist-parser.d.ts.map +1 -0
- package/build/src/lib/plist/binary-plist-parser.js +449 -0
- package/build/src/lib/plist/constants.d.ts +36 -0
- package/build/src/lib/plist/constants.d.ts.map +1 -0
- package/build/src/lib/plist/constants.js +43 -0
- package/build/src/lib/plist/index.d.ts +14 -0
- package/build/src/lib/plist/index.d.ts.map +1 -0
- package/build/src/lib/plist/index.js +16 -0
- package/build/src/lib/plist/length-based-splitter.d.ts +43 -0
- package/build/src/lib/plist/length-based-splitter.d.ts.map +1 -0
- package/build/src/lib/plist/length-based-splitter.js +228 -0
- package/build/src/lib/plist/plist-creator.d.ts +8 -0
- package/build/src/lib/plist/plist-creator.d.ts.map +1 -0
- package/build/src/lib/plist/plist-creator.js +33 -0
- package/build/src/lib/plist/plist-decoder.d.ts +25 -0
- package/build/src/lib/plist/plist-decoder.d.ts.map +1 -0
- package/build/src/lib/plist/plist-decoder.js +103 -0
- package/build/src/lib/plist/plist-encoder.d.ts +10 -0
- package/build/src/lib/plist/plist-encoder.d.ts.map +1 -0
- package/build/src/lib/plist/plist-encoder.js +27 -0
- package/build/src/lib/plist/plist-parser.d.ts +9 -0
- package/build/src/lib/plist/plist-parser.d.ts.map +1 -0
- package/build/src/lib/plist/plist-parser.js +109 -0
- package/build/src/lib/plist/plist-service.d.ts +86 -0
- package/build/src/lib/plist/plist-service.d.ts.map +1 -0
- package/build/src/lib/plist/plist-service.js +180 -0
- package/build/src/lib/plist/unified-plist-creator.d.ts +9 -0
- package/build/src/lib/plist/unified-plist-creator.d.ts.map +1 -0
- package/build/src/lib/plist/unified-plist-creator.js +14 -0
- package/build/src/lib/plist/unified-plist-parser.d.ts +8 -0
- package/build/src/lib/plist/unified-plist-parser.d.ts.map +1 -0
- package/build/src/lib/plist/unified-plist-parser.js +23 -0
- package/build/src/lib/plist/utils.d.ts +97 -0
- package/build/src/lib/plist/utils.d.ts.map +1 -0
- package/build/src/lib/plist/utils.js +287 -0
- package/build/src/lib/remote-xpc/constants.d.ts +20 -0
- package/build/src/lib/remote-xpc/constants.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/constants.js +21 -0
- package/build/src/lib/remote-xpc/handshake-frames.d.ts +74 -0
- package/build/src/lib/remote-xpc/handshake-frames.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/handshake-frames.js +285 -0
- package/build/src/lib/remote-xpc/handshake.d.ts +14 -0
- package/build/src/lib/remote-xpc/handshake.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/handshake.js +95 -0
- package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts +55 -0
- package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/remote-xpc-connection.js +365 -0
- package/build/src/lib/remote-xpc/xpc-protocol.d.ts +22 -0
- package/build/src/lib/remote-xpc/xpc-protocol.d.ts.map +1 -0
- package/build/src/lib/remote-xpc/xpc-protocol.js +368 -0
- package/build/src/lib/tunnel/index.d.ts +69 -0
- package/build/src/lib/tunnel/index.d.ts.map +1 -0
- package/build/src/lib/tunnel/index.js +205 -0
- package/build/src/lib/tunnel/packet-stream-client.d.ts +46 -0
- package/build/src/lib/tunnel/packet-stream-client.d.ts.map +1 -0
- package/build/src/lib/tunnel/packet-stream-client.js +152 -0
- package/build/src/lib/tunnel/packet-stream-server.d.ts +37 -0
- package/build/src/lib/tunnel/packet-stream-server.d.ts.map +1 -0
- package/build/src/lib/tunnel/packet-stream-server.js +109 -0
- package/build/src/lib/tunnel/tunnel-api-client.d.ts +85 -0
- package/build/src/lib/tunnel/tunnel-api-client.d.ts.map +1 -0
- package/build/src/lib/tunnel/tunnel-api-client.js +207 -0
- package/build/src/lib/tunnel/tunnel-registry-server.d.ts +68 -0
- package/build/src/lib/tunnel/tunnel-registry-server.d.ts.map +1 -0
- package/build/src/lib/tunnel/tunnel-registry-server.js +351 -0
- package/build/src/lib/types.d.ts +238 -0
- package/build/src/lib/types.d.ts.map +1 -0
- package/build/src/lib/types.js +4 -0
- package/build/src/lib/usbmux/index.d.ts +177 -0
- package/build/src/lib/usbmux/index.d.ts.map +1 -0
- package/build/src/lib/usbmux/index.js +490 -0
- package/build/src/lib/usbmux/usbmux-decoder.d.ts +19 -0
- package/build/src/lib/usbmux/usbmux-decoder.d.ts.map +1 -0
- package/build/src/lib/usbmux/usbmux-decoder.js +38 -0
- package/build/src/lib/usbmux/usbmux-encoder.d.ts +12 -0
- package/build/src/lib/usbmux/usbmux-encoder.d.ts.map +1 -0
- package/build/src/lib/usbmux/usbmux-encoder.js +32 -0
- package/build/src/service-connection.d.ts +34 -0
- package/build/src/service-connection.d.ts.map +1 -0
- package/build/src/service-connection.js +51 -0
- package/build/src/services/index.d.ts +6 -0
- package/build/src/services/index.d.ts.map +1 -0
- package/build/src/services/index.js +5 -0
- package/build/src/services/ios/base-service.d.ts +35 -0
- package/build/src/services/ios/base-service.d.ts.map +1 -0
- package/build/src/services/ios/base-service.js +55 -0
- package/build/src/services/ios/diagnostic-service/index.d.ts +46 -0
- package/build/src/services/ios/diagnostic-service/index.d.ts.map +1 -0
- package/build/src/services/ios/diagnostic-service/index.js +169 -0
- package/build/src/services/ios/diagnostic-service/keys.d.ts +5 -0
- package/build/src/services/ios/diagnostic-service/keys.d.ts.map +1 -0
- package/build/src/services/ios/diagnostic-service/keys.js +770 -0
- package/build/src/services/ios/syslog-service/index.d.ts +91 -0
- package/build/src/services/ios/syslog-service/index.d.ts.map +1 -0
- package/build/src/services/ios/syslog-service/index.js +323 -0
- package/build/src/services/ios/tunnel-service/index.d.ts +17 -0
- package/build/src/services/ios/tunnel-service/index.d.ts.map +1 -0
- package/build/src/services/ios/tunnel-service/index.js +57 -0
- package/build/src/services.d.ts +14 -0
- package/build/src/services.d.ts.map +1 -0
- package/build/src/services.js +48 -0
- package/package.json +12 -3
- package/.github/dependabot.yml +0 -38
- package/.github/workflows/format-check.yml +0 -43
- package/.github/workflows/lint-and-build.yml +0 -40
- package/.github/workflows/pr-title.yml +0 -16
- package/.github/workflows/publish.js.yml +0 -43
- package/.github/workflows/test-validation.yml +0 -40
- package/.mocharc.json +0 -8
- package/.prettierignore +0 -3
- package/.prettierrc +0 -17
- package/.releaserc +0 -48
- package/assets/images/ios-arch.png +0 -0
- package/eslint.config.js +0 -45
- package/npm-shrinkwrap.json +0 -2711
- package/test/integration/diagnostics-test.ts +0 -44
- package/test/integration/read-pair-record-test.ts +0 -39
- package/test/integration/tunnel-test.ts +0 -104
- package/test/unit/apple-tv/tlv/decoder.spec.ts +0 -144
- package/test/unit/apple-tv/tlv/encoder.spec.ts +0 -91
- package/test/unit/apple-tv/tlv/pairing-tlv.spec.ts +0 -101
- package/test/unit/apple-tv/tlv/tlv-integration.spec.ts +0 -146
- package/test/unit/apple-tv/utils/buffer-utils.spec.ts +0 -74
- package/test/unit/apple-tv/utils/uuid-generator.spec.ts +0 -39
- package/test/unit/fixtures/index.ts +0 -88
- package/test/unit/fixtures/usbmuxconnectmessage.bin +0 -0
- package/test/unit/fixtures/usbmuxlistdevicemessage.bin +0 -0
- package/test/unit/plist/error-handling.spec.ts +0 -101
- package/test/unit/plist/fixtures/sample.binary.plist +0 -0
- package/test/unit/plist/fixtures/sample.xml.plist +0 -38
- package/test/unit/plist/plist-parser.spec.ts +0 -283
- package/test/unit/plist/plist.spec.ts +0 -205
- package/test/unit/plist/tag-position-handling.spec.ts +0 -90
- package/test/unit/plist/unified-plist-parser.spec.ts +0 -227
- package/test/unit/plist/utils.spec.ts +0 -249
- package/test/unit/plist/xml-cleaning.spec.ts +0 -60
- package/test/unit/tunnel/tunnel-registry-server.spec.ts +0 -194
- package/test/unit/usbmux/usbmux-specs.ts +0 -71
- package/tsconfig.json +0 -36
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { logger } from '@appium/support';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
const log = logger.getLogger('PairRecord');
|
|
5
|
+
/**
|
|
6
|
+
* Converts a buffer containing PEM data to a string
|
|
7
|
+
* @param buffer - Buffer containing PEM data
|
|
8
|
+
* @returns String representation of the PEM data
|
|
9
|
+
*/
|
|
10
|
+
function bufferToPEMString(buffer) {
|
|
11
|
+
return buffer.toString('utf8');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Processes raw response from plist.parsePlist and formats it into a proper pair-record
|
|
15
|
+
* @param response - Response from plist.parsePlist(data.payload.PairRecordData)
|
|
16
|
+
* @returns Formatted pair-record object with properly structured data
|
|
17
|
+
*/
|
|
18
|
+
export function processPlistResponse(response) {
|
|
19
|
+
return {
|
|
20
|
+
HostID: response.HostID || null,
|
|
21
|
+
SystemBUID: response.SystemBUID || null,
|
|
22
|
+
HostCertificate: response.HostCertificate
|
|
23
|
+
? bufferToPEMString(response.HostCertificate)
|
|
24
|
+
: null,
|
|
25
|
+
HostPrivateKey: response.HostPrivateKey
|
|
26
|
+
? bufferToPEMString(response.HostPrivateKey)
|
|
27
|
+
: null,
|
|
28
|
+
DeviceCertificate: response.DeviceCertificate
|
|
29
|
+
? bufferToPEMString(response.DeviceCertificate)
|
|
30
|
+
: null,
|
|
31
|
+
RootCertificate: response.RootCertificate
|
|
32
|
+
? bufferToPEMString(response.RootCertificate)
|
|
33
|
+
: null,
|
|
34
|
+
RootPrivateKey: response.RootPrivateKey
|
|
35
|
+
? bufferToPEMString(response.RootPrivateKey)
|
|
36
|
+
: null,
|
|
37
|
+
WiFiMACAddress: response.WiFiMACAddress || null,
|
|
38
|
+
// For EscrowBag, we need it as a base64 string
|
|
39
|
+
EscrowBag: response.EscrowBag
|
|
40
|
+
? response.EscrowBag.toString('base64')
|
|
41
|
+
: null,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/* --- File storage functions remain unchanged --- */
|
|
45
|
+
const RECORDS_DIR = path.join(process.cwd(), '../../.records');
|
|
46
|
+
async function ensureRecordsDirectoryExists() {
|
|
47
|
+
await fs.promises.mkdir(RECORDS_DIR, { recursive: true, mode: 0o777 });
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Saves a pair record to the filesystem.
|
|
51
|
+
* @param udid - Device UDID.
|
|
52
|
+
* @param pairRecord - Pair record to save.
|
|
53
|
+
* @returns Promise that resolves when record is saved.
|
|
54
|
+
*/
|
|
55
|
+
export async function savePairRecord(udid, pairRecord) {
|
|
56
|
+
await ensureRecordsDirectoryExists();
|
|
57
|
+
const recordPath = path.join(RECORDS_DIR, `${udid}-record.json`);
|
|
58
|
+
try {
|
|
59
|
+
await fs.promises.writeFile(recordPath, JSON.stringify(pairRecord, null, 2), { mode: 0o777 });
|
|
60
|
+
log.info(`Pair record saved: ${recordPath}`);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
log.error(`Failed to save pair record for ${udid}: ${error}`);
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Gets a saved pair record from the filesystem.
|
|
69
|
+
* @param udid - Device UDID.
|
|
70
|
+
* @returns Promise that resolves with the pair record or null if not found.
|
|
71
|
+
*/
|
|
72
|
+
export async function getPairRecord(udid) {
|
|
73
|
+
const recordPath = path.join(RECORDS_DIR, `${udid}-record.json`);
|
|
74
|
+
try {
|
|
75
|
+
const data = await fs.promises.readFile(recordPath, 'utf8');
|
|
76
|
+
return JSON.parse(data);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error.code === 'ENOENT') {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
log.error(`Failed to read pair record for ${udid}: ${error}`);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary Property List (bplist) Creator
|
|
3
|
+
*
|
|
4
|
+
* This module provides functionality to create binary property lists (bplists)
|
|
5
|
+
* commonly used in Apple's iOS and macOS systems.
|
|
6
|
+
*/
|
|
7
|
+
import type { PlistValue } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Creates a binary plist from a JavaScript object
|
|
10
|
+
* @param obj - The JavaScript object to convert to a binary plist
|
|
11
|
+
* @returns Buffer containing the binary plist data
|
|
12
|
+
*/
|
|
13
|
+
export declare function createBinaryPlist(obj: PlistValue): Buffer;
|
|
14
|
+
//# sourceMappingURL=binary-plist-creator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-plist-creator.d.ts","sourceRoot":"","sources":["../../../../src/lib/plist/binary-plist-creator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAmB,UAAU,EAAE,MAAM,aAAa,CAAC;AA4iB/D;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAGzD"}
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
import { APPLE_EPOCH_OFFSET, BPLIST_MAGIC_AND_VERSION, BPLIST_TRAILER_SIZE, BPLIST_TYPE, } from './constants.js';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a value is a plain object (not null, not an array, not a Date, not a Buffer)
|
|
4
|
+
* @param value - The value to check
|
|
5
|
+
* @returns True if the value is a plain object
|
|
6
|
+
*/
|
|
7
|
+
function isPlainObject(value) {
|
|
8
|
+
return (typeof value === 'object' &&
|
|
9
|
+
value !== null &&
|
|
10
|
+
!Array.isArray(value) &&
|
|
11
|
+
!(value instanceof Date) &&
|
|
12
|
+
!(value instanceof Buffer) &&
|
|
13
|
+
Object.getPrototypeOf(value) === Object.prototype);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Class for creating binary property lists
|
|
17
|
+
*/
|
|
18
|
+
class BinaryPlistCreator {
|
|
19
|
+
_objectTable = [];
|
|
20
|
+
_objectRefMap = new Map();
|
|
21
|
+
_objectRefSize = 0;
|
|
22
|
+
_offsetSize = 0;
|
|
23
|
+
_rootObject;
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new BinaryPlistCreator
|
|
26
|
+
* @param rootObject - The root object to convert to a binary plist
|
|
27
|
+
*/
|
|
28
|
+
constructor(rootObject) {
|
|
29
|
+
this._rootObject = rootObject;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates the binary plist
|
|
33
|
+
* @returns Buffer containing the binary plist data
|
|
34
|
+
*/
|
|
35
|
+
create() {
|
|
36
|
+
// Collect all objects and assign IDs
|
|
37
|
+
this._collectObjects();
|
|
38
|
+
// Create object data
|
|
39
|
+
const objectOffsets = [];
|
|
40
|
+
const objectData = [];
|
|
41
|
+
for (const value of this._objectTable) {
|
|
42
|
+
objectOffsets.push(this._calculateObjectDataLength(objectData));
|
|
43
|
+
objectData.push(this._createObjectData(value));
|
|
44
|
+
}
|
|
45
|
+
// Calculate offset table size
|
|
46
|
+
const maxOffset = this._calculateObjectDataLength(objectData);
|
|
47
|
+
this._offsetSize = this._calculateMinByteSize(maxOffset);
|
|
48
|
+
// Create offset table
|
|
49
|
+
const offsetTable = this._createOffsetTable(objectOffsets);
|
|
50
|
+
// Calculate offset table offset
|
|
51
|
+
const offsetTableOffset = BPLIST_MAGIC_AND_VERSION.length +
|
|
52
|
+
this._calculateObjectDataLength(objectData);
|
|
53
|
+
// Create trailer
|
|
54
|
+
const trailer = this._createTrailer(this._objectTable.length, offsetTableOffset);
|
|
55
|
+
// Combine all parts
|
|
56
|
+
return Buffer.concat([
|
|
57
|
+
BPLIST_MAGIC_AND_VERSION,
|
|
58
|
+
...objectData,
|
|
59
|
+
offsetTable,
|
|
60
|
+
trailer,
|
|
61
|
+
]);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Collects all unique objects in the object hierarchy
|
|
65
|
+
*/
|
|
66
|
+
_collectObjects() {
|
|
67
|
+
this._collectObjectsRecursive(this._rootObject);
|
|
68
|
+
// Calculate the object reference size based on the number of objects
|
|
69
|
+
const numObjects = this._objectTable.length;
|
|
70
|
+
this._objectRefSize = this._calculateMinByteSize(numObjects - 1);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Recursively collects objects from a value
|
|
74
|
+
* @param value - The value to collect objects from
|
|
75
|
+
*/
|
|
76
|
+
_collectObjectsRecursive(value) {
|
|
77
|
+
// Skip if already in the table
|
|
78
|
+
if (this._objectRefMap.has(value)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Add to the table and map
|
|
82
|
+
const id = this._objectTable.length;
|
|
83
|
+
this._objectTable.push(value);
|
|
84
|
+
this._objectRefMap.set(value, id);
|
|
85
|
+
// Recursively collect objects for arrays and dictionaries
|
|
86
|
+
if (Array.isArray(value)) {
|
|
87
|
+
for (const item of value) {
|
|
88
|
+
this._collectObjectsRecursive(item);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (value !== null && isPlainObject(value)) {
|
|
92
|
+
// This is a dictionary
|
|
93
|
+
const dict = value;
|
|
94
|
+
for (const key of Object.keys(dict)) {
|
|
95
|
+
this._collectObjectsRecursive(key);
|
|
96
|
+
this._collectObjectsRecursive(dict[key]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Calculates the minimum number of bytes needed to represent a number
|
|
102
|
+
* @param value - The number to calculate for
|
|
103
|
+
* @returns The minimum number of bytes needed (1, 2, 4, or 8)
|
|
104
|
+
*/
|
|
105
|
+
_calculateMinByteSize(value) {
|
|
106
|
+
if (value < 256) {
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
else if (value < 65536) {
|
|
110
|
+
return 2;
|
|
111
|
+
}
|
|
112
|
+
else if (value < 4294967296) {
|
|
113
|
+
return 4;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
return 8;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Calculates the total length of object data buffers
|
|
121
|
+
* @param buffers - Array of buffers
|
|
122
|
+
* @returns Total length
|
|
123
|
+
*/
|
|
124
|
+
_calculateObjectDataLength(buffers) {
|
|
125
|
+
return buffers.reduce((sum, buffer) => sum + buffer.length, 0);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Writes an offset value to a buffer
|
|
129
|
+
* @param buffer - Target buffer
|
|
130
|
+
* @param position - Position in the buffer
|
|
131
|
+
* @param value - Value to write
|
|
132
|
+
* @param size - Number of bytes to use
|
|
133
|
+
*/
|
|
134
|
+
_writeOffsetToBuffer(buffer, position, value, size) {
|
|
135
|
+
if (size === 1) {
|
|
136
|
+
buffer.writeUInt8(Number(value), position);
|
|
137
|
+
}
|
|
138
|
+
else if (size === 2) {
|
|
139
|
+
buffer.writeUInt16BE(Number(value), position);
|
|
140
|
+
}
|
|
141
|
+
else if (size === 4) {
|
|
142
|
+
buffer.writeUInt32BE(Number(value), position);
|
|
143
|
+
}
|
|
144
|
+
else if (size === 8) {
|
|
145
|
+
// Use BigInt directly for the value to avoid potential precision issues
|
|
146
|
+
buffer.writeBigUInt64BE(typeof value === 'bigint' ? value : BigInt(value), position);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Writes a BigInt to a buffer
|
|
151
|
+
* @param buffer - Target buffer
|
|
152
|
+
* @param position - Position in the buffer
|
|
153
|
+
* @param value - BigInt value to write
|
|
154
|
+
*/
|
|
155
|
+
_writeBigIntToBuffer(buffer, position, value) {
|
|
156
|
+
buffer.writeBigUInt64BE(value, position);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Creates binary data for a null value
|
|
160
|
+
* @returns Buffer containing the binary data
|
|
161
|
+
*/
|
|
162
|
+
_createNullData() {
|
|
163
|
+
return Buffer.from([BPLIST_TYPE.NULL]);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Creates binary data for a boolean value
|
|
167
|
+
* @param value - The boolean value
|
|
168
|
+
* @returns Buffer containing the binary data
|
|
169
|
+
*/
|
|
170
|
+
_createBooleanData(value) {
|
|
171
|
+
return Buffer.from([value ? BPLIST_TYPE.TRUE : BPLIST_TYPE.FALSE]);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Creates binary data for an integer value
|
|
175
|
+
* @param value - The integer value (number or bigint)
|
|
176
|
+
* @returns Buffer containing the binary data
|
|
177
|
+
*/
|
|
178
|
+
_createIntegerData(value) {
|
|
179
|
+
let buffer;
|
|
180
|
+
// If value is a BigInt, handle it directly
|
|
181
|
+
if (typeof value === 'bigint') {
|
|
182
|
+
// For BigInt values, we always use 64-bit representation
|
|
183
|
+
buffer = Buffer.alloc(9);
|
|
184
|
+
buffer.writeUInt8(BPLIST_TYPE.INT | 3, 0);
|
|
185
|
+
buffer.writeBigInt64BE(value, 1);
|
|
186
|
+
}
|
|
187
|
+
// For number values, determine the smallest representation
|
|
188
|
+
else if (value >= 0 && value <= 255) {
|
|
189
|
+
buffer = Buffer.alloc(2);
|
|
190
|
+
buffer.writeUInt8(BPLIST_TYPE.INT | 0, 0);
|
|
191
|
+
buffer.writeUInt8(value, 1);
|
|
192
|
+
}
|
|
193
|
+
else if (value >= -128 && value <= 127) {
|
|
194
|
+
buffer = Buffer.alloc(2);
|
|
195
|
+
buffer.writeUInt8(BPLIST_TYPE.INT | 0, 0);
|
|
196
|
+
buffer.writeInt8(value, 1);
|
|
197
|
+
}
|
|
198
|
+
else if (value >= -32768 && value <= 32767) {
|
|
199
|
+
buffer = Buffer.alloc(3);
|
|
200
|
+
buffer.writeUInt8(BPLIST_TYPE.INT | 1, 0);
|
|
201
|
+
buffer.writeInt16BE(value, 1);
|
|
202
|
+
}
|
|
203
|
+
else if (value >= -2147483648 && value <= 2147483647) {
|
|
204
|
+
buffer = Buffer.alloc(5);
|
|
205
|
+
buffer.writeUInt8(BPLIST_TYPE.INT | 2, 0);
|
|
206
|
+
buffer.writeInt32BE(value, 1);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// 64-bit integer - use BigInt directly to avoid precision issues
|
|
210
|
+
buffer = Buffer.alloc(9);
|
|
211
|
+
buffer.writeUInt8(BPLIST_TYPE.INT | 3, 0);
|
|
212
|
+
buffer.writeBigInt64BE(BigInt(value), 1);
|
|
213
|
+
}
|
|
214
|
+
return buffer;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Creates binary data for a floating point value
|
|
218
|
+
* @param value - The floating point value
|
|
219
|
+
* @returns Buffer containing the binary data
|
|
220
|
+
*/
|
|
221
|
+
_createFloatData(value) {
|
|
222
|
+
const buffer = Buffer.alloc(9);
|
|
223
|
+
buffer.writeUInt8(BPLIST_TYPE.REAL | 3, 0); // Use double precision
|
|
224
|
+
buffer.writeDoubleBE(value, 1);
|
|
225
|
+
return buffer;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Creates binary data for a date value
|
|
229
|
+
* @param value - The date value
|
|
230
|
+
* @returns Buffer containing the binary data
|
|
231
|
+
*/
|
|
232
|
+
_createDateData(value) {
|
|
233
|
+
const buffer = Buffer.alloc(9);
|
|
234
|
+
buffer.writeUInt8(BPLIST_TYPE.DATE, 0);
|
|
235
|
+
// Convert to seconds since Apple epoch (2001-01-01)
|
|
236
|
+
const timestamp = value.getTime() / 1000 - APPLE_EPOCH_OFFSET;
|
|
237
|
+
buffer.writeDoubleBE(timestamp, 1);
|
|
238
|
+
return buffer;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Creates a header for an integer value
|
|
242
|
+
* @param value - The integer value
|
|
243
|
+
* @returns Buffer containing the integer header
|
|
244
|
+
*/
|
|
245
|
+
_createIntHeader(value) {
|
|
246
|
+
let buffer;
|
|
247
|
+
if (value < 256) {
|
|
248
|
+
buffer = Buffer.alloc(2);
|
|
249
|
+
buffer.writeUInt8(BPLIST_TYPE.INT | 0, 0);
|
|
250
|
+
buffer.writeUInt8(value, 1);
|
|
251
|
+
}
|
|
252
|
+
else if (value < 65536) {
|
|
253
|
+
buffer = Buffer.alloc(3);
|
|
254
|
+
buffer.writeUInt8(BPLIST_TYPE.INT | 1, 0);
|
|
255
|
+
buffer.writeUInt16BE(value, 1);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
buffer = Buffer.alloc(5);
|
|
259
|
+
buffer.writeUInt8(BPLIST_TYPE.INT | 2, 0);
|
|
260
|
+
buffer.writeUInt32BE(value, 1);
|
|
261
|
+
}
|
|
262
|
+
return buffer;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Creates binary data for a buffer (data) value
|
|
266
|
+
* @param value - The buffer value
|
|
267
|
+
* @returns Buffer containing the binary data
|
|
268
|
+
*/
|
|
269
|
+
_createBufferData(value) {
|
|
270
|
+
const length = value.length;
|
|
271
|
+
let header;
|
|
272
|
+
if (length < 15) {
|
|
273
|
+
header = Buffer.from([BPLIST_TYPE.DATA | length]);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
// For longer data, we need to encode the length separately
|
|
277
|
+
const lengthBuffer = this._createIntHeader(length);
|
|
278
|
+
header = Buffer.concat([
|
|
279
|
+
Buffer.from([BPLIST_TYPE.DATA | 0x0f]), // 0x0F indicates length follows
|
|
280
|
+
lengthBuffer,
|
|
281
|
+
]);
|
|
282
|
+
}
|
|
283
|
+
return Buffer.concat([header, value]);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Creates binary data for a string value
|
|
287
|
+
* @param value - The string value
|
|
288
|
+
* @returns Buffer containing the binary data
|
|
289
|
+
*/
|
|
290
|
+
_createStringData(value) {
|
|
291
|
+
// Check if string can be ASCII
|
|
292
|
+
// eslint-disable-next-line no-control-regex
|
|
293
|
+
const isAscii = /^[\x00-\x7F]*$/.test(value);
|
|
294
|
+
const stringBuffer = isAscii
|
|
295
|
+
? Buffer.from(value, 'ascii')
|
|
296
|
+
: Buffer.from(value, 'utf16le');
|
|
297
|
+
// Fixed the typo here - using stringBuffer.length instead of value.length for Unicode strings
|
|
298
|
+
const length = isAscii ? value.length : stringBuffer.length / 2;
|
|
299
|
+
let header;
|
|
300
|
+
if (length < 15) {
|
|
301
|
+
header = Buffer.from([
|
|
302
|
+
isAscii
|
|
303
|
+
? BPLIST_TYPE.STRING_ASCII | length
|
|
304
|
+
: BPLIST_TYPE.STRING_UNICODE | length,
|
|
305
|
+
]);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
// For longer strings, we need to encode the length separately
|
|
309
|
+
const lengthBuffer = this._createIntHeader(length);
|
|
310
|
+
header = Buffer.concat([
|
|
311
|
+
Buffer.from([
|
|
312
|
+
isAscii
|
|
313
|
+
? BPLIST_TYPE.STRING_ASCII | 0x0f
|
|
314
|
+
: BPLIST_TYPE.STRING_UNICODE | 0x0f,
|
|
315
|
+
]),
|
|
316
|
+
lengthBuffer,
|
|
317
|
+
]);
|
|
318
|
+
}
|
|
319
|
+
return Buffer.concat([header, stringBuffer]);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Creates binary data for an array value
|
|
323
|
+
* @param value - The array value
|
|
324
|
+
* @returns Buffer containing the binary data
|
|
325
|
+
*/
|
|
326
|
+
_createArrayData(value) {
|
|
327
|
+
const length = value.length;
|
|
328
|
+
let header;
|
|
329
|
+
if (length < 15) {
|
|
330
|
+
header = Buffer.from([BPLIST_TYPE.ARRAY | length]);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
// For longer arrays, we need to encode the length separately
|
|
334
|
+
const lengthBuffer = this._createIntHeader(length);
|
|
335
|
+
header = Buffer.concat([
|
|
336
|
+
Buffer.from([BPLIST_TYPE.ARRAY | 0x0f]), // 0x0F indicates length follows
|
|
337
|
+
lengthBuffer,
|
|
338
|
+
]);
|
|
339
|
+
}
|
|
340
|
+
// Create references to each item
|
|
341
|
+
const refBuffer = Buffer.alloc(length * this._objectRefSize);
|
|
342
|
+
for (let i = 0; i < length; i++) {
|
|
343
|
+
const itemRef = this._objectRefMap.get(value[i]) ?? 0;
|
|
344
|
+
this._writeOffsetToBuffer(refBuffer, i * this._objectRefSize, itemRef, this._objectRefSize);
|
|
345
|
+
}
|
|
346
|
+
return Buffer.concat([header, refBuffer]);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Creates binary data for a dictionary value
|
|
350
|
+
* @param value - The dictionary value
|
|
351
|
+
* @returns Buffer containing the binary data
|
|
352
|
+
*/
|
|
353
|
+
_createDictionaryData(value) {
|
|
354
|
+
const keys = Object.keys(value);
|
|
355
|
+
const length = keys.length;
|
|
356
|
+
let header;
|
|
357
|
+
if (length < 15) {
|
|
358
|
+
header = Buffer.from([BPLIST_TYPE.DICT | length]);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
// For larger dictionaries, we need to encode the length separately
|
|
362
|
+
const lengthBuffer = this._createIntHeader(length);
|
|
363
|
+
header = Buffer.concat([
|
|
364
|
+
Buffer.from([BPLIST_TYPE.DICT | 0x0f]), // 0x0F indicates length follows
|
|
365
|
+
lengthBuffer,
|
|
366
|
+
]);
|
|
367
|
+
}
|
|
368
|
+
// Create references to keys and values
|
|
369
|
+
const keyRefBuffer = Buffer.alloc(length * this._objectRefSize);
|
|
370
|
+
const valueRefBuffer = Buffer.alloc(length * this._objectRefSize);
|
|
371
|
+
for (let i = 0; i < length; i++) {
|
|
372
|
+
const key = keys[i];
|
|
373
|
+
const keyRef = this._objectRefMap.get(key) ?? 0;
|
|
374
|
+
const valueRef = this._objectRefMap.get(value[key]) ?? 0;
|
|
375
|
+
this._writeOffsetToBuffer(keyRefBuffer, i * this._objectRefSize, keyRef, this._objectRefSize);
|
|
376
|
+
this._writeOffsetToBuffer(valueRefBuffer, i * this._objectRefSize, valueRef, this._objectRefSize);
|
|
377
|
+
}
|
|
378
|
+
return Buffer.concat([header, keyRefBuffer, valueRefBuffer]);
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Creates binary data for an object
|
|
382
|
+
* @param value - The value to convert
|
|
383
|
+
* @returns Buffer containing the binary data
|
|
384
|
+
*/
|
|
385
|
+
_createObjectData(value) {
|
|
386
|
+
// Handle null and booleans
|
|
387
|
+
if (value === null) {
|
|
388
|
+
return this._createNullData();
|
|
389
|
+
}
|
|
390
|
+
else if (typeof value === 'boolean') {
|
|
391
|
+
return this._createBooleanData(value);
|
|
392
|
+
}
|
|
393
|
+
// Handle BigInt
|
|
394
|
+
if (typeof value === 'bigint') {
|
|
395
|
+
return this._createIntegerData(value);
|
|
396
|
+
}
|
|
397
|
+
// Handle numbers
|
|
398
|
+
if (typeof value === 'number') {
|
|
399
|
+
// Check if it's an integer
|
|
400
|
+
if (Number.isInteger(value)) {
|
|
401
|
+
return this._createIntegerData(value);
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
// Float
|
|
405
|
+
return this._createFloatData(value);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
// Handle Date
|
|
409
|
+
if (value instanceof Date) {
|
|
410
|
+
return this._createDateData(value);
|
|
411
|
+
}
|
|
412
|
+
// Handle Buffer (DATA)
|
|
413
|
+
if (Buffer.isBuffer(value)) {
|
|
414
|
+
return this._createBufferData(value);
|
|
415
|
+
}
|
|
416
|
+
// Handle strings
|
|
417
|
+
if (typeof value === 'string') {
|
|
418
|
+
return this._createStringData(value);
|
|
419
|
+
}
|
|
420
|
+
// Handle arrays
|
|
421
|
+
if (Array.isArray(value)) {
|
|
422
|
+
return this._createArrayData(value);
|
|
423
|
+
}
|
|
424
|
+
// Handle objects (dictionaries) - using isPlainObject for better type checking
|
|
425
|
+
if (isPlainObject(value)) {
|
|
426
|
+
return this._createDictionaryData(value);
|
|
427
|
+
}
|
|
428
|
+
// Default fallback
|
|
429
|
+
return Buffer.from([BPLIST_TYPE.NULL]);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Creates the offset table
|
|
433
|
+
* @param objectOffsets - Array of object offsets
|
|
434
|
+
* @returns Buffer containing the offset table
|
|
435
|
+
*/
|
|
436
|
+
_createOffsetTable(objectOffsets) {
|
|
437
|
+
const numObjects = this._objectTable.length;
|
|
438
|
+
const offsetTable = Buffer.alloc(numObjects * this._offsetSize);
|
|
439
|
+
for (let i = 0; i < numObjects; i++) {
|
|
440
|
+
this._writeOffsetToBuffer(offsetTable, i * this._offsetSize, objectOffsets[i], this._offsetSize);
|
|
441
|
+
}
|
|
442
|
+
return offsetTable;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Creates the trailer
|
|
446
|
+
* @param numObjects - Number of objects
|
|
447
|
+
* @param offsetTableOffset - Offset of the offset table
|
|
448
|
+
* @returns Buffer containing the trailer
|
|
449
|
+
*/
|
|
450
|
+
_createTrailer(numObjects, offsetTableOffset) {
|
|
451
|
+
const trailer = Buffer.alloc(BPLIST_TRAILER_SIZE);
|
|
452
|
+
// 6 unused bytes
|
|
453
|
+
trailer.fill(0, 0, 6);
|
|
454
|
+
// offset size (1 byte)
|
|
455
|
+
trailer.writeUInt8(this._offsetSize, 6);
|
|
456
|
+
// object ref size (1 byte)
|
|
457
|
+
trailer.writeUInt8(this._objectRefSize, 7);
|
|
458
|
+
// number of objects (8 bytes)
|
|
459
|
+
this._writeBigIntToBuffer(trailer, 8, BigInt(numObjects));
|
|
460
|
+
// top object ID (8 bytes)
|
|
461
|
+
this._writeBigIntToBuffer(trailer, 16, BigInt(0)); // Root object is always the first one
|
|
462
|
+
// offset table offset (8 bytes)
|
|
463
|
+
this._writeBigIntToBuffer(trailer, 24, BigInt(offsetTableOffset));
|
|
464
|
+
return trailer;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Creates a binary plist from a JavaScript object
|
|
469
|
+
* @param obj - The JavaScript object to convert to a binary plist
|
|
470
|
+
* @returns Buffer containing the binary plist data
|
|
471
|
+
*/
|
|
472
|
+
export function createBinaryPlist(obj) {
|
|
473
|
+
const creator = new BinaryPlistCreator(obj);
|
|
474
|
+
return creator.create();
|
|
475
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PlistValue } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses a binary plist buffer into a JavaScript object
|
|
4
|
+
* @param buffer - The binary plist data as a Buffer
|
|
5
|
+
* @returns The parsed JavaScript object
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseBinaryPlist(buffer: Buffer): PlistValue;
|
|
8
|
+
/**
|
|
9
|
+
* Determines if a buffer is a binary plist
|
|
10
|
+
* @param buffer - The buffer to check
|
|
11
|
+
* @returns True if the buffer is a binary plist
|
|
12
|
+
*/
|
|
13
|
+
export declare function isBinaryPlist(buffer: Buffer): boolean;
|
|
14
|
+
//# sourceMappingURL=binary-plist-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-plist-parser.d.ts","sourceRoot":"","sources":["../../../../src/lib/plist/binary-plist-parser.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAA+B,UAAU,EAAE,MAAM,aAAa,CAAC;AA+iB3E;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAG3D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAIrD"}
|