From 99f2db216108d97e7f625f312eed172f03b28b6b Mon Sep 17 00:00:00 2001 From: Stephen <158498287+StephenDev0@users.noreply.github.com> Date: Tue, 23 Jun 2026 12:17:03 -0400 Subject: [PATCH] Initial commit Initial commit --- .gitattributes | 2 + .github/workflows/build.yml | 50 + .gitignore | 19 + LICENSE | 373 ++ README.md | 36 + Resources/universal.js | 296 ++ Sources/BundledScript.swift | 16 + Sources/IdeviceFFI.swift | 21 + Sources/JITSession.swift | 108 + Sources/ScriptRunner.swift | 81 + Sources/StikJIT.swift | 26 + Sources/StikJITError.swift | 25 + idevice/idevice.h | 7593 +++++++++++++++++++++++++++++++++++ idevice/libidevice_ffi.a | Bin 0 -> 97089368 bytes idevice/module.modulemap | 4 + project.yml | 49 + 16 files changed, 8699 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/workflows/build.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Resources/universal.js create mode 100644 Sources/BundledScript.swift create mode 100644 Sources/IdeviceFFI.swift create mode 100644 Sources/JITSession.swift create mode 100644 Sources/ScriptRunner.swift create mode 100644 Sources/StikJIT.swift create mode 100644 Sources/StikJITError.swift create mode 100644 idevice/idevice.h create mode 100644 idevice/libidevice_ffi.a create mode 100644 idevice/module.modulemap create mode 100644 project.yml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..0a160b8 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,50 @@ +name: Build + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + build: + name: Build XCFramework + runs-on: macos-15 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Show toolchain + run: xcodebuild -version + + - name: Install XcodeGen + run: brew install xcodegen + + - name: Generate Xcode project + run: xcodegen generate + + - name: Build framework + run: | + xcodebuild archive \ + -project StikJIT.xcodeproj \ + -scheme StikJIT \ + -destination 'generic/platform=iOS' \ + -archivePath build/StikJIT-iOS \ + SKIP_INSTALL=NO \ + BUILD_LIBRARY_FOR_DISTRIBUTION=YES \ + CODE_SIGNING_ALLOWED=NO + + - name: Assemble XCFramework + run: | + xcodebuild -create-xcframework \ + -framework build/StikJIT-iOS.xcarchive/Products/Library/Frameworks/StikJIT.framework \ + -output StikJIT.xcframework + + - name: Upload XCFramework + uses: actions/upload-artifact@v4 + with: + name: StikJIT.xcframework + path: StikJIT.xcframework + if-no-files-found: error diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9c276f --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Build output +build/ +DerivedData/ + +# The framework is a build artifact — rebuild it with the steps in README.md. +StikJIT.xcframework/ + +# XcodeGen-generated project — run `xcodegen generate`. +*.xcodeproj + +# Xcode user data +xcuserdata/ +*.xcuserstate + +# OS / editor junk +.DS_Store +*.bak +*.swp +*.log diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a612ad9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c8ba78b --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# StikJIT + +An iOS XCFramework that enables JIT for another process over the device's RSD tunnel. Based on StikDebug. + +A separate process (e.g. an app extension) attaches a debugserver to the target by PID, marks its JIT memory executable, then detaches. It is self-contained: the idevice FFI and `universal.js` are bundled inside. The target must carry the `get-task-allow` entitlement. + +## Use + +Add `StikJIT.xcframework` to your target (Embed & Sign), then call it off the main thread: + +```swift +import StikJIT + +try StikJIT.enableJIT( + targetPID: hostPID, // process to enable JIT for + pairingFile: pairingFileURL, // device pairing file + progress: { print("[StikJIT] \($0)") } +) +``` + +It blocks until done and throws `StikJITError` on failure. Pass `configuration:` to override the tunnel endpoint (defaults to `10.7.0.1:49152`). + +## Build + +```sh +xcodegen generate +xcodebuild archive -scheme StikJIT -destination 'generic/platform=iOS' \ + -archivePath build/StikJIT BUILD_LIBRARY_FOR_DISTRIBUTION=YES +xcodebuild -create-xcframework \ + -framework build/StikJIT.xcarchive/Products/Library/Frameworks/StikJIT.framework \ + -output StikJIT.xcframework +``` + +## License + +StikJIT is licensed under the MPL-2.0 (see [`LICENSE`](LICENSE)). It uses StikDebug as a reference, with the bundled [idevice](https://github.com/jkcoxson/idevice) and universal.js retaining their own licenses. diff --git a/Resources/universal.js b/Resources/universal.js new file mode 100644 index 0000000..9bca8f6 --- /dev/null +++ b/Resources/universal.js @@ -0,0 +1,296 @@ +// Universal JIT Script, last updated 2026-29-03 (YYYY-DD-MM) +/* + // JIT "syscalls" + __attribute__((noinline,optnone,naked)) + void JIT26Detach(void) { + asm("mov x16, #0 \n" + "brk #0xf00d \n" + "ret"); + } + __attribute__((noinline,optnone,naked)) + void* JIT26PrepareRegion(void *addr, size_t len) { + asm("mov x16, #1 \n" + "brk #0xf00d \n" + "ret"); + } + + __attribute__((noinline,optnone,naked)) +void BreakSendJITScript(char* script, size_t len) { + asm("mov x16, #2 \n" + "brk #0xf00d \n" + "ret"); +} + */ +const CMD_DETACH = 0; +const CMD_PREPARE_REGION = 1; +const CMD_NEW_BREAKPOINTS = 2; +const commands = { + [CMD_DETACH]: JIT26Detach, + [CMD_PREPARE_REGION]: JIT26PrepareRegion, + [CMD_NEW_BREAKPOINTS]: JIT26NewBreakpoints +}; +const legacyCommands = { + [0x68]: JIT26NewBreakpoints, + [0x69]: JIT26HandleBrk0x69, + [0xf00d]: JIT26HandleBrk0xf00d +}; + +// Log levels +//const LOG_NONE = 0; +const LOG_INFO = 1; +const LOG_VERBOSE = 2; +let logLevel = LOG_INFO; +function log_verbose(msg) { + if (logLevel >= LOG_VERBOSE) { + log(msg); + } +} + +// To avoid having to re-parse these in each function, we save some registers here +let tid, x0, x1, x16, pc; +let detached = false; +let continuesWithSignal = true; +let pid = get_pid(); +let attachResponse = send_command(`vAttach;${pid.toString(16)}`); + +log(`pid = ${pid}`); +log(`attach_response = ${attachResponse}`); + +let totalBreakpoints = 0; +while (!detached) { + totalBreakpoints++; + log(`Handling signal ${totalBreakpoints}`); + + let brkResponse = send_command(`c`); + log_verbose(`brkResponse = ${brkResponse}`); + + // extract tid, pc, x16 + let tmpMatch = /T[0-9a-f]+thread:(?[0-9a-f]+);/.exec(brkResponse); + tid = tmpMatch ? tmpMatch.groups['tid'] : null; + tmpMatch = /20:(?[0-9a-f]{16});/.exec(brkResponse); + pc = tmpMatch ? tmpMatch.groups['reg'] : null; + tmpMatch = /10:(?[0-9a-f]{16});/.exec(brkResponse); + x16 = tmpMatch ? tmpMatch.groups['reg'] : null; + if (!tid || !pc || !x16) { + log(`Failed to extract registers: tid=${tid}, pc=${pc}, x16=${x16}`); + continue; + } + pc = littleEndianHexStringToNumber(pc); + x16 = littleEndianHexStringToNumber(x16); + + let instructionResponse = send_command(`m${pc.toString(16)},4`); + log(`instruction at pc: ${instructionResponse}`); + let instrU32 = littleEndianHexToU32(instructionResponse); + + // check if this is a brk + if ((instrU32 & 0xFFE0001F)>>>0 != 0xD4200000) { + log(`Skipping: instruction was not a brk (was 0x${instrU32.toString(16)})`); + if (continuesWithSignal) { + let signum = /^T(?[a-z0-9;]{2})/.exec(brkResponse); + signum = signum ? signum.groups['sig'] : null; + if (!signum) { + log(`Failed to extract signal number: ${signum}`); + continue; + } + log(`Continuing with signal 0x${signum}`); + send_command(`vCont;S${signum}:${tid}`); + } + continue; + } + + let brkImmediate = extractBrkImmediate(instrU32); + log(`BRK immediate: 0x${brkImmediate.toString(16)} (${brkImmediate})`); + if (legacyCommands[brkImmediate] != undefined) { + // when we find a valid brk immediate command, parse x0 and x1 + tmpMatch = /00:(?[0-9a-f]{16});/.exec(brkResponse); + x0 = tmpMatch ? tmpMatch.groups['reg'] : null; + tmpMatch = /01:(?[0-9a-f]{16});/.exec(brkResponse); + x1 = tmpMatch ? tmpMatch.groups['reg'] : null; + if (!x0 || !x1) { + log(`Failed to extract registers: x0=${x0}, x1=${x1}`); + continue; + } + x0 = littleEndianHexStringToNumber(x0); + x1 = littleEndianHexStringToNumber(x1); + + // jump over brk + let pcPlus4 = numberToLittleEndianHexString(pc + 4n); + let pcPlus4Response = send_command(`P20=${pcPlus4};thread:${tid};`); + log(`pcPlus4Response = ${pcPlus4Response}`); + + // dispatch brk-immediate command + const command = legacyCommands[brkImmediate]; + command(brkResponse); + } else { + log(`Skipping breakpoint: brk immediate 0x${brkImmediate.toString(16)} was not handled by this script. You could add it by evaluating legacyCommands[0x${brkImmediate.toString(16)}] = yourFunction;`); + continue; + } +} + +function JIT26Detach() { + let detachResponse = send_command(`D`); + log_verbose(`detachResponse = ${detachResponse}`); + detached = true; +} + +// brk 0x68 +function JIT26NewBreakpoints(brkResponse) { + let instructionResponse = send_command(`m${pc.toString(16)},4`); + log(`instruction at pc: ${instructionResponse}`); + let instrU32 = littleEndianHexToU32(instructionResponse); + let brkImmediate = extractBrkImmediate(instrU32); + + let memResponse = send_command(`m${x0.toString(16)},${x1}`); + + let scriptText = hexToAscii(memResponse); + log_verbose(`Script text: ${scriptText}`); + + const res = runScriptAndCapture(scriptText); + if (res.ok) { + log('Script succeeded:', res.value); + } else { + log('Script failed:', res.name, res.message); + log(res.stack); + } +} + +// brk 0x69 +function JIT26HandleBrk0x69(brkResponse) { + // in the old script we chose 0x69, so now we check here and return error + // if you wish to keep using this, you can set your own handler like `legacyCommands[0x69] = yourHandler;` using BreakSendJITScript + log(`Error: It seems you are using legacy breakpoint 0x69. Please set your legacy handler using \`legacyCommands[0x69] = yourHandler;\` or migrate to universal jitcalls to use this script. The function will now return 0xE0000069.`); + let putX0Response = send_command(`P0=E0000069;thread:${tid};`); + log(`putX0Response = ${putX0Response}`); +} + +// brk 0xf00d +function JIT26HandleBrk0xf00d(brkResponse) { + // dispatch command via x16 + const command = commands[x16]; + if (command === undefined) { + log(`Unknown command ${x16.toString(16)}`); + return; + } + log(`Invoking command ${x16.toString(16)}`); + command(brkResponse); +} + +function JIT26PrepareRegion(brkResponse) { + let instructionResponse = send_command(`m${pc.toString(16)},4`); + log(`instruction at pc: ${instructionResponse}`); + let instrU32 = littleEndianHexToU32(instructionResponse); + let brkImmediate = extractBrkImmediate(instrU32); + + if (x0 == 0n && x1 == 0n) { + return; + } + + let jitPageAddress = x0; + if (x0 == 0n) { + let requestRXResponse = send_command(`_M${x1.toString(16)},rx`); + log_verbose(`requestRXResponse = ${requestRXResponse}`); + + if (!requestRXResponse || requestRXResponse.length === 0) { + log(`Failed to allocate RX memory`); + return; + } + + jitPageAddress = BigInt(`0x${requestRXResponse}`); + log(`Allocated JIT page at address: 0x${jitPageAddress.toString(16)}`); + } + + let prepareJITPageResponse = prepare_memory_region(jitPageAddress, x1); + log(`prepareJITPageResponse = ${prepareJITPageResponse}`); + + let putX0Response = send_command(`P0=${numberToLittleEndianHexString(jitPageAddress)};thread:${tid};`); + log(`putX0Response = ${putX0Response}`); +} + +// utilities +function littleEndianHexStringToNumber(hexStr) { + const bytes = []; + for (let i = 0; i < hexStr.length; i += 2) { + bytes.push(parseInt(hexStr.substr(i, 2), 16)); + } + let num = 0n; + for (let i = 4; i >= 0; i--) { + num = (num << 8n) | BigInt(bytes[i]); + } + return num; +} + +function numberToLittleEndianHexString(num) { + const bytes = []; + for (let i = 0; i < 5; i++) { + bytes.push(Number(num & 0xFFn)); + num >>= 8n; + } + while (bytes.length < 8) { + bytes.push(0); + } + return bytes.map(b => b.toString(16).padStart(2, '0')).join(''); +} + +function littleEndianHexToU32(hexStr) { + return parseInt(hexStr.match(/../g).reverse().join(''), 16); +} + +function extractBrkImmediate(u32) { + return (u32 >> 5) & 0xFFFF; +} + +function hexToAscii(hexStr) { + let str = ''; + for (let i = 0; i < hexStr.length; i += 2) { + const byte = parseInt(hexStr.substr(i, 2), 16); + if (byte === 0) break; + str += String.fromCharCode(byte); + } + return str; +} + +function runScriptAndCapture(scriptText) { + try { + const value = eval(scriptText); + return { ok: true, value }; + } catch (err) { + return { + ok: false, + name: err && err.name, + message: err && err.message, + stack: err && err.stack + }; + } +} + +// For making your own script / adding your own breakpoints. you can send this string to BreakSendJITScript and it'll add it for any subsequent breakpoints +// x0, x1, x16, pc and tid are global variables. If you need more registers, parse them like: +// tmpMatch = /02:(?[0-9a-f]{16});/.exec(brkResponse); // x2 +// let x2 = tmpMatch ? tmpMatch.groups['reg'] : null; +// if (!x2) { +// log(`Failed to extract registers: x2=${x2}`); +// return; +// } +// x2 = littleEndianHexStringToNumber(x2); +// +/* +commands[3] = wowBreakPoint; + +function wowBreakPoint(brekpoint) { + let instructionResponse = send_command(`m${pc.toString(16)},4`); + log(`instruction at pc: ${instructionResponse}`); + let instrU32 = littleEndianHexToU32(instructionResponse); + let brkImmediate = extractBrkImmediate(instrU32); + + if (x0 == 0n && x1 == 0n) { + return; + } + + let jitPageAddress = x0; + let prepareJITPageResponse = prepare_memory_region(jitPageAddress, x1); + log(`prepareJITPageResponse = ${prepareJITPageResponse}`); + + let putX0Response = send_command(`P0=${numberToLittleEndianHexString(jitPageAddress)};thread:${tid};`); + log(`putX0Response = ${putX0Response}`); +} +*/ diff --git a/Sources/BundledScript.swift b/Sources/BundledScript.swift new file mode 100644 index 0000000..80df5b4 --- /dev/null +++ b/Sources/BundledScript.swift @@ -0,0 +1,16 @@ +import Foundation + +enum BundledScript { + + static func universalJS() throws -> String { + let bundle = Bundle(for: BundleToken.self) + guard let url = bundle.url(forResource: "universal", withExtension: "js"), + let source = try? String(contentsOf: url, encoding: .utf8), + !source.isEmpty else { + throw StikJITError.scriptUnavailable + } + return source + } +} + +private final class BundleToken {} diff --git a/Sources/IdeviceFFI.swift b/Sources/IdeviceFFI.swift new file mode 100644 index 0000000..6a952b7 --- /dev/null +++ b/Sources/IdeviceFFI.swift @@ -0,0 +1,21 @@ +import Foundation +@_implementationOnly import idevice + +enum IdeviceFFI { + + static func consume(_ pointer: UnsafeMutablePointer?, + fallback: String) -> StikJITError { + guard let pointer else { return .device(code: -1, subCode: 0, message: fallback) } + let error = StikJITError.device( + code: pointer.pointee.code, + subCode: pointer.pointee.sub_code, + message: pointer.pointee.message.map { String(cString: $0) } ?? fallback) + idevice_error_free(pointer) + return error + } + + static func check(_ fallback: String, + _ call: () -> UnsafeMutablePointer?) throws { + if let error = call() { throw consume(error, fallback: fallback) } + } +} diff --git a/Sources/JITSession.swift b/Sources/JITSession.swift new file mode 100644 index 0000000..cd84b9b --- /dev/null +++ b/Sources/JITSession.swift @@ -0,0 +1,108 @@ +import Foundation +@_implementationOnly import idevice + +final class JITSession { + + struct Tunnel { + var adapter: OpaquePointer? + var handshake: OpaquePointer? + func free() { + if let handshake { rsd_handshake_free(handshake) } + if let adapter { adapter_free(adapter) } + } + } + + private struct DebugSession { + var remoteServer: OpaquePointer? + var debugProxy: OpaquePointer? + func free() { + if let debugProxy { debug_proxy_free(debugProxy) } + if let remoteServer { remote_server_free(remoteServer) } + } + } + + private let pairingFilePath: String + private let configuration: StikJIT.Configuration + + init(pairingFilePath: String, configuration: StikJIT.Configuration) { + self.pairingFilePath = pairingFilePath + self.configuration = configuration + } + + func enableJIT(targetPID: Int32, progress: @escaping (String) -> Void) throws { + let tunnel = try makeTunnel() + defer { tunnel.free() } + + let session = try connectDebugSession(over: tunnel) + defer { session.free() } + + guard let debugProxy = session.debugProxy else { throw StikJITError.debugProxyUnavailable } + + debug_proxy_send_ack(debugProxy) + _ = try? sendCommand("QStartNoAckMode", over: debugProxy) + debug_proxy_set_ack_mode(debugProxy, 0) + + try ScriptRunner(targetPID: targetPID, debugProxy: debugProxy, progress: progress).run() + } + + private func openPairingFile() throws -> OpaquePointer { + guard !pairingFilePath.isEmpty, FileManager.default.fileExists(atPath: pairingFilePath) else { + throw StikJITError.pairingFile("not found at \(pairingFilePath)") + } + var handle: OpaquePointer? + try IdeviceFFI.check("failed to read pairing file") { + pairingFilePath.withCString { rp_pairing_file_read($0, &handle) } + } + guard let handle else { throw StikJITError.pairingFile("unreadable at \(pairingFilePath)") } + return handle + } + + private func makeTunnel() throws -> Tunnel { + let pairing = try openPairingFile() + defer { rp_pairing_file_free(pairing) } + + var address = sockaddr_in() + address.sin_family = sa_family_t(AF_INET) + address.sin_port = configuration.rsdPort.bigEndian + _ = configuration.deviceAddress.withCString { inet_pton(AF_INET, $0, &address.sin_addr) } + + var tunnel = Tunnel() + try IdeviceFFI.check("failed to create RSD tunnel") { + "StikJIT".withCString { hostname in + withUnsafePointer(to: &address) { pointer in + pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { sa in + tunnel_create_rppairing( + sa, socklen_t(MemoryLayout.stride), + hostname, pairing, nil, nil, + &tunnel.adapter, &tunnel.handshake) + } + } + } + } + return tunnel + } + + private func connectDebugSession(over tunnel: Tunnel) throws -> DebugSession { + var session = DebugSession() + try IdeviceFFI.check("failed to connect remote server") { + remote_server_connect_rsd(tunnel.adapter, tunnel.handshake, &session.remoteServer) + } + try IdeviceFFI.check("failed to connect debug proxy") { + debug_proxy_connect_rsd(tunnel.adapter, tunnel.handshake, &session.debugProxy) + } + return session + } + + @discardableResult + private func sendCommand(_ command: String, over debugProxy: OpaquePointer) throws -> String? { + guard let handle = command.withCString({ debugserver_command_new($0, nil, 0) }) else { return nil } + defer { debugserver_command_free(handle) } + var response: UnsafeMutablePointer? + try IdeviceFFI.check("debugserver command failed") { + debug_proxy_send_command(debugProxy, handle, &response) + } + guard let response else { return nil } + defer { idevice_string_free(response) } + return String(cString: response) + } +} diff --git a/Sources/ScriptRunner.swift b/Sources/ScriptRunner.swift new file mode 100644 index 0000000..13e81c7 --- /dev/null +++ b/Sources/ScriptRunner.swift @@ -0,0 +1,81 @@ +import Foundation +import JavaScriptCore +@_implementationOnly import idevice + +final class ScriptRunner { + + private static let jitPageSize: UInt64 = 16384 + + private let targetPID: Int32 + private let debugProxy: OpaquePointer + private let progress: (String) -> Void + private var context: JSContext? + + init(targetPID: Int32, debugProxy: OpaquePointer, progress: @escaping (String) -> Void) { + self.targetPID = targetPID + self.debugProxy = debugProxy + self.progress = progress + } + + func run() throws { + let source = try BundledScript.universalJS() + + guard let context = JSContext() else { throw StikJITError.scriptUnavailable } + self.context = context + + context.exceptionHandler = { [weak self] _, value in + self?.progress("JS exception: \(value?.toString() ?? "")") + } + + let getPID: @convention(block) () -> Int = { [targetPID] in Int(targetPID) } + let send: @convention(block) (String?) -> String = { [weak self] command in + guard let self, let command else { return "" } + return self.sendCommand(command) ?? "" + } + let prepare: @convention(block) (Double, Double) -> String = { [weak self] address, length in + guard let self else { return "" } + return self.prepareMemoryRegion(UInt64(address), length: UInt64(length)) ?? "OK" + } + let log: @convention(block) (JSValue?) -> Void = { [weak self] value in + self?.progress(value?.toString() ?? "") + } + + context.setObject(getPID, forKeyedSubscript: "get_pid" as NSString) + context.setObject(send, forKeyedSubscript: "send_command" as NSString) + context.setObject(prepare, forKeyedSubscript: "prepare_memory_region" as NSString) + context.setObject(log, forKeyedSubscript: "log" as NSString) + + progress("Running universal.js against pid \(targetPID)…") + context.evaluateScript(source) + progress("JIT script finished (region blessed, detached).") + } + + private func sendCommand(_ command: String) -> String? { + guard let handle = command.withCString({ debugserver_command_new($0, nil, 0) }) else { return nil } + defer { debugserver_command_free(handle) } + var response: UnsafeMutablePointer? + if let error = debug_proxy_send_command(debugProxy, handle, &response) { + progress("send_command error: \(IdeviceFFI.consume(error, fallback: "send_command").localizedDescription)") + return nil + } + guard let response else { return "" } + defer { idevice_string_free(response) } + return String(cString: response) + } + + private func prepareMemoryRegion(_ address: UInt64, length: UInt64) -> String? { + guard length > 0 else { return "OK" } + let pageCount = (length - 1) / Self.jitPageSize + 1 + for page in 0.. Void = { _ in }) throws { + let session = JITSession(pairingFilePath: pairingFile.path, configuration: configuration) + try session.enableJIT(targetPID: targetPID, progress: progress) + } +} diff --git a/Sources/StikJITError.swift b/Sources/StikJITError.swift new file mode 100644 index 0000000..17dac40 --- /dev/null +++ b/Sources/StikJITError.swift @@ -0,0 +1,25 @@ +import Foundation + +public enum StikJITError: Error, LocalizedError { + + case pairingFile(String) + + case scriptUnavailable + + case debugProxyUnavailable + + case device(code: Int32, subCode: Int32, message: String) + + public var errorDescription: String? { + switch self { + case .pairingFile(let detail): + return "Pairing file error: \(detail)." + case .scriptUnavailable: + return "The bundled universal.js could not be loaded from the StikJIT framework." + case .debugProxyUnavailable: + return "Failed to establish a debugserver connection to the target process." + case .device(let code, let subCode, let message): + return "\(message) (idevice code \(code)/\(subCode))." + } + } +} diff --git a/idevice/idevice.h b/idevice/idevice.h new file mode 100644 index 0000000..b429ce2 --- /dev/null +++ b/idevice/idevice.h @@ -0,0 +1,7593 @@ +// Jackson Coxson +// Bindings to idevice - https://github.com/jkcoxson/idevice + +#ifdef _WIN32 + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include + #include + typedef int idevice_socklen_t; + typedef struct sockaddr idevice_sockaddr; +#else + #include + #include + typedef socklen_t idevice_socklen_t; + typedef struct sockaddr idevice_sockaddr; +#endif + + +#ifndef IDEVICE_H +#define IDEVICE_H + +#include +#include +#include +#include + +#define LOCKDOWN_PORT 62078 + +typedef enum AfcFopenMode { + AfcRdOnly = 1, + AfcRw = 2, + AfcWrOnly = 3, + AfcWr = 4, + AfcAppend = 5, + AfcRdAppend = 6, +} AfcFopenMode; + +/** + * Link type for creating hard or symbolic links + */ +typedef enum AfcLinkType { + Hard = 1, + Symbolic = 2, +} AfcLinkType; + +typedef enum IdeviceLoggerError { + Success = 0, + FileError = -1, + AlreadyInitialized = -2, + InvalidPathString = -3, +} IdeviceLoggerError; + +typedef enum IdeviceLogLevel { + Disabled = 0, + ErrorLevel = 1, + Warn = 2, + Info = 3, + Debug = 4, + Trace = 5, +} IdeviceLogLevel; + +typedef struct AdapterHandle AdapterHandle; + +typedef struct AdapterStreamHandle AdapterStreamHandle; + +typedef struct AfcClientHandle AfcClientHandle; + +/** + * Handle for an open file on the device + */ +typedef struct AfcFileHandle AfcFileHandle; + +typedef struct AmfiClientHandle AmfiClientHandle; + +/** + * Opaque handle to an AppServiceClient + */ +typedef struct AppServiceHandle AppServiceHandle; + +typedef struct BtPacketLoggerClientHandle BtPacketLoggerClientHandle; + +typedef struct CompanionProxyClientHandle CompanionProxyClientHandle; + +typedef struct CoreDeviceProxyHandle CoreDeviceProxyHandle; + +typedef struct CrashReportCopyMobileHandle CrashReportCopyMobileHandle; + +/** + * Opaque handle to a DebugProxyClient + */ +typedef struct DebugProxyHandle DebugProxyHandle; + +typedef struct DiagnosticsRelayClientHandle DiagnosticsRelayClientHandle; + +/** + * Opaque handle to an AppServiceClient + */ +typedef struct DiagnosticsServiceHandle DiagnosticsServiceHandle; + +typedef struct HeartbeatClientHandle HeartbeatClientHandle; + +typedef struct HouseArrestClientHandle HouseArrestClientHandle; + +/** + * Opaque C-compatible handle to an Idevice connection + */ +typedef struct IdeviceHandle IdeviceHandle; + +/** + * Opaque C-compatible handle to a PairingFile + */ +typedef struct IdevicePairingFile IdevicePairingFile; + +typedef struct IdeviceProviderHandle IdeviceProviderHandle; + +typedef struct IdeviceSocketHandle IdeviceSocketHandle; + +typedef struct ImageMounterHandle ImageMounterHandle; + +typedef struct InstallationProxyClientHandle InstallationProxyClientHandle; + +typedef struct InstallcoordinationProxyHandle InstallcoordinationProxyHandle; + +/** + * Opaque handle to a ProcessControlClient + */ +typedef struct LocationSimulationHandle LocationSimulationHandle; + +typedef struct LocationSimulationServiceHandle LocationSimulationServiceHandle; + +typedef struct LockdowndClientHandle LockdowndClientHandle; + +typedef struct MisagentClientHandle MisagentClientHandle; + +/** + * Opaque handle wrapping a provider pointer for MobileActivationd. + * The client is recreated per call since each request requires a new connection. + */ +typedef struct MobileActivationdClientHandle MobileActivationdClientHandle; + +typedef struct MobileBackup2ClientHandle MobileBackup2ClientHandle; + +typedef struct NotificationProxyClientHandle NotificationProxyClientHandle; + +typedef struct OsTraceRelayClientHandle OsTraceRelayClientHandle; + +typedef struct OsTraceRelayReceiverHandle OsTraceRelayReceiverHandle; + +typedef struct PcapdClientHandle PcapdClientHandle; + +typedef struct PreboardServiceClientHandle PreboardServiceClientHandle; + +/** + * Opaque handle to a ProcessControlClient + */ +typedef struct ProcessControlHandle ProcessControlHandle; + +typedef struct ReadWriteOpaque ReadWriteOpaque; + +/** + * Opaque handle to a RemoteServerClient + */ +typedef struct RemoteServerHandle RemoteServerHandle; + +typedef struct RestoreServiceClientHandle RestoreServiceClientHandle; + +/** + * Opaque handle to an RPPairing file + */ +typedef struct RpPairingFileHandle RpPairingFileHandle; + +/** + * Opaque handle to an RsdHandshake + */ +typedef struct RsdHandshakeHandle RsdHandshakeHandle; + +/** + * An opaque FFI handle for a [`ScreenshotClient`]. + * + * This type wraps a [`ScreenshotClient`] that communicates with + * a connected device to capture screenshots through the DVT (Device Virtualization Toolkit) service. + */ +typedef struct ScreenshotClientHandle ScreenshotClientHandle; + +typedef struct ScreenshotrClientHandle ScreenshotrClientHandle; + +typedef struct SpringBoardServicesClientHandle SpringBoardServicesClientHandle; + +typedef struct SysdiagnoseStreamHandle SysdiagnoseStreamHandle; + +typedef struct SyslogRelayClientHandle SyslogRelayClientHandle; + +typedef struct TcpEatObject TcpEatObject; + +typedef struct TcpFeedObject TcpFeedObject; + +typedef struct UsbmuxdAddrHandle UsbmuxdAddrHandle; + +typedef struct UsbmuxdConnectionHandle UsbmuxdConnectionHandle; + +typedef struct UsbmuxdDeviceHandle UsbmuxdDeviceHandle; + +typedef struct UsbmuxdListenerHandle UsbmuxdListenerHandle; + +typedef struct Vec_u64 Vec_u64; + +typedef struct IdeviceFfiError { + int32_t code; + int32_t sub_code; + const char *message; +} IdeviceFfiError; + +/** + * Stub to avoid header problems + */ +typedef void *plist_t; + +/** + * File information structure for C bindings + */ +typedef struct AfcFileInfo { + size_t size; + size_t blocks; + int64_t creation; + int64_t modified; + char *st_nlink; + char *st_ifmt; + char *st_link_target; +} AfcFileInfo; + +/** + * Device information structure for C bindings + */ +typedef struct AfcDeviceInfo { + char *model; + size_t total_bytes; + size_t free_bytes; + size_t block_size; +} AfcDeviceInfo; + +/** + * Represents a parsed BT packet from the logger + */ +typedef struct BtPacketHandle { + /** + * Header: advisory length + */ + uint32_t length; + /** + * Header: timestamp seconds + */ + uint32_t ts_secs; + /** + * Header: timestamp microseconds + */ + uint32_t ts_usecs; + /** + * Packet kind byte (0x00=HciCmd, 0x01=HciEvt, 0x02=AclSent, 0x03=AclRecv, etc.) + */ + uint8_t kind; + /** + * H4-ready payload data + */ + uint8_t *h4_data; + /** + * Length of h4_data + */ + uintptr_t h4_data_len; +} BtPacketHandle; + +/** + * C-compatible app list entry + */ +typedef struct AppListEntryC { + int is_removable; + char *name; + int is_first_party; + char *path; + char *bundle_identifier; + int is_developer_app; + char *bundle_version; + int is_internal; + int is_hidden; + int is_app_clip; + char *version; +} AppListEntryC; + +/** + * C-compatible launch response + */ +typedef struct LaunchResponseC { + uint32_t process_identifier_version; + uint32_t pid; + char *executable_url; + uint32_t *audit_token; + uintptr_t audit_token_len; +} LaunchResponseC; + +/** + * C-compatible process token + */ +typedef struct ProcessTokenC { + uint32_t pid; + char *executable_url; +} ProcessTokenC; + +/** + * C-compatible signal response + */ +typedef struct SignalResponseC { + uint32_t pid; + char *executable_url; + uint64_t device_timestamp; + uint32_t signal; +} SignalResponseC; + +/** + * C-compatible icon data + */ +typedef struct IconDataC { + uint8_t *data; + uintptr_t data_len; + double icon_width; + double icon_height; + double minimum_width; + double minimum_height; +} IconDataC; + +/** + * Represents a debugserver command + */ +typedef struct DebugserverCommandHandle { + char *name; + char **argv; + uintptr_t argv_count; +} DebugserverCommandHandle; + +/** + * C-compatible delegate for mobilebackup2 operations. + * + * All function pointers are required except `on_file_received` and + * `on_progress` which may be NULL. + * + * Every path argument is a null-terminated UTF-8 string. + * `context` is forwarded unchanged from the struct field. + */ +typedef struct Mobilebackup2BackupDelegateFFI { + void *context; + uint64_t (*get_free_disk_space)(const char *path, void *context); + struct IdeviceFfiError *(*open_file_read)(const char *path, + uint8_t **out_data, + uintptr_t *out_len, + void *context); + struct IdeviceFfiError *(*create_file_write)(const char *path, void *context); + struct IdeviceFfiError *(*write_chunk)(const char *path, + const uint8_t *data, + uintptr_t len, + void *context); + struct IdeviceFfiError *(*close_file)(const char *path, void *context); + struct IdeviceFfiError *(*create_dir_all)(const char *path, void *context); + struct IdeviceFfiError *(*remove)(const char *path, void *context); + struct IdeviceFfiError *(*rename)(const char *from, const char *to, void *context); + struct IdeviceFfiError *(*copy)(const char *src, const char *dst, void *context); + bool (*exists)(const char *path, void *context); + bool (*is_dir)(const char *path, void *context); + /** + * Optional progress callback. May be NULL. + */ + void (*on_progress)(uint64_t bytes_done, + uint64_t bytes_total, + double overall_progress, + void *context); +} Mobilebackup2BackupDelegateFFI; + +typedef struct SyslogLabel { + const char *subsystem; + const char *category; +} SyslogLabel; + +typedef struct OsTraceLog { + uint32_t pid; + int64_t timestamp; + uint8_t level; + const char *image_name; + const char *filename; + const char *message; + const struct SyslogLabel *label; +} OsTraceLog; + +/** + * Represents a captured device packet from pcapd + */ +typedef struct DevicePacketHandle { + uint32_t header_length; + uint8_t header_version; + uint32_t packet_length; + uint8_t interface_type; + uint16_t unit; + uint8_t io; + uint32_t protocol_family; + uint32_t frame_pre_length; + uint32_t frame_post_length; + char *interface_name; + uint32_t pid; + char *comm; + uint32_t svc; + uint32_t epid; + char *ecomm; + uint32_t seconds; + uint32_t microseconds; + uint8_t *data; + uintptr_t data_len; +} DevicePacketHandle; + +/** + * C-compatible representation of an RSD service + */ +typedef struct CRsdService { + /** + * Service name (null-terminated string) + */ + char *name; + /** + * Required entitlement (null-terminated string) + */ + char *entitlement; + /** + * Port number + */ + uint16_t port; + /** + * Whether service uses remote XPC + */ + bool uses_remote_xpc; + /** + * Number of features + */ + size_t features_count; + /** + * Array of feature strings + */ + char **features; + /** + * Service version (-1 if not present) + */ + int64_t service_version; +} CRsdService; + +/** + * Array of RSD services returned by rsd_get_services + */ +typedef struct CRsdServiceArray { + /** + * Array of services + */ + struct CRsdService *services; + /** + * Number of services in array + */ + size_t count; +} CRsdServiceArray; + +/** + * Represents a screenshot data buffer + */ +typedef struct ScreenshotData { + uint8_t *data; + uintptr_t length; +} ScreenshotData; + +/** + * Creates a new Idevice connection + * + * # Arguments + * * [`socket`] - Socket for communication with the device + * * [`label`] - Label for the connection + * * [`idevice`] - On success, will be set to point to a newly allocated Idevice handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `label` must be a valid null-terminated C string + * `idevice` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_new(struct IdeviceSocketHandle *socket, + const char *label, + struct IdeviceHandle **idevice); + +/** + * Creates an Idevice object from a socket file descriptor + * + * # Safety + * The socket FD must be valid. + * The pointers must be valid and non-null. + */ +struct IdeviceFfiError *idevice_from_fd(int32_t fd, + const char *label, + struct IdeviceHandle **idevice); + +/** + * Creates a new Idevice connection + * + * # Arguments + * * [`addr`] - The socket address to connect to + * * [`addr_len`] - Length of the socket + * * [`label`] - Label for the connection + * * [`idevice`] - On success, will be set to point to a newly allocated Idevice handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `addr` must be a valid sockaddr + * `label` must be a valid null-terminated C string + * `idevice` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_new_tcp_socket(const idevice_sockaddr *addr, + idevice_socklen_t addr_len, + const char *label, + struct IdeviceHandle **idevice); + +/** + * Gets the device type + * + * # Arguments + * * [`idevice`] - The Idevice handle + * * [`device_type`] - On success, will be set to point to a newly allocated string containing the device type + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `idevice` must be a valid, non-null pointer to an Idevice handle + * `device_type` must be a valid, non-null pointer to a location where the string pointer will be stored + */ +struct IdeviceFfiError *idevice_get_type(struct IdeviceHandle *idevice, + char **device_type); + +/** + * Performs RSD checkin + * + * # Arguments + * * [`idevice`] - The Idevice handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `idevice` must be a valid, non-null pointer to an Idevice handle + */ +struct IdeviceFfiError *idevice_rsd_checkin(struct IdeviceHandle *idevice); + +/** + * Starts a TLS session + * + * # Arguments + * * [`idevice`] - The Idevice handle + * * [`pairing_file`] - The pairing file to use for TLS + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `idevice` must be a valid, non-null pointer to an Idevice handle + * `pairing_file` must be a valid, non-null pointer to a pairing file handle + */ +struct IdeviceFfiError *idevice_start_session(struct IdeviceHandle *idevice, + const struct IdevicePairingFile *pairing_file, + bool legacy); + +/** + * Frees an Idevice handle + * + * # Arguments + * * [`idevice`] - The Idevice handle to free + * + * # Safety + * `idevice` must be a valid pointer to an Idevice handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void idevice_free(struct IdeviceHandle *idevice); + +/** + * Frees a stream handle + * + * # Safety + * Pass a valid handle allocated by this library + */ +void idevice_stream_free(struct ReadWriteOpaque *stream_handle); + +/** + * Frees a string allocated by this library + * + * # Arguments + * * [`string`] - The string to free + * + * # Safety + * `string` must be a valid pointer to a string that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void idevice_string_free(char *string); + +/** + * Frees data allocated by this library + * + * # Arguments + * * [`data`] - The data to free + * + * # Safety + * `data` must be a valid pointer to data that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void idevice_data_free(uint8_t *data, uintptr_t len); + +/** + * Frees an array of plists allocated by this library + * + * # Safety + * `data` must be a pointer to data allocated by this library, + * NOT data allocated by libplist. + */ +void idevice_plist_array_free(plist_t *plists, uintptr_t len); + +/** + * Frees a slice of pointers allocated by this library that had an underlying + * vec creation. + * + * The following functions use an underlying vec and are safe to use: + * - idevice_usbmuxd_get_devices + * + * # Safety + * Pass a valid pointer passed by the Vec creating functions + */ +void idevice_outer_slice_free(void *slice, uintptr_t len); + +/** + * Connects the adapter to a specific port + * + * # Arguments + * * [`adapter_handle`] - The adapter handle + * * [`port`] - The port to connect to + * * [`stream_handle`] - A pointer to allocate the new stream to + * + * # Returns + * Null on success, an IdeviceFfiError otherwise + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library. + * Any stream allocated must be used in the same thread as the adapter. The handles are NOT thread + * safe. + */ +struct IdeviceFfiError *adapter_connect(struct AdapterHandle *adapter_handle, + uint16_t port, + struct ReadWriteOpaque **stream_handle); + +/** + * Enables PCAP logging for the adapter + * + * # Arguments + * * [`handle`] - The adapter handle + * * [`path`] - The path to save the PCAP file (null-terminated string) + * + * # Returns + * Null on success, an IdeviceFfiError otherwise + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `path` must be a valid null-terminated string + */ +struct IdeviceFfiError *adapter_pcap(struct AdapterHandle *handle, const char *path); + +/** + * Closes the adapter stream connection + * + * # Arguments + * * [`handle`] - The adapter stream handle + * + * # Returns + * Null on success, an IdeviceFfiError otherwise + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *adapter_stream_close(struct AdapterStreamHandle *handle); + +/** + * Stops the entire adapter TCP stack + * + * # Arguments + * * [`handle`] - The adapter handle + * + * # Returns + * Null on success, an IdeviceFfiError otherwise + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *adapter_close(struct AdapterHandle *handle); + +/** + * Sends data through the adapter stream + * + * # Arguments + * * [`handle`] - The adapter stream handle + * * [`data`] - The data to send + * * [`length`] - The length of the data + * + * # Returns + * Null on success, an IdeviceFfiError otherwise + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `data` must be a valid pointer to at least `length` bytes + */ +struct IdeviceFfiError *adapter_send(struct AdapterStreamHandle *handle, + const uint8_t *data, + uintptr_t length); + +/** + * Receives data from the adapter stream + * + * # Arguments + * * [`handle`] - The adapter stream handle + * * [`data`] - Pointer to a buffer where the received data will be stored + * * [`length`] - Pointer to store the actual length of received data + * * [`max_length`] - Maximum number of bytes that can be stored in `data` + * + * # Returns + * Null on success, an IdeviceFfiError otherwise + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `data` must be a valid pointer to at least `max_length` bytes + * `length` must be a valid pointer to a usize + */ +struct IdeviceFfiError *adapter_recv(struct AdapterStreamHandle *handle, + uint8_t *data, + uintptr_t *length, + uintptr_t max_length); + +/** + * Connects to the AFC service using a TCP provider + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated AfcClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *afc_client_connect(struct IdeviceProviderHandle *provider, + struct AfcClientHandle **client); + +/** + * Creates a new AfcClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated AfcClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *afc_client_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct AfcClientHandle **client); + +/** + * Connects to the AFC2 service using a TCP provider + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated AfcClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *afc2_client_connect(struct IdeviceProviderHandle *provider, + struct AfcClientHandle **client); + +/** + * Creates a new AfcClient from an existing Idevice connection + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated AfcClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *afc_client_new(struct IdeviceHandle *socket, + struct AfcClientHandle **client); + +/** + * Frees an AfcClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void afc_client_free(struct AfcClientHandle *handle); + +/** + * Lists the contents of a directory on the device + * + * # Arguments + * * [`client`] - A valid AfcClient handle + * * [`path`] - Path to the directory to list (UTF-8 null-terminated) + * * [`entries`] - Will be set to point to an array of directory entries + * * [`count`] - Will be set to the number of entries + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + * `path` must be a valid null-terminated C string + */ +struct IdeviceFfiError *afc_list_directory(struct AfcClientHandle *client, + const char *path, + char ***entries, + size_t *count); + +/** + * Creates a new directory on the device + * + * # Arguments + * * [`client`] - A valid AfcClient handle + * * [`path`] - Path of the directory to create (UTF-8 null-terminated) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `path` must be a valid null-terminated C string + */ +struct IdeviceFfiError *afc_make_directory(struct AfcClientHandle *client, const char *path); + +/** + * Retrieves information about a file or directory + * + * # Arguments + * * [`client`] - A valid AfcClient handle + * * [`path`] - Path to the file or directory (UTF-8 null-terminated) + * * [`info`] - Will be populated with file information + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` and `path` must be valid pointers + * `info` must be a valid pointer to an AfcFileInfo struct + */ +struct IdeviceFfiError *afc_get_file_info(struct AfcClientHandle *client, + const char *path, + struct AfcFileInfo *info); + +/** + * Frees memory allocated by afc_get_file_info + * + * # Arguments + * * [`info`] - Pointer to AfcFileInfo struct to free + * + * # Safety + * `info` must be a valid pointer to an AfcFileInfo struct previously returned by afc_get_file_info + */ +void afc_file_info_free(struct AfcFileInfo *info); + +/** + * Retrieves information about the device's filesystem + * + * # Arguments + * * [`client`] - A valid AfcClient handle + * * [`info`] - Will be populated with device information + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` and `info` must be valid pointers + */ +struct IdeviceFfiError *afc_get_device_info(struct AfcClientHandle *client, + struct AfcDeviceInfo *info); + +/** + * Frees memory allocated by afc_get_device_info + * + * # Arguments + * * [`info`] - Pointer to AfcDeviceInfo struct to free + * + * # Safety + * `info` must be a valid pointer to an AfcDeviceInfo struct previously returned by afc_get_device_info + */ +void afc_device_info_free(struct AfcDeviceInfo *info); + +/** + * Removes a file or directory + * + * # Arguments + * * [`client`] - A valid AfcClient handle + * * [`path`] - Path to the file or directory to remove (UTF-8 null-terminated) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `path` must be a valid null-terminated C string + */ +struct IdeviceFfiError *afc_remove_path(struct AfcClientHandle *client, const char *path); + +/** + * Recursively removes a directory and all its contents + * + * # Arguments + * * [`client`] - A valid AfcClient handle + * * [`path`] - Path to the directory to remove (UTF-8 null-terminated) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `path` must be a valid null-terminated C string + */ +struct IdeviceFfiError *afc_remove_path_and_contents(struct AfcClientHandle *client, + const char *path); + +/** + * Opens a file on the device + * + * # Arguments + * * [`client`] - A valid AfcClient handle + * * [`path`] - Path to the file to open (UTF-8 null-terminated) + * * [`mode`] - File open mode + * * [`handle`] - Will be set to a new file handle on success + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + * `path` must be a valid null-terminated C string. + * The file handle MAY NOT be used from another thread, and is + * dependant upon the client it was created by. + */ +struct IdeviceFfiError *afc_file_open(struct AfcClientHandle *client, + const char *path, + enum AfcFopenMode mode, + struct AfcFileHandle **handle); + +/** + * Closes a file handle + * + * # Arguments + * * [`handle`] - File handle to close + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *afc_file_close(struct AfcFileHandle *handle); + +/** + * Reads data from an open file. This advances the cursor of the file. + * + * # Arguments + * * [`handle`] - File handle to read from + * * [`data`] - Will be set to point to the read data + * * [`len`] - Number of bytes to read from the file + * * [`bytes_read`] - The number of bytes read from the file + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + */ +struct IdeviceFfiError *afc_file_read(struct AfcFileHandle *handle, + uint8_t **data, + uintptr_t len, + size_t *bytes_read); + +/** + * Reads all data from an open file. + * + * # Arguments + * * [`handle`] - File handle to read from + * * [`data`] - Will be set to point to the read data + * * [`length`] - The number of bytes read from the file + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + */ +struct IdeviceFfiError *afc_file_read_entire(struct AfcFileHandle *handle, + uint8_t **data, + size_t *length); + +/** + * Moves the read/write cursor in an open file. + * + * # Arguments + * * [`handle`] - File handle whose cursor should be moved + * * [`offset`] - Distance to move the cursor, interpreted based on `whence` + * * [`whence`] - Origin used for the seek operation: + * * `0` — Seek from the start of the file (`SeekFrom::Start`) + * * `1` — Seek from the current cursor position (`SeekFrom::Current`) + * * `2` — Seek from the end of the file (`SeekFrom::End`) + * * [`new_pos`] - Output parameter; will be set to the new absolute cursor position + * + * # Returns + * An [`IdeviceFfiError`] on error, or null on success. + * + * # Safety + * All pointers must be valid and non-null. + * + * # Notes + * * If `whence` is invalid, this function returns `FfiInvalidArg`. + * * The AFC protocol may restrict seeking beyond certain bounds; such errors + * are reported through the returned [`IdeviceFfiError`]. + */ +struct IdeviceFfiError *afc_file_seek(struct AfcFileHandle *handle, + int64_t offset, + int whence, + int64_t *new_pos); + +/** + * Returns the current read/write cursor position of an open file. + * + * # Arguments + * * [`handle`] - File handle whose cursor should be queried + * * [`pos`] - Output parameter; will be set to the current absolute cursor position + * + * # Returns + * An [`IdeviceFfiError`] on error, or null on success. + * + * # Safety + * All pointers must be valid and non-null. + * + * # Notes + * This function is equivalent to performing a seek operation with + * `SeekFrom::Current(0)` internally. + */ +struct IdeviceFfiError *afc_file_tell(struct AfcFileHandle *handle, int64_t *pos); + +/** + * Writes data to an open file + * + * # Arguments + * * [`handle`] - File handle to write to + * * [`data`] - Data to write + * * [`length`] - Length of data to write + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + * `data` must point to at least `length` bytes + */ +struct IdeviceFfiError *afc_file_write(struct AfcFileHandle *handle, + const uint8_t *data, + size_t length); + +/** + * Creates a hard or symbolic link + * + * # Arguments + * * [`client`] - A valid AfcClient handle + * * [`target`] - Target path of the link (UTF-8 null-terminated) + * * [`source`] - Path where the link should be created (UTF-8 null-terminated) + * * [`link_type`] - Type of link to create + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + * `target` and `source` must be valid null-terminated C strings + */ +struct IdeviceFfiError *afc_make_link(struct AfcClientHandle *client, + const char *target, + const char *source, + enum AfcLinkType link_type); + +/** + * Renames a file or directory + * + * # Arguments + * * [`client`] - A valid AfcClient handle + * * [`source`] - Current path of the file/directory (UTF-8 null-terminated) + * * [`target`] - New path for the file/directory (UTF-8 null-terminated) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + * `source` and `target` must be valid null-terminated C strings + */ +struct IdeviceFfiError *afc_rename_path(struct AfcClientHandle *client, + const char *source, + const char *target); + +/** + * Frees memory allocated by a file read function allocated by this library + * + * # Arguments + * * [`info`] - Pointer to AfcDeviceInfo struct to free + * + * # Safety + * `info` must be a valid pointer to an AfcDeviceInfo struct previously returned by afc_get_device_info + */ +void afc_file_read_data_free(uint8_t *data, + size_t length); + +/** + * Automatically creates and connects to AMFI service, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated AmfiClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *amfi_connect(struct IdeviceProviderHandle *provider, + struct AmfiClientHandle **client); + +/** + * Creates a new AmfiClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated AmfiClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *amfi_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct AmfiClientHandle **client); + +/** + * Automatically creates and connects to AMFI service, returning a client handle + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated AmfiClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. It is consumed, and + * should not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *amfi_new(struct IdeviceHandle *socket, struct AmfiClientHandle **client); + +/** + * Shows the option in the settings UI + * + * # Arguments + * * `client` - A valid AmfiClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *amfi_reveal_developer_mode_option_in_ui(struct AmfiClientHandle *client); + +/** + * Enables developer mode on the device + * + * # Arguments + * * `client` - A valid AmfiClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *amfi_enable_developer_mode(struct AmfiClientHandle *client); + +/** + * Accepts developer mode on the device + * + * # Arguments + * * `client` - A valid AmfiClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *amfi_accept_developer_mode(struct AmfiClientHandle *client); + +/** + * Frees a handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void amfi_client_free(struct AmfiClientHandle *handle); + +/** + * Automatically creates and connects to BTPacketLogger, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated BtPacketLoggerClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *bt_packet_logger_connect(struct IdeviceProviderHandle *provider, + struct BtPacketLoggerClientHandle **client); + +/** + * Creates a new BtPacketLoggerClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated BtPacketLoggerClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *bt_packet_logger_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct BtPacketLoggerClientHandle **client); + +/** + * Creates a new BtPacketLoggerClient from an existing socket + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated BtPacketLoggerClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *bt_packet_logger_new(struct IdeviceHandle *socket, + struct BtPacketLoggerClientHandle **client); + +/** + * Reads the next BT packet from the logger + * + * # Arguments + * * `client` - A valid BtPacketLoggerClient handle + * * `packet` - On success, will be set to point to a newly allocated BtPacketHandle. + * May be set to NULL if EOF was reached. + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * The returned packet must be freed with `bt_packet_free` + */ +struct IdeviceFfiError *bt_packet_logger_next_packet(struct BtPacketLoggerClientHandle *client, + struct BtPacketHandle **packet); + +/** + * Frees a BtPacketHandle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void bt_packet_free(struct BtPacketHandle *handle); + +/** + * Frees a BtPacketLoggerClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void bt_packet_logger_client_free(struct BtPacketLoggerClientHandle *handle); + +/** + * Automatically creates and connects to Companion Proxy, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated CompanionProxy handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *companion_proxy_connect(struct IdeviceProviderHandle *provider, + struct CompanionProxyClientHandle **client); + +/** + * Creates a new CompanionProxy client via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated CompanionProxy handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *companion_proxy_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct CompanionProxyClientHandle **client); + +/** + * Creates a new CompanionProxy client from an existing socket + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated CompanionProxy handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *companion_proxy_new(struct IdeviceHandle *socket, + struct CompanionProxyClientHandle **client); + +/** + * Gets the device registry from Companion Proxy, returning paired watch UDIDs + * + * # Arguments + * * `client` - A valid CompanionProxy handle + * * `udids` - On success, will be set to point to a newly allocated array of C strings + * * `udids_len` - On success, will be set to the length of the array + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * The returned strings must be freed with `idevice_string_free` and the outer array + * with `idevice_outer_slice_free` + */ +struct IdeviceFfiError *companion_proxy_get_device_registry(struct CompanionProxyClientHandle *client, + char ***udids, + uintptr_t *udids_len); + +/** + * Starts forwarding a service port through the companion proxy + * + * # Arguments + * * `client` - A valid CompanionProxy handle + * * `port` - The remote port number on the watch + * * `local_port` - On success, will be set to the local forwarded port number + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *companion_proxy_start_forwarding_service_port(struct CompanionProxyClientHandle *client, + uint16_t port, + uint16_t *local_port); + +/** + * Stops forwarding a service port through the companion proxy + * + * # Arguments + * * `client` - A valid CompanionProxy handle + * * `port` - The remote port number to stop forwarding + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *companion_proxy_stop_forwarding_service_port(struct CompanionProxyClientHandle *client, + uint16_t port); + +/** + * Frees a CompanionProxy client handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void companion_proxy_client_free(struct CompanionProxyClientHandle *handle); + +/** + * Creates a new AppServiceClient using RSD connection + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`handle`] - Pointer to store the newly created handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` and `handshake` must be valid pointers to handles allocated by this library + * `handle` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *app_service_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct AppServiceHandle **handle); + +/** + * Creates a new AppServiceClient from a socket + * + * # Arguments + * * [`socket`] - The socket to use for communication + * * [`handle`] - Pointer to store the newly created handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library + * `handle` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *app_service_new(struct ReadWriteOpaque *socket, + struct AppServiceHandle **handle); + +/** + * Frees an AppServiceClient handle + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library or NULL + */ +void app_service_free(struct AppServiceHandle *handle); + +/** + * Lists applications on the device + * + * # Arguments + * * [`handle`] - The AppServiceClient handle + * * [`app_clips`] - Include app clips + * * [`removable_apps`] - Include removable apps + * * [`hidden_apps`] - Include hidden apps + * * [`internal_apps`] - Include internal apps + * * [`default_apps`] - Include default apps + * * [`apps`] - Pointer to store the array of apps (caller must free) + * * [`count`] - Pointer to store the number of apps + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle`, `apps`, and `count` must be valid pointers + */ +struct IdeviceFfiError *app_service_list_apps(struct AppServiceHandle *handle, + int app_clips, + int removable_apps, + int hidden_apps, + int internal_apps, + int default_apps, + struct AppListEntryC **apps, + uintptr_t *count); + +/** + * Frees an array of AppListEntryC structures + * + * # Safety + * `apps` must be a valid pointer to an array allocated by app_service_list_apps + * `count` must match the count returned by app_service_list_apps + */ +void app_service_free_app_list(struct AppListEntryC *apps, uintptr_t count); + +/** + * Launches an application + * + * # Arguments + * * [`handle`] - The AppServiceClient handle + * * [`bundle_id`] - Bundle identifier of the app to launch + * * [`argv`] - NULL-terminated array of arguments + * * [`argc`] - Number of arguments + * * [`kill_existing`] - Whether to kill existing instances + * * [`start_suspended`] - Whether to start suspended + * * [`stdio_uuid`] - The UUID received from openstdiosocket, null for none + * * [`response`] - Pointer to store the launch response (caller must free) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointer parameters must be valid + */ +struct IdeviceFfiError *app_service_launch_app(struct AppServiceHandle *handle, + const char *bundle_id, + const char *const *argv, + uintptr_t argc, + int kill_existing, + int start_suspended, + const uint8_t *stdio_uuid, + struct LaunchResponseC **response); + +/** + * Frees a LaunchResponseC structure + * + * # Safety + * `response` must be a valid pointer allocated by app_service_launch_app + */ +void app_service_free_launch_response(struct LaunchResponseC *response); + +/** + * Lists running processes + * + * # Arguments + * * [`handle`] - The AppServiceClient handle + * * [`processes`] - Pointer to store the array of processes (caller must free) + * * [`count`] - Pointer to store the number of processes + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointer parameters must be valid + */ +struct IdeviceFfiError *app_service_list_processes(struct AppServiceHandle *handle, + struct ProcessTokenC **processes, + uintptr_t *count); + +/** + * Frees an array of ProcessTokenC structures + * + * # Safety + * `processes` must be a valid pointer allocated by app_service_list_processes + * `count` must match the count returned by app_service_list_processes + */ +void app_service_free_process_list(struct ProcessTokenC *processes, uintptr_t count); + +/** + * Uninstalls an application + * + * # Arguments + * * [`handle`] - The AppServiceClient handle + * * [`bundle_id`] - Bundle identifier of the app to uninstall + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointer parameters must be valid + */ +struct IdeviceFfiError *app_service_uninstall_app(struct AppServiceHandle *handle, + const char *bundle_id); + +/** + * Sends a signal to a process + * + * # Arguments + * * [`handle`] - The AppServiceClient handle + * * [`pid`] - Process ID + * * [`signal`] - Signal number + * * [`response`] - Pointer to store the signal response (caller must free) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointer parameters must be valid + */ +struct IdeviceFfiError *app_service_send_signal(struct AppServiceHandle *handle, + uint32_t pid, + uint32_t signal, + struct SignalResponseC **response); + +/** + * Frees a SignalResponseC structure + * + * # Safety + * `response` must be a valid pointer allocated by app_service_send_signal + */ +void app_service_free_signal_response(struct SignalResponseC *response); + +/** + * Fetches an app icon + * + * # Arguments + * * [`handle`] - The AppServiceClient handle + * * [`bundle_id`] - Bundle identifier of the app + * * [`width`] - Icon width + * * [`height`] - Icon height + * * [`scale`] - Icon scale + * * [`allow_placeholder`] - Whether to allow placeholder icons + * * [`icon_data`] - Pointer to store the icon data (caller must free) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointer parameters must be valid + */ +struct IdeviceFfiError *app_service_fetch_app_icon(struct AppServiceHandle *handle, + const char *bundle_id, + float width, + float height, + float scale, + int allow_placeholder, + struct IconDataC **icon_data); + +/** + * Frees an IconDataC structure + * + * # Safety + * `icon_data` must be a valid pointer allocated by app_service_fetch_app_icon + */ +void app_service_free_icon_data(struct IconDataC *icon_data); + +/** + * Creates a new DiagnosticsServiceClient using RSD connection + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`handle`] - Pointer to store the newly created handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` and `handshake` must be valid pointers to handles allocated by this library + * `handle` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *diagnostics_service_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct DiagnosticsServiceHandle **handle); + +/** + * Creates a new DiagnostisServiceClient from a socket + * + * # Arguments + * * [`socket`] - The socket to use for communication + * * [`handle`] - Pointer to store the newly created handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library + * `handle` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *diagnostics_service_new(struct ReadWriteOpaque *socket, + struct DiagnosticsServiceHandle **handle); + +/** + * Captures a sysdiagnose from the device. + * Note that this will take a LONG time to return while the device collects enough information to + * return to the service. This function returns a stream that can be called on to get the next + * chunk of data. A typical sysdiagnose is roughly 1-2 GB. + * + * # Arguments + * * [`handle`] - The handle to the client + * * [`dry_run`] - Whether or not to do a dry run with a simple .txt file from the device + * * [`preferred_filename`] - The name the device wants to save the sysdaignose as + * * [`expected_length`] - The size in bytes of the sysdiagnose + * * [`stream_handle`] - The handle that will be set to capture bytes for + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * Pointers must be all valid. Handle must be allocated by this library. Preferred filename must + * be freed `idevice_string_free`. + */ +struct IdeviceFfiError *diagnostics_service_capture_sysdiagnose(struct DiagnosticsServiceHandle *handle, + bool dry_run, + char **preferred_filename, + uintptr_t *expected_length, + struct SysdiagnoseStreamHandle **stream_handle); + +/** + * Gets the next packet from the stream. + * Data will be set to 0 when there is no more data to get from the stream. + * + * # Arguments + * * [`handle`] - The handle to the stream + * * [`data`] - A pointer to the bytes + * * [`len`] - The length of the bytes written + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * Pass valid pointers. The handle must be allocated by this library. + */ +struct IdeviceFfiError *sysdiagnose_stream_next(struct SysdiagnoseStreamHandle *handle, + uint8_t **data, + uintptr_t *len); + +/** + * Frees a DiagnostisServiceClient handle + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library or NULL + */ +void diagnostics_service_free(struct DiagnosticsServiceHandle *handle); + +/** + * Frees a SysdiagnoseStreamHandle handle + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library or NULL + */ +void sysdiagnose_stream_free(struct SysdiagnoseStreamHandle *handle); + +/** + * Automatically creates and connects to Core Device Proxy, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated CoreDeviceProxy handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *core_device_proxy_connect(struct IdeviceProviderHandle *provider, + struct CoreDeviceProxyHandle **client); + +/** + * Automatically creates and connects to Core Device Proxy, returning a client handle + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated CoreDeviceProxy handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. It is consumed and + * may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *core_device_proxy_new(struct IdeviceHandle *socket, + struct CoreDeviceProxyHandle **client); + +/** + * Sends data through the CoreDeviceProxy tunnel + * + * # Arguments + * * [`handle`] - The CoreDeviceProxy handle + * * [`data`] - The data to send + * * [`length`] - The length of the data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `data` must be a valid pointer to at least `length` bytes + */ +struct IdeviceFfiError *core_device_proxy_send(struct CoreDeviceProxyHandle *handle, + const uint8_t *data, + uintptr_t length); + +/** + * Receives data from the CoreDeviceProxy tunnel + * + * # Arguments + * * [`handle`] - The CoreDeviceProxy handle + * * [`data`] - Pointer to a buffer where the received data will be stored + * * [`length`] - Pointer to store the actual length of received data + * * [`max_length`] - Maximum number of bytes that can be stored in `data` + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `data` must be a valid pointer to at least `max_length` bytes + * `length` must be a valid pointer to a usize + */ +struct IdeviceFfiError *core_device_proxy_recv(struct CoreDeviceProxyHandle *handle, + uint8_t *data, + uintptr_t *length, + uintptr_t max_length); + +/** + * Gets the client parameters from the handshake + * + * # Arguments + * * [`handle`] - The CoreDeviceProxy handle + * * [`mtu`] - Pointer to store the MTU value + * * [`address`] - Pointer to store the IP address string + * * [`netmask`] - Pointer to store the netmask string + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `mtu` must be a valid pointer to a u16 + * `address` and `netmask` must be valid pointers to buffers of at least 16 bytes + */ +struct IdeviceFfiError *core_device_proxy_get_client_parameters(struct CoreDeviceProxyHandle *handle, + uint16_t *mtu, + char **address, + char **netmask); + +/** + * Gets the server address from the handshake + * + * # Arguments + * * [`handle`] - The CoreDeviceProxy handle + * * [`address`] - Pointer to store the server address string + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `address` must be a valid pointer to a buffer of at least 16 bytes + */ +struct IdeviceFfiError *core_device_proxy_get_server_address(struct CoreDeviceProxyHandle *handle, + char **address); + +/** + * Gets the server RSD port from the handshake + * + * # Arguments + * * [`handle`] - The CoreDeviceProxy handle + * * [`port`] - Pointer to store the port number + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `port` must be a valid pointer to a u16 + */ +struct IdeviceFfiError *core_device_proxy_get_server_rsd_port(struct CoreDeviceProxyHandle *handle, + uint16_t *port); + +/** + * Creates a software TCP tunnel adapter + * + * # Arguments + * * [`handle`] - The CoreDeviceProxy handle + * * [`adapter`] - Pointer to store the newly created adapter handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library, and never used again + * `adapter` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *core_device_proxy_create_tcp_adapter(struct CoreDeviceProxyHandle *handle, + struct AdapterHandle **adapter); + +/** + * Frees a handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void core_device_proxy_free(struct CoreDeviceProxyHandle *handle); + +/** + * Frees a handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void adapter_free(struct AdapterHandle *handle); + +/** + * Automatically creates and connects to the crash report copy mobile service, + * returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *crash_report_client_connect(struct IdeviceProviderHandle *provider, + struct CrashReportCopyMobileHandle **client); + +/** + * Creates a new CrashReportCopyMobileClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *crash_report_client_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct CrashReportCopyMobileHandle **client); + +/** + * Creates a new CrashReportCopyMobile client from an existing Idevice connection + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *crash_report_client_new(struct IdeviceHandle *socket, + struct CrashReportCopyMobileHandle **client); + +/** + * Lists crash report files in the specified directory + * + * # Arguments + * * [`client`] - A valid CrashReportCopyMobile handle + * * [`dir_path`] - Optional directory path (NULL for root "/") + * * [`entries`] - Will be set to point to an array of C strings + * * [`count`] - Will be set to the number of entries + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + * `dir_path` may be NULL (defaults to root) + * Caller must free the returned array with `afc_free_directory_entries` + */ +struct IdeviceFfiError *crash_report_client_ls(struct CrashReportCopyMobileHandle *client, + const char *dir_path, + char ***entries, + size_t *count); + +/** + * Downloads a crash report file from the device + * + * # Arguments + * * [`client`] - A valid CrashReportCopyMobile handle + * * [`log_name`] - Name of the log file to download (C string) + * * [`data`] - Will be set to point to the file contents + * * [`length`] - Will be set to the size of the data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + * `log_name` must be a valid C string + * Caller must free the returned data with `idevice_data_free` + */ +struct IdeviceFfiError *crash_report_client_pull(struct CrashReportCopyMobileHandle *client, + const char *log_name, + uint8_t **data, + size_t *length); + +/** + * Removes a crash report file from the device + * + * # Arguments + * * [`client`] - A valid CrashReportCopyMobile handle + * * [`log_name`] - Name of the log file to remove (C string) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `log_name` must be a valid C string + */ +struct IdeviceFfiError *crash_report_client_remove(struct CrashReportCopyMobileHandle *client, + const char *log_name); + +/** + * Converts this client to an AFC client for advanced file operations + * + * # Arguments + * * [`client`] - A valid CrashReportCopyMobile handle (will be consumed) + * * [`afc_client`] - On success, will be set to an AFC client handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer (will be freed after this call) + * `afc_client` must be a valid, non-null pointer where the new AFC client will be stored + */ +struct IdeviceFfiError *crash_report_client_to_afc(struct CrashReportCopyMobileHandle *client, + struct AfcClientHandle **afc_client); + +/** + * Triggers a flush of crash logs from system storage + * + * This connects to the crashreportmover service to move crash logs + * into the AFC-accessible directory. Should be called before listing logs. + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *crash_report_flush(struct IdeviceProviderHandle *provider); + +/** + * Frees a CrashReportCopyMobile client handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void crash_report_client_free(struct CrashReportCopyMobileHandle *handle); + +/** + * Creates a new DebugserverCommand + * + * # Safety + * Caller must free with debugserver_command_free + */ +struct DebugserverCommandHandle *debugserver_command_new(const char *name, + const char *const *argv, + uintptr_t argv_count); + +/** + * Frees a DebugserverCommand + * + * # Safety + * `command` must be a valid pointer or NULL + */ +void debugserver_command_free(struct DebugserverCommandHandle *command); + +/** + * Creates a new DebugProxyClient + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *debug_proxy_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct DebugProxyHandle **handle); + +/** + * Creates a new DebugProxyClient + * + * # Arguments + * * [`socket`] - The socket to use for communication. Any object that supports ReadWrite. + * * [`handle`] - Pointer to store the newly created DebugProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library + * `handle` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *debug_proxy_new(struct ReadWriteOpaque *socket, + struct DebugProxyHandle **handle); + +/** + * Frees a DebugProxyClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library or NULL + */ +void debug_proxy_free(struct DebugProxyHandle *handle); + +/** + * Sends a command to the debug proxy + * + * # Arguments + * * [`handle`] - The DebugProxyClient handle + * * [`command`] - The command to send + * * [`response`] - Pointer to store the response (caller must free) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` and `command` must be valid pointers + * `response` must be a valid pointer to a location where the string will be stored + */ +struct IdeviceFfiError *debug_proxy_send_command(struct DebugProxyHandle *handle, + struct DebugserverCommandHandle *command, + char **response); + +/** + * Reads a response from the debug proxy + * + * # Arguments + * * [`handle`] - The DebugProxyClient handle + * * [`response`] - Pointer to store the response (caller must free) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer + * `response` must be a valid pointer to a location where the string will be stored + */ +struct IdeviceFfiError *debug_proxy_read_response(struct DebugProxyHandle *handle, char **response); + +/** + * Sends raw data to the debug proxy + * + * # Arguments + * * [`handle`] - The DebugProxyClient handle + * * [`data`] - The data to send + * * [`len`] - Length of the data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer + * `data` must be a valid pointer to `len` bytes + */ +struct IdeviceFfiError *debug_proxy_send_raw(struct DebugProxyHandle *handle, + const uint8_t *data, + uintptr_t len); + +/** + * Reads data from the debug proxy + * + * # Arguments + * * [`handle`] - The DebugProxyClient handle + * * [`len`] - Maximum number of bytes to read + * * [`response`] - Pointer to store the response (caller must free) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer + * `response` must be a valid pointer to a location where the string will be stored + */ +struct IdeviceFfiError *debug_proxy_read(struct DebugProxyHandle *handle, + uintptr_t len, + char **response); + +/** + * Sets the argv for the debug proxy + * + * # Arguments + * * [`handle`] - The DebugProxyClient handle + * * [`argv`] - NULL-terminated array of arguments + * * [`argv_count`] - Number of arguments + * * [`response`] - Pointer to store the response (caller must free) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer + * `argv` must be a valid pointer to `argv_count` C strings or NULL + * `response` must be a valid pointer to a location where the string will be stored + */ +struct IdeviceFfiError *debug_proxy_set_argv(struct DebugProxyHandle *handle, + const char *const *argv, + uintptr_t argv_count, + char **response); + +/** + * Sends an ACK to the debug proxy + * + * # Arguments + * * [`handle`] - The DebugProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer + */ +struct IdeviceFfiError *debug_proxy_send_ack(struct DebugProxyHandle *handle); + +/** + * Sends a NACK to the debug proxy + * + * # Arguments + * * [`handle`] - The DebugProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer + */ +struct IdeviceFfiError *debug_proxy_send_nack(struct DebugProxyHandle *handle); + +/** + * Sets the ACK mode for the debug proxy + * + * # Arguments + * * [`handle`] - The DebugProxyClient handle + * * [`enabled`] - Whether ACK mode should be enabled + * + * # Safety + * `handle` must be a valid pointer + */ +void debug_proxy_set_ack_mode(struct DebugProxyHandle *handle, int enabled); + +/** + * Automatically creates and connects to Diagnostics Relay, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated DiagnosticsRelayClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *diagnostics_relay_client_connect(struct IdeviceProviderHandle *provider, + struct DiagnosticsRelayClientHandle **client); + +/** + * Creates a new DiagnosticsRelayClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated DiagnosticsRelayClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *diagnostics_relay_client_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct DiagnosticsRelayClientHandle **client); + +/** + * Automatically creates and connects to Diagnostics Relay, returning a client handle + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated DiagnosticsRelayClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *diagnostics_relay_client_new(struct IdeviceHandle *socket, + struct DiagnosticsRelayClientHandle **client); + +/** + * Queries the device IO registry + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * * `current_plane` - A string to search by or null + * * `entry_name` - A string to search by or null + * * `entry_class` - A string to search by or null + * * `res` - Will be set to a pointer of a plist dictionary node on search success + * + * # Returns + * An IdeviceFfiError on error, null on success. Note that res can be null on success + * if the search resulted in no values. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_ioregistry(struct DiagnosticsRelayClientHandle *client, + const char *current_plane, + const char *entry_name, + const char *entry_class, + plist_t *res); + +/** + * Requests MobileGestalt information from the device + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * * `keys` - Optional list of specific keys to request. If None, requests all available keys + * * `res` - Will be set to a pointer of a plist dictionary node on search success + * + * # Returns + * An IdeviceFfiError on error, null on success. Note that res can be null on success + * if the search resulted in no values. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_mobilegestalt(struct DiagnosticsRelayClientHandle *client, + const char *const *keys, + uintptr_t keys_len, + plist_t *res); + +/** + * Requests gas gauge information from the device + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * * `res` - Will be set to a pointer of a plist dictionary node on search success + * + * # Returns + * An IdeviceFfiError on error, null on success. Note that res can be null on success + * if the search resulted in no values. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_gasguage(struct DiagnosticsRelayClientHandle *client, + plist_t *res); + +/** + * Requests nand information from the device + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * * `res` - Will be set to a pointer of a plist dictionary node on search success + * + * # Returns + * An IdeviceFfiError on error, null on success. Note that res can be null on success + * if the search resulted in no values. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_nand(struct DiagnosticsRelayClientHandle *client, + plist_t *res); + +/** + * Requests all available information from the device + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * * `res` - Will be set to a pointer of a plist dictionary node on search success + * + * # Returns + * An IdeviceFfiError on error, null on success. Note that res can be null on success + * if the search resulted in no values. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_all(struct DiagnosticsRelayClientHandle *client, + plist_t *res); + +/** + * Restarts the device + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_restart(struct DiagnosticsRelayClientHandle *client); + +/** + * Shuts down the device + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_shutdown(struct DiagnosticsRelayClientHandle *client); + +/** + * Puts the device to sleep + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_sleep(struct DiagnosticsRelayClientHandle *client); + +/** + * Requests WiFi diagnostics from the device + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * * `res` - Will be set to a pointer of a plist dictionary node on search success + * + * # Returns + * An IdeviceFfiError on error, null on success. Note that res can be null on success + * if the search resulted in no values. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_wifi(struct DiagnosticsRelayClientHandle *client, + plist_t *res); + +/** + * Puts the device to sleep + * + * # Arguments + * * `client` - A valid DiagnosticsRelayClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *diagnostics_relay_client_goodbye(struct DiagnosticsRelayClientHandle *client); + +/** + * Frees a handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void diagnostics_relay_client_free(struct DiagnosticsRelayClientHandle *handle); + +/** + * Creates a new ProcessControlClient from a RemoteServerClient + * + * # Arguments + * * [`server`] - The RemoteServerClient to use + * * [`handle`] - Pointer to store the newly created ProcessControlClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `server` must be a valid pointer to a handle allocated by this library + * `handle` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *location_simulation_new(struct RemoteServerHandle *server, + struct LocationSimulationHandle **handle); + +/** + * Frees a ProcessControlClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library or NULL + */ +void location_simulation_free(struct LocationSimulationHandle *handle); + +/** + * Clears the location set + * + * # Arguments + * * [`handle`] - The LocationSimulation handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid or NULL where appropriate + */ +struct IdeviceFfiError *location_simulation_clear(struct LocationSimulationHandle *handle); + +/** + * Sets the location + * + * # Arguments + * * [`handle`] - The LocationSimulation handle + * * [`latitude`] - The latitude to set + * * [`longitude`] - The longitude to set + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid or NULL where appropriate + */ +struct IdeviceFfiError *location_simulation_set(struct LocationSimulationHandle *handle, + double latitude, + double longitude); + +/** + * Creates a new ProcessControlClient from a RemoteServerClient + * + * # Arguments + * * [`server`] - The RemoteServerClient to use + * * [`handle`] - Pointer to store the newly created ProcessControlClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `server` must be a valid pointer to a handle allocated by this library + * `handle` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *process_control_new(struct RemoteServerHandle *server, + struct ProcessControlHandle **handle); + +/** + * Frees a ProcessControlClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library or NULL + */ +void process_control_free(struct ProcessControlHandle *handle); + +/** + * Launches an application on the device + * + * # Arguments + * * [`handle`] - The ProcessControlClient handle + * * [`bundle_id`] - The bundle identifier of the app to launch + * * [`env_vars`] - NULL-terminated array of environment variables (format "KEY=VALUE") + * * [`arguments`] - NULL-terminated array of arguments + * * [`start_suspended`] - Whether to start the app suspended + * * [`kill_existing`] - Whether to kill existing instances of the app + * * [`pid`] - Pointer to store the process ID of the launched app + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid or NULL where appropriate + */ +struct IdeviceFfiError *process_control_launch_app(struct ProcessControlHandle *handle, + const char *bundle_id, + const char *const *env_vars, + uintptr_t env_vars_count, + const char *const *arguments, + uintptr_t arguments_count, + bool start_suspended, + bool kill_existing, + uint64_t *pid); + +/** + * Kills a running process + * + * # Arguments + * * [`handle`] - The ProcessControlClient handle + * * [`pid`] - The process ID to kill + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *process_control_kill_app(struct ProcessControlHandle *handle, uint64_t pid); + +/** + * Disables memory limits for a process + * + * # Arguments + * * [`handle`] - The ProcessControlClient handle + * * [`pid`] - The process ID to modify + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *process_control_disable_memory_limit(struct ProcessControlHandle *handle, + uint64_t pid); + +/** + * Creates a new RemoteServerClient from a ReadWrite connection + * + * # Arguments + * * [`socket`] - The connection to use for communication, an object that implements ReadWrite + * * [`handle`] - Pointer to store the newly created RemoteServerClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. It is consumed and may + * not be used again. + * `handle` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *remote_server_new(struct ReadWriteOpaque *socket, + struct RemoteServerHandle **handle); + +/** + * Creates a new RemoteServerClient from a handshake and adapter + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *remote_server_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct RemoteServerHandle **handle); + +/** + * Frees a RemoteServerClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library or NULL + */ +void remote_server_free(struct RemoteServerHandle *handle); + +/** + * Creates a new [`ScreenshotClient`] associated with a given [`RemoteServerHandle`]. + * + * # Arguments + * * `server` - A pointer to a valid [`RemoteServerHandle`], previously created by this library. + * * `handle` - A pointer to a location where the newly created [`ScreenshotClientHandle`] will be stored. + * + * # Returns + * * `null_mut()` on success. + * * A pointer to an [`IdeviceFfiError`] on failure. + * + * # Safety + * - `server` must be a non-null pointer to a valid remote server handle allocated by this library. + * - `handle` must be a non-null pointer to a writable memory location where the handle will be stored. + * - The returned handle must later be freed using [`screenshot_client_free`]. + */ +struct IdeviceFfiError *screenshot_client_new(struct RemoteServerHandle *server, + struct ScreenshotClientHandle **handle); + +/** + * Frees a [`ScreenshotClientHandle`]. + * + * This releases all memory associated with the handle. + * After calling this function, the handle pointer must not be used again. + * + * # Arguments + * * `handle` - Pointer to a [`ScreenshotClientHandle`] previously returned by [`screenshot_client_new`]. + * + * # Safety + * - `handle` must either be `NULL` or a valid pointer created by this library. + * - Double-freeing or using the handle after freeing causes undefined behavior. + */ +void screenshot_client_free(struct ScreenshotClientHandle *handle); + +/** + * Captures a screenshot from the connected device. + * + * On success, this function writes a pointer to the PNG-encoded screenshot data and its length + * into the provided output arguments. The caller is responsible for freeing this data using + * `idevice_data_free`. + * + * # Arguments + * * `handle` - A pointer to a valid [`ScreenshotClientHandle`]. + * * `data` - Output pointer where the screenshot buffer pointer will be written. + * * `len` - Output pointer where the buffer length (in bytes) will be written. + * + * # Returns + * * `null_mut()` on success. + * * A pointer to an [`IdeviceFfiError`] on failure. + * + * # Safety + * - `handle` must be a valid pointer to a [`ScreenshotClientHandle`]. + * - `data` and `len` must be valid writable pointers. + * - The data returned through `*data` must be freed by the caller with `idevice_data_free`. + */ +struct IdeviceFfiError *screenshot_client_take_screenshot(struct ScreenshotClientHandle *handle, + uint8_t **data, + uintptr_t *len); + +/** + * Frees the IdeviceFfiError + * + * # Safety + * `err` must be a struct allocated by this library + */ +void idevice_error_free(struct IdeviceFfiError *err); + +/** + * Automatically creates and connects to Installation Proxy, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated InstallationProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *heartbeat_connect(struct IdeviceProviderHandle *provider, + struct HeartbeatClientHandle **client); + +/** + * Creates a new HeartbeatClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated HeartbeatClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *heartbeat_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct HeartbeatClientHandle **client); + +/** + * Automatically creates and connects to Installation Proxy, returning a client handle + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated InstallationProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *heartbeat_new(struct IdeviceHandle *socket, + struct HeartbeatClientHandle **client); + +/** + * Sends a polo to the device + * + * # Arguments + * * `client` - A valid HeartbeatClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *heartbeat_send_polo(struct HeartbeatClientHandle *client); + +/** + * Sends a polo to the device + * + * # Arguments + * * `client` - A valid HeartbeatClient handle + * * `interval` - The time to wait for a marco + * * `new_interval` - A pointer to set the requested marco + * + * # Returns + * An IdeviceFfiError on error, null on success. + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *heartbeat_get_marco(struct HeartbeatClientHandle *client, + uint64_t interval, + uint64_t *new_interval); + +/** + * Frees a handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void heartbeat_client_free(struct HeartbeatClientHandle *handle); + +/** + * Connects to the House Arrest service using a TCP provider + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated HouseArrestClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *house_arrest_client_connect(struct IdeviceProviderHandle *provider, + struct HouseArrestClientHandle **client); + +/** + * Creates a new HouseArrestClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated HouseArrestClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *house_arrest_client_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct HouseArrestClientHandle **client); + +/** + * Creates a new HouseArrestClient from an existing Idevice connection + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated HouseArrestClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *house_arrest_client_new(struct IdeviceHandle *socket, + struct HouseArrestClientHandle **client); + +/** + * Vends a container for an app + * + * # Arguments + * * [`client`] - The House Arrest client + * * [`bundle_id`] - The bundle ID to vend for + * * [`afc_client`] - The new AFC client for the underlying connection + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a allocated by this library + * `bundle_id` must be a NULL-terminated string + * `afc_client` must be a valid, non-null pointer where the new AFC client will be stored + */ +struct IdeviceFfiError *house_arrest_vend_container(struct HouseArrestClientHandle *client, + const char *bundle_id, + struct AfcClientHandle **afc_client); + +/** + * Vends documents for an app + * + * # Arguments + * * [`client`] - The House Arrest client + * * [`bundle_id`] - The bundle ID to vend for + * * [`afc_client`] - The new AFC client for the underlying connection + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a allocated by this library + * `bundle_id` must be a NULL-terminated string + * `afc_client` must be a valid, non-null pointer where the new AFC client will be stored + */ +struct IdeviceFfiError *house_arrest_vend_documents(struct HouseArrestClientHandle *client, + const char *bundle_id, + struct AfcClientHandle **afc_client); + +/** + * Frees an HouseArrestClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void house_arrest_client_free(struct HouseArrestClientHandle *handle); + +/** + * Automatically creates and connects to Installation Proxy, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated InstallationProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *installation_proxy_connect(struct IdeviceProviderHandle *provider, + struct InstallationProxyClientHandle **client); + +/** + * Creates a new InstallationProxyClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated InstallationProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *installation_proxy_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct InstallationProxyClientHandle **client); + +/** + * Automatically creates and connects to Installation Proxy, returning a client handle + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated InstallationProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *installation_proxy_new(struct IdeviceHandle *socket, + struct InstallationProxyClientHandle **client); + +/** + * Gets installed apps on the device + * + * # Arguments + * * [`client`] - A valid InstallationProxyClient handle + * * [`application_type`] - The application type to filter by (optional, NULL for "Any") + * * [`bundle_identifiers`] - The identifiers to filter by (optional, NULL for all apps) + * * [`out_result`] - On success, will be set to point to a newly allocated array of PlistRef + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `out_result` must be a valid, non-null pointer to a location where the result will be stored + */ +struct IdeviceFfiError *installation_proxy_get_apps(struct InstallationProxyClientHandle *client, + const char *application_type, + const char *const *bundle_identifiers, + size_t bundle_identifiers_len, + void **out_result, + size_t *out_result_len); + +/** + * Frees a handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void installation_proxy_client_free(struct InstallationProxyClientHandle *handle); + +/** + * Installs an application package on the device + * + * # Arguments + * * [`client`] - A valid InstallationProxyClient handle + * * [`package_path`] - Path to the .ipa package in the AFC jail + * * [`options`] - Optional installation options as a plist dictionary (can be NULL) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `package_path` must be a valid C string + * `options` must be a valid plist dictionary or NULL + */ +struct IdeviceFfiError *installation_proxy_install(struct InstallationProxyClientHandle *client, + const char *package_path, + plist_t options); + +/** + * Installs an application package on the device + * + * # Arguments + * * [`client`] - A valid InstallationProxyClient handle + * * [`package_path`] - Path to the .ipa package in the AFC jail + * * [`options`] - Optional installation options as a plist dictionary (can be NULL) + * * [`callback`] - Progress callback function + * * [`context`] - User context to pass to callback + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `package_path` must be a valid C string + * `options` must be a valid plist dictionary or NULL + */ +struct IdeviceFfiError *installation_proxy_install_with_callback(struct InstallationProxyClientHandle *client, + const char *package_path, + plist_t options, + void (*callback)(uint64_t progress, + void *context), + void *context); + +/** + * Upgrades an existing application on the device + * + * # Arguments + * * [`client`] - A valid InstallationProxyClient handle + * * [`package_path`] - Path to the .ipa package in the AFC jail + * * [`options`] - Optional upgrade options as a plist dictionary (can be NULL) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `package_path` must be a valid C string + * `options` must be a valid plist dictionary or NULL + */ +struct IdeviceFfiError *installation_proxy_upgrade(struct InstallationProxyClientHandle *client, + const char *package_path, + plist_t options); + +/** + * Upgrades an existing application on the device + * + * # Arguments + * * [`client`] - A valid InstallationProxyClient handle + * * [`package_path`] - Path to the .ipa package in the AFC jail + * * [`options`] - Optional upgrade options as a plist dictionary (can be NULL) + * * [`callback`] - Progress callback function + * * [`context`] - User context to pass to callback + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `package_path` must be a valid C string + * `options` must be a valid plist dictionary or NULL + */ +struct IdeviceFfiError *installation_proxy_upgrade_with_callback(struct InstallationProxyClientHandle *client, + const char *package_path, + plist_t options, + void (*callback)(uint64_t progress, + void *context), + void *context); + +/** + * Uninstalls an application from the device + * + * # Arguments + * * [`client`] - A valid InstallationProxyClient handle + * * [`bundle_id`] - Bundle identifier of the application to uninstall + * * [`options`] - Optional uninstall options as a plist dictionary (can be NULL) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `bundle_id` must be a valid C string + * `options` must be a valid plist dictionary or NULL + */ +struct IdeviceFfiError *installation_proxy_uninstall(struct InstallationProxyClientHandle *client, + const char *bundle_id, + plist_t options); + +/** + * Uninstalls an application from the device + * + * # Arguments + * * [`client`] - A valid InstallationProxyClient handle + * * [`bundle_id`] - Bundle identifier of the application to uninstall + * * [`options`] - Optional uninstall options as a plist dictionary (can be NULL) + * * [`callback`] - Progress callback function + * * [`context`] - User context to pass to callback + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `bundle_id` must be a valid C string + * `options` must be a valid plist dictionary or NULL + */ +struct IdeviceFfiError *installation_proxy_uninstall_with_callback(struct InstallationProxyClientHandle *client, + const char *bundle_id, + plist_t options, + void (*callback)(uint64_t progress, + void *context), + void *context); + +/** + * Checks if the device capabilities match the required capabilities + * + * # Arguments + * * [`client`] - A valid InstallationProxyClient handle + * * [`capabilities`] - Array of plist values representing required capabilities + * * [`capabilities_len`] - Length of the capabilities array + * * [`options`] - Optional check options as a plist dictionary (can be NULL) + * * [`out_result`] - Will be set to true if all capabilities are supported, false otherwise + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `capabilities` must be a valid array of plist values or NULL + * `options` must be a valid plist dictionary or NULL + * `out_result` must be a valid pointer to a bool + */ +struct IdeviceFfiError *installation_proxy_check_capabilities_match(struct InstallationProxyClientHandle *client, + const plist_t *capabilities, + size_t capabilities_len, + plist_t options, + bool *out_result); + +/** + * Browses installed applications on the device + * + * # Arguments + * * [`client`] - A valid InstallationProxyClient handle + * * [`options`] - Optional browse options as a plist dictionary (can be NULL) + * * [`out_result`] - On success, will be set to point to a newly allocated array of PlistRef + * * [`out_result_len`] - Will be set to the length of the result array + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `options` must be a valid plist dictionary or NULL + * `out_result` must be a valid, non-null pointer to a location where the result will be stored + * `out_result_len` must be a valid, non-null pointer to a location where the length will be stored + */ +struct IdeviceFfiError *installation_proxy_browse(struct InstallationProxyClientHandle *client, + plist_t options, + plist_t **out_result, + size_t *out_result_len); + +/** + * Creates a new InstallcoordinationProxy client from a ReadWrite stream + * + * # Arguments + * * [`socket`] - A ReadWriteOpaque handle (consumed) + * * [`client`] - On success, will be set to point to a newly allocated handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *installcoordination_proxy_new(struct ReadWriteOpaque *socket, + struct InstallcoordinationProxyHandle **client); + +/** + * Creates a new InstallcoordinationProxy client via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated InstallcoordinationProxy handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *installcoordination_proxy_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct InstallcoordinationProxyHandle **client); + +/** + * Uninstalls an app by bundle ID + * + * # Arguments + * * `client` - A valid InstallcoordinationProxy handle + * * `bundle_id` - The bundle identifier of the app to uninstall + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `bundle_id` must be a valid null-terminated C string + */ +struct IdeviceFfiError *installcoordination_proxy_uninstall_app(struct InstallcoordinationProxyHandle *client, + const char *bundle_id); + +/** + * Queries the install path of an app by bundle ID + * + * # Arguments + * * `client` - A valid InstallcoordinationProxy handle + * * `bundle_id` - The bundle identifier of the app to query + * * `path` - On success, will be set to a newly allocated C string with the install path + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `bundle_id` must be a valid null-terminated C string + * The returned string must be freed with `idevice_string_free` + */ +struct IdeviceFfiError *installcoordination_proxy_query_app_path(struct InstallcoordinationProxyHandle *client, + const char *bundle_id, + char **path); + +/** + * Frees an InstallcoordinationProxy client handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void installcoordination_proxy_client_free(struct InstallcoordinationProxyHandle *handle); + +/** + * Connects to the Location Simulation service using a provider + * This is the location_simulation api for iOS 16 and below + * You must have a developer disk image mounted to use this API + * + * # Safety + * `provider` must be valid; `client` must be a non-null pointer to store the handle. + */ +struct IdeviceFfiError *lockdown_location_simulation_connect(struct IdeviceProviderHandle *provider, + struct LocationSimulationServiceHandle **handle); + +/** + * Creates a new Location Simulation service client directly from an existing `IdeviceHandle` (socket). + * + * # Safety + * - `socket` must be a valid, unowned pointer to an `IdeviceHandle` that has been properly + * initialized and represents an open connection to the Location Simulation service. + * Ownership of the `IdeviceHandle` is transferred to this function. + * - `client` must be a non-null pointer to a location where the newly created + * `*mut LocationSimulationServiceHandle` will be stored. + * + */ +struct IdeviceFfiError *lockdown_location_simulation_new(struct IdeviceHandle *socket, + struct LocationSimulationServiceHandle **client); + +/** + * Sets the device's simulated location. + * This is the location_simulation api for iOS 16 and below. + * + * # Safety + * `handle` must be a valid pointer to a `LocationSimulationServiceHandle` returned by `lockdown_location_simulation_connect`. + * `latitude` and `longitude` must be valid, null-terminated C strings. + */ +struct IdeviceFfiError *lockdown_location_simulation_set(struct LocationSimulationServiceHandle *handle, + const char *latitude, + const char *longitude); + +/** + * Clears the device's simulated location, returning it to the actual location. + * This is the location_simulation api for iOS 16 and below. + * + * # Safety + * `handle` must be a valid pointer to a `LocationSimulationServiceHandle` returned by `lockdown_location_simulation_connect`. + */ +struct IdeviceFfiError *lockdown_location_simulation_clear(struct LocationSimulationServiceHandle *handle); + +/** + * Frees a LocationSimulationService handle + * + * # Safety + * `handle` must be a pointer returned by `lockdown_location_simulation_connect`. + */ +void lockdown_location_simulation_free(struct LocationSimulationServiceHandle *handle); + +/** + * Connects to lockdownd service using provider + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated LockdowndClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *lockdownd_connect(struct IdeviceProviderHandle *provider, + struct LockdowndClientHandle **client); + +/** + * Creates a new LockdownClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated LockdownClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *lockdownd_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct LockdowndClientHandle **client); + +/** + * Creates a new LockdowndClient from an existing Idevice connection + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle. + * * [`client`] - On success, will be set to point to a newly allocated LockdowndClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and maybe not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *lockdownd_new(struct IdeviceHandle *socket, + struct LockdowndClientHandle **client); + +/** + * Starts a session with lockdownd + * + * # Arguments + * * `client` - A valid LockdowndClient handle + * * `pairing_file` - An IdevicePairingFile alocated by this library + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `pairing_file` must be a valid plist_t containing a pairing file + */ +struct IdeviceFfiError *lockdownd_start_session(struct LockdowndClientHandle *client, + struct IdevicePairingFile *pairing_file); + +/** + * Starts a service through lockdownd + * + * # Arguments + * * `client` - A valid LockdowndClient handle + * * `identifier` - The service identifier to start (null-terminated string) + * * `port` - Pointer to store the returned port number + * * `ssl` - Pointer to store whether SSL should be enabled + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `identifier` must be a valid null-terminated string + * `port` and `ssl` must be valid pointers + */ +struct IdeviceFfiError *lockdownd_start_service(struct LockdowndClientHandle *client, + const char *identifier, + uint16_t *port, + bool *ssl); + +/** + * Pairs with the device using lockdownd + * + * # Arguments + * * `client` - A valid LockdowndClient handle + * * `host_id` - The host ID (null-terminated string) + * * `system_buid` - The system BUID (null-terminated string) + * * `pairing_file` - On success, will be set to point to a newly allocated IdevicePairingFile handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `host_id` must be a valid null-terminated string + * `system_buid` must be a valid null-terminated string + * `pairing_file` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *lockdownd_pair(struct LockdowndClientHandle *client, + const char *host_id, + const char *system_buid, + const char *host_name, + struct IdevicePairingFile **pairing_file); + +/** + * Gets a value from lockdownd + * + * # Arguments + * * `client` - A valid LockdowndClient handle + * * `key` - The value to get (null-terminated string) + * * `domain` - The value to get (null-terminated string) + * * `out_plist` - Pointer to store the returned plist value + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `value` must be a valid null-terminated string + * `out_plist` must be a valid pointer to store the plist + */ +struct IdeviceFfiError *lockdownd_get_value(struct LockdowndClientHandle *client, + const char *key, + const char *domain, + plist_t *out_plist); + +/** + * Tells the device to enter recovery mode + * + * # Arguments + * * `client` - A valid LockdowndClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *lockdownd_enter_recovery(struct LockdowndClientHandle *client); + +/** + * Sets a value in lockdownd + * + * # Arguments + * * `client` - A valid LockdowndClient handle + * * `key` - The key to set (null-terminated string) + * * `value` - The value to set as a plist + * * `domain` - The domain to set in (null-terminated string, optional) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `key` must be a valid null-terminated string + * `value` must be a valid plist + * `domain` must be a valid null-terminated string or NULL + */ +struct IdeviceFfiError *lockdownd_set_value(struct LockdowndClientHandle *client, + const char *key, + plist_t value, + const char *domain); + +/** + * Frees a LockdowndClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void lockdownd_client_free(struct LockdowndClientHandle *handle); + +/** + * Initializes the global logger + * + * # Safety + * Pass a valid file path string + */ +enum IdeviceLoggerError idevice_init_logger(enum IdeviceLogLevel console_level, + enum IdeviceLogLevel file_level, + char *file_path); + +/** + * Automatically creates and connects to Misagent, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated MisagentClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *misagent_connect(struct IdeviceProviderHandle *provider, + struct MisagentClientHandle **client); + +/** + * Creates a new MisagentClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated MisagentClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *misagent_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct MisagentClientHandle **client); + +/** + * Installs a provisioning profile on the device + * + * # Arguments + * * [`client`] - A valid MisagentClient handle + * * [`profile_data`] - The provisioning profile data to install + * * [`profile_len`] - Length of the profile data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `profile_data` must be a valid pointer to profile data of length `profile_len` + */ +struct IdeviceFfiError *misagent_install(struct MisagentClientHandle *client, + const uint8_t *profile_data, + size_t profile_len); + +/** + * Removes a provisioning profile from the device + * + * # Arguments + * * [`client`] - A valid MisagentClient handle + * * [`profile_id`] - The UUID of the profile to remove (C string) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `profile_id` must be a valid C string + */ +struct IdeviceFfiError *misagent_remove(struct MisagentClientHandle *client, + const char *profile_id); + +/** + * Retrieves all provisioning profiles from the device + * + * # Arguments + * * [`client`] - A valid MisagentClient handle + * * [`out_profiles`] - On success, will be set to point to an array of profile data + * * [`out_profiles_len`] - On success, will be set to the number of profiles + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `out_profiles` must be a valid pointer to store the resulting array + * `out_profiles_len` must be a valid pointer to store the array length + */ +struct IdeviceFfiError *misagent_copy_all(struct MisagentClientHandle *client, + uint8_t ***out_profiles, + size_t **out_profiles_len, + size_t *out_count); + +/** + * Frees profiles array returned by misagent_copy_all + * + * # Arguments + * * [`profiles`] - Array of profile data pointers + * * [`lens`] - Array of profile lengths + * * [`count`] - Number of profiles in the array + * + * # Safety + * Must only be called with values returned from misagent_copy_all + */ +void misagent_free_profiles(uint8_t **profiles, size_t *lens, size_t count); + +/** + * Frees a misagent client handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library, + * or NULL (in which case this function does nothing) + */ +void misagent_client_free(struct MisagentClientHandle *handle); + +/** + * Connects to the Image Mounter service using a provider + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated ImageMounter handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *image_mounter_connect(struct IdeviceProviderHandle *provider, + struct ImageMounterHandle **client); + +/** + * Creates a new ImageMounter via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated ImageMounter handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *image_mounter_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct ImageMounterHandle **client); + +/** + * Creates a new ImageMounter client from an existing Idevice connection + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated ImageMounter handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *image_mounter_new(struct IdeviceHandle *socket, + struct ImageMounterHandle **client); + +/** + * Frees an ImageMounter handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void image_mounter_free(struct ImageMounterHandle *handle); + +/** + * Gets a list of mounted devices + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`devices`] - Will be set to point to a slice of device plists on success + * * [`devices_len`] - Will be set to the number of devices copied + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `devices` must be a valid, non-null pointer to a location where the plist will be stored + */ +struct IdeviceFfiError *image_mounter_copy_devices(struct ImageMounterHandle *client, + plist_t **devices, + size_t *devices_len); + +/** + * Looks up an image and returns its signature + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`image_type`] - The type of image to look up + * * [`signature`] - Will be set to point to the signature data on success + * * [`signature_len`] - Will be set to the length of the signature data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `image_type` must be a valid null-terminated C string + * `signature` and `signature_len` must be valid pointers + */ +struct IdeviceFfiError *image_mounter_lookup_image(struct ImageMounterHandle *client, + const char *image_type, + uint8_t **signature, + size_t *signature_len); + +/** + * Uploads an image to the device + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`image_type`] - The type of image being uploaded + * * [`image`] - Pointer to the image data + * * [`image_len`] - Length of the image data + * * [`signature`] - Pointer to the signature data + * * [`signature_len`] - Length of the signature data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + * `image_type` must be a valid null-terminated C string + */ +struct IdeviceFfiError *image_mounter_upload_image(struct ImageMounterHandle *client, + const char *image_type, + const uint8_t *image, + size_t image_len, + const uint8_t *signature, + size_t signature_len); + +/** + * Mounts an image on the device + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`image_type`] - The type of image being mounted + * * [`signature`] - Pointer to the signature data + * * [`signature_len`] - Length of the signature data + * * [`trust_cache`] - Pointer to trust cache data (optional) + * * [`trust_cache_len`] - Length of trust cache data (0 if none) + * * [`info_plist`] - Pointer to info plist (optional) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid (except optional ones which can be null) + * `image_type` must be a valid null-terminated C string + */ +struct IdeviceFfiError *image_mounter_mount_image(struct ImageMounterHandle *client, + const char *image_type, + const uint8_t *signature, + size_t signature_len, + const uint8_t *trust_cache, + size_t trust_cache_len, + const void *info_plist); + +/** + * Unmounts an image from the device + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`mount_path`] - The path where the image is mounted + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `mount_path` must be a valid null-terminated C string + */ +struct IdeviceFfiError *image_mounter_unmount_image(struct ImageMounterHandle *client, + const char *mount_path); + +/** + * Queries the developer mode status + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`status`] - Will be set to the developer mode status (1 = enabled, 0 = disabled) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `status` must be a valid pointer + */ +struct IdeviceFfiError *image_mounter_query_developer_mode_status(struct ImageMounterHandle *client, + int *status); + +/** + * Mounts a developer image + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`image`] - Pointer to the image data + * * [`image_len`] - Length of the image data + * * [`signature`] - Pointer to the signature data + * * [`signature_len`] - Length of the signature data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + */ +struct IdeviceFfiError *image_mounter_mount_developer(struct ImageMounterHandle *client, + const uint8_t *image, + size_t image_len, + const uint8_t *signature, + size_t signature_len); + +/** + * Queries the personalization manifest from the device + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`image_type`] - The type of image to query + * * [`signature`] - Pointer to the signature data + * * [`signature_len`] - Length of the signature data + * * [`manifest`] - Will be set to point to the manifest data on success + * * [`manifest_len`] - Will be set to the length of the manifest data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid and non-null + * `image_type` must be a valid null-terminated C string + */ +struct IdeviceFfiError *image_mounter_query_personalization_manifest(struct ImageMounterHandle *client, + const char *image_type, + const uint8_t *signature, + size_t signature_len, + uint8_t **manifest, + size_t *manifest_len); + +/** + * Queries the nonce from the device + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`personalized_image_type`] - The type of image to query (optional) + * * [`nonce`] - Will be set to point to the nonce data on success + * * [`nonce_len`] - Will be set to the length of the nonce data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client`, `nonce`, and `nonce_len` must be valid pointers + * `personalized_image_type` can be NULL + */ +struct IdeviceFfiError *image_mounter_query_nonce(struct ImageMounterHandle *client, + const char *personalized_image_type, + uint8_t **nonce, + size_t *nonce_len); + +/** + * Queries personalization identifiers from the device + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`image_type`] - The type of image to query (optional) + * * [`identifiers`] - Will be set to point to the identifiers plist on success + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` and `identifiers` must be valid pointers + * `image_type` can be NULL + */ +struct IdeviceFfiError *image_mounter_query_personalization_identifiers(struct ImageMounterHandle *client, + const char *image_type, + plist_t *identifiers); + +/** + * Rolls the personalization nonce + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *image_mounter_roll_personalization_nonce(struct ImageMounterHandle *client); + +/** + * Rolls the cryptex nonce + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *image_mounter_roll_cryptex_nonce(struct ImageMounterHandle *client); + +/** + * Mounts a personalized developer image + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`provider`] - A valid provider handle + * * [`image`] - Pointer to the image data + * * [`image_len`] - Length of the image data + * * [`trust_cache`] - Pointer to the trust cache data + * * [`trust_cache_len`] - Length of the trust cache data + * * [`build_manifest`] - Pointer to the build manifest data + * * [`build_manifest_len`] - Length of the build manifest data + * * [`info_plist`] - Pointer to info plist (optional) + * * [`unique_chip_id`] - The device's unique chip ID + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid (except optional ones which can be null) + */ +struct IdeviceFfiError *image_mounter_mount_personalized(struct ImageMounterHandle *client, + struct IdeviceProviderHandle *provider, + const uint8_t *image, + size_t image_len, + const uint8_t *trust_cache, + size_t trust_cache_len, + const uint8_t *build_manifest, + size_t build_manifest_len, + const void *info_plist, + uint64_t unique_chip_id); + +/** + * Mounts a personalized developer image via RSD + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`provider`] - An adapter handle + * * [`handshake`] - An RSD handshake handle + * * [`image`] - Pointer to the image data + * * [`image_len`] - Length of the image data + * * [`trust_cache`] - Pointer to the trust cache data + * * [`trust_cache_len`] - Length of the trust cache data + * * [`build_manifest`] - Pointer to the build manifest data + * * [`build_manifest_len`] - Length of the build manifest data + * * [`info_plist`] - Pointer to info plist (optional) + * * [`unique_chip_id`] - The device's unique chip ID + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * All pointers must be valid (except optional ones which can be null) + */ +struct IdeviceFfiError *image_mounter_mount_personalized_rsd(struct ImageMounterHandle *client, + struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + const uint8_t *image, + size_t image_len, + const uint8_t *trust_cache, + size_t trust_cache_len, + const uint8_t *build_manifest, + size_t build_manifest_len, + const void *info_plist, + uint64_t unique_chip_id); + +/** + * Mounts a personalized developer image via RSD with progress callback + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`provider`] - An adapter handle + * * [`handshake`] - An RSD handshake handle + * * [`image`] - Pointer to the image data + * * [`image_len`] - Length of the image data + * * [`trust_cache`] - Pointer to the trust cache data + * * [`trust_cache_len`] - Length of the trust cache data + * * [`build_manifest`] - Pointer to the build manifest data + * * [`build_manifest_len`] - Length of the build manifest data + * * [`info_plist`] - Pointer to info plist (optional) + * * [`unique_chip_id`] - The device's unique chip ID + * * [`callback`] - Progress callback function + * * [`context`] - User context to pass to callback + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid (except optional ones which can be null) + */ +struct IdeviceFfiError *image_mounter_mount_personalized_with_callback_rsd(struct ImageMounterHandle *client, + struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + const uint8_t *image, + size_t image_len, + const uint8_t *trust_cache, + size_t trust_cache_len, + const uint8_t *build_manifest, + size_t build_manifest_len, + const void *info_plist, + uint64_t unique_chip_id, + void (*callback)(size_t progress, + size_t total, + void *context), + void *context); + +/** + * Mounts a personalized developer image with progress callback + * + * # Arguments + * * [`client`] - A valid ImageMounter handle + * * [`provider`] - A valid provider handle + * * [`image`] - Pointer to the image data + * * [`image_len`] - Length of the image data + * * [`trust_cache`] - Pointer to the trust cache data + * * [`trust_cache_len`] - Length of the trust cache data + * * [`build_manifest`] - Pointer to the build manifest data + * * [`build_manifest_len`] - Length of the build manifest data + * * [`info_plist`] - Pointer to info plist (optional) + * * [`unique_chip_id`] - The device's unique chip ID + * * [`callback`] - Progress callback function + * * [`context`] - User context to pass to callback + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * All pointers must be valid (except optional ones which can be null) + */ +struct IdeviceFfiError *image_mounter_mount_personalized_with_callback(struct ImageMounterHandle *client, + struct IdeviceProviderHandle *provider, + const uint8_t *image, + size_t image_len, + const uint8_t *trust_cache, + size_t trust_cache_len, + const uint8_t *build_manifest, + size_t build_manifest_len, + const void *info_plist, + uint64_t unique_chip_id, + void (*callback)(size_t progress, + size_t total, + void *context), + void *context); + +/** + * Creates a new MobileActivationd client handle from a provider + * + * # Arguments + * * [`provider`] - An IdeviceProvider (not consumed, must remain valid for the lifetime of the handle) + * * [`client`] - On success, will be set to point to a newly allocated handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library. + * The provider must remain valid for the lifetime of the returned handle. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *mobileactivationd_connect(struct IdeviceProviderHandle *provider, + struct MobileActivationdClientHandle **client); + +/** + * Gets the activation state of the device + * + * # Arguments + * * `client` - A valid MobileActivationd handle + * * `state` - On success, will be set to a newly allocated C string with the activation state + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * The returned string must be freed with `idevice_string_free` + */ +struct IdeviceFfiError *mobileactivationd_get_state(struct MobileActivationdClientHandle *client, + char **state); + +/** + * Checks if the device is activated + * + * # Arguments + * * `client` - A valid MobileActivationd handle + * * `activated` - On success, will be set to true if the device is activated + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *mobileactivationd_is_activated(struct MobileActivationdClientHandle *client, + bool *activated); + +/** + * Deactivates the device + * + * # Arguments + * * `client` - A valid MobileActivationd handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *mobileactivationd_deactivate(struct MobileActivationdClientHandle *client); + +/** + * Frees a MobileActivationd client handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void mobileactivationd_client_free(struct MobileActivationdClientHandle *handle); + +/** + * Connects to the mobilebackup2 service via a provider + * + * # Safety + * All pointer arguments must be valid and non-null + */ +struct IdeviceFfiError *mobilebackup2_connect(struct IdeviceProviderHandle *provider, + struct MobileBackup2ClientHandle **client); + +/** + * Creates a new MobileBackup2Client via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated MobileBackup2Client handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *mobilebackup2_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct MobileBackup2ClientHandle **client); + +/** + * Creates a mobilebackup2 client from an existing connection (consumes the socket) + * + * # Safety + * `socket` is consumed and must not be used after this call + */ +struct IdeviceFfiError *mobilebackup2_new(struct IdeviceHandle *socket, + struct MobileBackup2ClientHandle **client); + +/** + * Frees a mobilebackup2 client handle + * + * # Safety + * `handle` must be valid or NULL + */ +void mobilebackup2_client_free(struct MobileBackup2ClientHandle *handle); + +/** + * Creates a backup of the device + * + * # Arguments + * * `client` - A valid MobileBackup2Client handle + * * `backup_root` - Path to the backup root directory (null-terminated UTF-8) + * * `source_identifier` - Source UDID (null-terminated UTF-8, or NULL for current device) + * * `options` - Optional plist dictionary of backup options (NULL for defaults) + * * `delegate` - Pointer to a populated Mobilebackup2BackupDelegateFFI struct + * * `out_response` - On success, receives the device response plist (caller must free). May be NULL. + * + * # Safety + * All non-null pointers must be valid. `delegate` must remain valid for the entire call. + */ +struct IdeviceFfiError *mobilebackup2_backup(struct MobileBackup2ClientHandle *client, + const char *backup_root, + const char *source_identifier, + plist_t options, + const struct Mobilebackup2BackupDelegateFFI *delegate, + plist_t *out_response); + +/** + * Restores a backup to the device + * + * # Safety + * All non-null pointers must be valid. `delegate` must remain valid for the entire call. + */ +struct IdeviceFfiError *mobilebackup2_restore(struct MobileBackup2ClientHandle *client, + const char *backup_root, + const char *source_identifier, + plist_t options, + const struct Mobilebackup2BackupDelegateFFI *delegate, + plist_t *out_response); + +/** + * Changes the backup password on the device + * + * # Safety + * All non-null pointers must be valid. + */ +struct IdeviceFfiError *mobilebackup2_change_password(struct MobileBackup2ClientHandle *client, + const char *backup_root, + const char *old_password, + const char *new_password, + const struct Mobilebackup2BackupDelegateFFI *delegate); + +/** + * Disconnects from the mobilebackup2 service + * + * # Safety + * `client` must be a valid handle + */ +struct IdeviceFfiError *mobilebackup2_disconnect(struct MobileBackup2ClientHandle *client); + +/** + * Automatically creates and connects to Notification Proxy, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated NotificationProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *notification_proxy_connect(struct IdeviceProviderHandle *provider, + struct NotificationProxyClientHandle **client); + +/** + * Creates a new NotificationProxyClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated NotificationProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *notification_proxy_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct NotificationProxyClientHandle **client); + +/** + * Creates a new NotificationProxyClient from an existing Idevice connection + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated NotificationProxyClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *notification_proxy_new(struct IdeviceHandle *socket, + struct NotificationProxyClientHandle **client); + +/** + * Posts a notification to the device + * + * # Arguments + * * `client` - A valid NotificationProxyClient handle + * * `name` - C string containing the notification name + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `name` must be a valid null-terminated C string + */ +struct IdeviceFfiError *notification_proxy_post(struct NotificationProxyClientHandle *client, + const char *name); + +/** + * Observes a specific notification + * + * # Arguments + * * `client` - A valid NotificationProxyClient handle + * * `name` - C string containing the notification name to observe + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `name` must be a valid null-terminated C string + */ +struct IdeviceFfiError *notification_proxy_observe(struct NotificationProxyClientHandle *client, + const char *name); + +/** + * Observes multiple notifications at once + * + * # Arguments + * * `client` - A valid NotificationProxyClient handle + * * `names` - A null-terminated array of C strings containing notification names + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `names` must be a valid pointer to a null-terminated array of null-terminated C strings + */ +struct IdeviceFfiError *notification_proxy_observe_multiple(struct NotificationProxyClientHandle *client, + const char *const *names); + +/** + * Receives the next notification from the device + * + * # Arguments + * * `client` - A valid NotificationProxyClient handle + * * `name_out` - On success, will be set to a newly allocated C string containing the notification name + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `name_out` must be a valid pointer. The returned string must be freed with `notification_proxy_free_string` + */ +struct IdeviceFfiError *notification_proxy_receive(struct NotificationProxyClientHandle *client, + char **name_out); + +/** + * Receives the next notification with a timeout + * + * # Arguments + * * `client` - A valid NotificationProxyClient handle + * * `interval` - Timeout in seconds to wait for a notification + * * `name_out` - On success, will be set to a newly allocated C string containing the notification name + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `name_out` must be a valid pointer. The returned string must be freed with `notification_proxy_free_string` + */ +struct IdeviceFfiError *notification_proxy_receive_with_timeout(struct NotificationProxyClientHandle *client, + uint64_t interval, + char **name_out); + +/** + * Frees a string returned by notification_proxy_receive + * + * # Safety + * `s` must be a valid pointer returned from `notification_proxy_receive` + */ +void notification_proxy_free_string(char *s); + +/** + * Frees a handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void notification_proxy_client_free(struct NotificationProxyClientHandle *handle); + +/** + * Connects to the relay with the given provider + * + * # Arguments + * * [`provider`] - A provider created by this library + * * [`client`] - A pointer where the handle will be allocated + * + * # Returns + * 0 for success, an *mut IdeviceFfiError otherwise + * + * # Safety + * None of the arguments can be null. Provider must be allocated by this library. + */ +struct IdeviceFfiError *os_trace_relay_connect(struct IdeviceProviderHandle *provider, + struct OsTraceRelayClientHandle **client); + +/** + * Creates a new OsTraceRelayClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated OsTraceRelayClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *os_trace_relay_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct OsTraceRelayClientHandle **client); + +/** + * Frees the relay client + * + * # Arguments + * * [`handle`] - The relay client handle + * + * # Safety + * The handle must be allocated by this library + */ +void os_trace_relay_free(struct OsTraceRelayClientHandle *handle); + +/** + * Creates a handle and starts receiving logs + * + * # Arguments + * * [`client`] - The relay client handle + * * [`receiver`] - A pointer to allocate the new handle to + * * [`pid`] - An optional pointer to a PID to get logs for. May be null. + * + * # Returns + * 0 for success, an *mut IdeviceFfiError otherwise + * + * # Safety + * The handle must be allocated by this library. It is consumed, and must never be used again. + */ +struct IdeviceFfiError *os_trace_relay_start_trace(struct OsTraceRelayClientHandle *client, + struct OsTraceRelayReceiverHandle **receiver, + const uint32_t *pid); + +/** + * Frees the receiver handle + * + * # Arguments + * * [`handle`] - The relay receiver client handle + * + * # Safety + * The handle must be allocated by this library. It is consumed, and must never be used again. + */ +void os_trace_relay_receiver_free(struct OsTraceRelayReceiverHandle *handle); + +/** + * Gets the PID list from the device + * + * # Arguments + * * [`client`] - The relay receiver client handle + * * [`list`] - A pointer to allocate a list of PIDs to + * + * # Returns + * 0 for success, an *mut IdeviceFfiError otherwise + * + * # Safety + * The handle must be allocated by this library. + */ +struct IdeviceFfiError *os_trace_relay_get_pid_list(struct OsTraceRelayClientHandle *client, + struct Vec_u64 **list); + +/** + * Gets the next log from the relay + * + * # Arguments + * * [`client`] - The relay receiver client handle + * * [`log`] - A pointer to allocate the new log + * + * # Returns + * 0 for success, an *mut IdeviceFfiError otherwise + * + * # Safety + * The handle must be allocated by this library. + */ +struct IdeviceFfiError *os_trace_relay_next(struct OsTraceRelayReceiverHandle *client, + struct OsTraceLog **log); + +/** + * Frees a log received from the relay + * + * # Arguments + * * [`log`] - The log to free + * + * # Returns + * 0 for success, an *mut IdeviceFfiError otherwise + * + * # Safety + * The log must be allocated by this library. It is consumed and must not be used again. + */ +void os_trace_relay_free_log(struct OsTraceLog *log); + +/** + * Reads a pairing file from the specified path + * + * # Arguments + * * [`path`] - Path to the pairing file + * * [`pairing_file`] - On success, will be set to point to a newly allocated pairing file instance + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `path` must be a valid null-terminated C string + * `pairing_file` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_pairing_file_read(const char *path, + struct IdevicePairingFile **pairing_file); + +/** + * Parses a pairing file from a byte buffer + * + * # Arguments + * * [`data`] - Pointer to the buffer containing pairing file data + * * [`size`] - Size of the buffer in bytes + * * [`pairing_file`] - On success, will be set to point to a newly allocated pairing file instance + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `data` must be a valid pointer to a buffer of at least `size` bytes + * `pairing_file` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_pairing_file_from_bytes(const uint8_t *data, + uintptr_t size, + struct IdevicePairingFile **pairing_file); + +/** + * Serializes a pairing file to XML format + * + * # Arguments + * * [`pairing_file`] - The pairing file to serialize + * * [`data`] - On success, will be set to point to a newly allocated buffer containing the serialized data + * * [`size`] - On success, will be set to the size of the allocated buffer + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `pairing_file` must be a valid, non-null pointer to a pairing file instance + * `data` must be a valid, non-null pointer to a location where the buffer pointer will be stored + * `size` must be a valid, non-null pointer to a location where the buffer size will be stored + */ +struct IdeviceFfiError *idevice_pairing_file_serialize(const struct IdevicePairingFile *pairing_file, + uint8_t **data, + uintptr_t *size); + +/** + * Frees a pairing file instance + * + * # Arguments + * * [`pairing_file`] - The pairing file to free + * + * # Safety + * `pairing_file` must be a valid pointer to a pairing file instance that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void idevice_pairing_file_free(struct IdevicePairingFile *pairing_file); + +/** + * Automatically creates and connects to pcapd, returning a client handle. + * Note that this service only works over USB or through RSD. + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated PcapdClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *pcapd_connect(struct IdeviceProviderHandle *provider, + struct PcapdClientHandle **client); + +/** + * Creates a new PcapdClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated PcapdClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *pcapd_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct PcapdClientHandle **client); + +/** + * Creates a new PcapdClient from an existing socket + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated PcapdClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *pcapd_new(struct IdeviceHandle *socket, struct PcapdClientHandle **client); + +/** + * Reads the next packet from the pcapd service + * + * # Arguments + * * `client` - A valid PcapdClient handle + * * `packet` - On success, will be set to point to a newly allocated DevicePacketHandle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * The returned packet must be freed with `pcapd_device_packet_free` + */ +struct IdeviceFfiError *pcapd_next_packet(struct PcapdClientHandle *client, + struct DevicePacketHandle **packet); + +/** + * Frees a DevicePacketHandle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void pcapd_device_packet_free(struct DevicePacketHandle *handle); + +/** + * Frees a PcapdClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void pcapd_client_free(struct PcapdClientHandle *handle); + +/** + * Automatically creates and connects to Preboard Service, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated PreboardServiceClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *preboard_service_connect(struct IdeviceProviderHandle *provider, + struct PreboardServiceClientHandle **client); + +/** + * Creates a new PreboardServiceClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated PreboardServiceClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *preboard_service_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct PreboardServiceClientHandle **client); + +/** + * Creates a new PreboardServiceClient from an existing socket + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated PreboardServiceClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *preboard_service_new(struct IdeviceHandle *socket, + struct PreboardServiceClientHandle **client); + +/** + * Creates a stashbag on the device + * + * # Arguments + * * `client` - A valid PreboardServiceClient handle + * * `manifest` - Pointer to the manifest data + * * `manifest_len` - Length of the manifest data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `manifest` must be a valid pointer to `manifest_len` bytes of data + */ +struct IdeviceFfiError *preboard_service_create_stashbag(struct PreboardServiceClientHandle *client, + const uint8_t *manifest, + uintptr_t manifest_len); + +/** + * Commits a stashbag on the device + * + * # Arguments + * * `client` - A valid PreboardServiceClient handle + * * `manifest` - Pointer to the manifest data + * * `manifest_len` - Length of the manifest data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `manifest` must be a valid pointer to `manifest_len` bytes of data + */ +struct IdeviceFfiError *preboard_service_commit_stashbag(struct PreboardServiceClientHandle *client, + const uint8_t *manifest, + uintptr_t manifest_len); + +/** + * Frees a PreboardServiceClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void preboard_service_client_free(struct PreboardServiceClientHandle *handle); + +/** + * Creates a TCP provider for idevice + * + * # Arguments + * * [`ip`] - The sockaddr IP to connect to + * * [`pairing_file`] - The pairing file handle to use + * * [`label`] - The label to use with the connection + * * [`provider`] - A pointer to a newly allocated provider + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `ip` must be a valid sockaddr + * `pairing_file` is consumed must never be used again + * `label` must be a valid Cstr + * `provider` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_tcp_provider_new(const idevice_sockaddr *ip, + struct IdevicePairingFile *pairing_file, + const char *label, + struct IdeviceProviderHandle **provider); + +/** + * Frees an IdeviceProvider handle + * + * # Arguments + * * [`provider`] - The provider handle to free + * + * # Safety + * `provider` must be a valid pointer to a IdeviceProvider handle that was allocated this library + * or NULL (in which case this function does nothing) + */ +void idevice_provider_free(struct IdeviceProviderHandle *provider); + +/** + * Creates a usbmuxd provider for idevice + * + * # Arguments + * * [`addr`] - The UsbmuxdAddr handle to connect to + * * [`tag`] - The tag returned in usbmuxd responses + * * [`udid`] - The UDID of the device to connect to + * * [`device_id`] - The muxer ID of the device to connect to + * * [`label`] - The label to use with the connection + * * [`provider`] - A pointer to a newly allocated provider + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `addr` must be a valid pointer to UsbmuxdAddrHandle created by this library, and never used again + * `udid` must be a valid CStr + * `label` must be a valid Cstr + * `provider` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *usbmuxd_provider_new(struct UsbmuxdAddrHandle *addr, + uint32_t tag, + const char *udid, + uint32_t device_id, + const char *label, + struct IdeviceProviderHandle **provider); + +/** + * Gets the pairing file for the device + * + * # Arguments + * * [`provider`] - A pointer to the provider + * * [`pairing_file`] - A pointer to the newly allocated pairing file + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid, non-null pointer to the provider + */ +struct IdeviceFfiError *idevice_provider_get_pairing_file(struct IdeviceProviderHandle *provider, + struct IdevicePairingFile **pairing_file); + +/** + * Creates a new RestoreServiceClient from a ReadWrite stream + * + * # Arguments + * * [`socket`] - A ReadWriteOpaque handle (consumed) + * * [`client`] - On success, will be set to point to a newly allocated handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *restore_service_new(struct ReadWriteOpaque *socket, + struct RestoreServiceClientHandle **client); + +/** + * Creates a new RestoreServiceClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated RestoreServiceClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *restore_service_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct RestoreServiceClientHandle **client); + +/** + * Enters recovery mode on the device + * + * # Arguments + * * `client` - A valid RestoreServiceClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *restore_service_enter_recovery(struct RestoreServiceClientHandle *client); + +/** + * Reboots the device + * + * # Arguments + * * `client` - A valid RestoreServiceClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *restore_service_reboot(struct RestoreServiceClientHandle *client); + +/** + * Gets preflight info from the device + * + * # Arguments + * * `client` - A valid RestoreServiceClient handle + * * `res` - Will be set to a pointer of a plist dictionary node on success + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *restore_service_get_preflightinfo(struct RestoreServiceClientHandle *client, + plist_t *res); + +/** + * Gets nonces from the device + * + * # Arguments + * * `client` - A valid RestoreServiceClient handle + * * `res` - Will be set to a pointer of a plist dictionary node on success + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *restore_service_get_nonces(struct RestoreServiceClientHandle *client, + plist_t *res); + +/** + * Gets app parameters from the device + * + * # Arguments + * * `client` - A valid RestoreServiceClient handle + * * `res` - Will be set to a pointer of a plist dictionary node on success + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + */ +struct IdeviceFfiError *restore_service_get_app_parameters(struct RestoreServiceClientHandle *client, + plist_t *res); + +/** + * Restores the device language + * + * # Arguments + * * `client` - A valid RestoreServiceClient handle + * * `language` - The language to restore to + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `language` must be a valid null-terminated C string + */ +struct IdeviceFfiError *restore_service_restore_lang(struct RestoreServiceClientHandle *client, + const char *language); + +/** + * Frees a RestoreServiceClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void restore_service_client_free(struct RestoreServiceClientHandle *handle); + +/** + * Generates a new RPPairing file with fresh Ed25519 keys. + * + * # Safety + * `hostname` must be a valid null-terminated C string. + * `out` must be valid and non-null. + */ +struct IdeviceFfiError *rp_pairing_file_generate(const char *hostname, + struct RpPairingFileHandle **out); + +/** + * Reads an RPPairing file from a path. + * + * # Safety + * `path` must be a valid null-terminated C string. + * `out` must be valid and non-null. + */ +struct IdeviceFfiError *rp_pairing_file_read(const char *path, struct RpPairingFileHandle **out); + +/** + * Parses an RPPairing file from plist bytes (XML or binary). + * + * # Safety + * `data` must point to `len` valid bytes. + * `out` must be valid and non-null. + */ +struct IdeviceFfiError *rp_pairing_file_from_bytes(const uint8_t *data, + uintptr_t len, + struct RpPairingFileHandle **out); + +/** + * Serializes an RPPairing file to XML plist bytes. + * + * The caller must free the returned bytes with `idevice_data_free(data, len)`. + * + * # Safety + * `handle`, `out_data`, and `out_len` must be valid and non-null. + */ +struct IdeviceFfiError *rp_pairing_file_to_bytes(struct RpPairingFileHandle *handle, + uint8_t **out_data, + uintptr_t *out_len); + +/** + * Writes an RPPairing file to a path. + * + * # Safety + * `handle` and `path` must be valid. + */ +struct IdeviceFfiError *rp_pairing_file_write(struct RpPairingFileHandle *handle, const char *path); + +/** + * Frees an RPPairing file handle. + * + * # Safety + * `handle` must be valid or NULL. + */ +void rp_pairing_file_free(struct RpPairingFileHandle *handle); + +/** + * Creates a new RSD handshake from a ReadWrite connection + * + * # Arguments + * * [`socket`] - The connection to use for communication + * * [`handle`] - Pointer to store the newly created RsdHandshake handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a ReadWrite handle allocated by this library. It is + * consumed and may not be used again. + * `handle` must be a valid pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *rsd_handshake_new(struct ReadWriteOpaque *socket, + struct RsdHandshakeHandle **handle); + +/** + * Gets the protocol version from the RSD handshake + * + * # Arguments + * * [`handle`] - A valid RsdHandshake handle + * * [`version`] - Pointer to store the protocol version + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `version` must be a valid pointer to store the version + */ +struct IdeviceFfiError *rsd_get_protocol_version(struct RsdHandshakeHandle *handle, + size_t *version); + +/** + * Gets the UUID from the RSD handshake + * + * # Arguments + * * [`handle`] - A valid RsdHandshake handle + * * [`uuid`] - Pointer to store the UUID string (caller must free with rsd_free_string) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `uuid` must be a valid pointer to store the string pointer + */ +struct IdeviceFfiError *rsd_get_uuid(struct RsdHandshakeHandle *handle, char **uuid); + +/** + * Gets all available services from the RSD handshake + * + * # Arguments + * * [`handle`] - A valid RsdHandshake handle + * * [`services`] - Pointer to store the services array + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `services` must be a valid pointer to store the services array + * Caller must free the returned array with rsd_free_services + */ +struct IdeviceFfiError *rsd_get_services(struct RsdHandshakeHandle *handle, + struct CRsdServiceArray **services); + +/** + * Checks if a specific service is available + * + * # Arguments + * * [`handle`] - A valid RsdHandshake handle + * * [`service_name`] - Name of the service to check for + * * [`available`] - Pointer to store the availability result + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `service_name` must be a valid C string + * `available` must be a valid pointer to store the boolean result + */ +struct IdeviceFfiError *rsd_service_available(struct RsdHandshakeHandle *handle, + const char *service_name, + bool *available); + +/** + * Gets information about a specific service + * + * # Arguments + * * [`handle`] - A valid RsdHandshake handle + * * [`service_name`] - Name of the service to get info for + * * [`service_info`] - Pointer to store the service information + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library + * `service_name` must be a valid C string + * `service_info` must be a valid pointer to store the service info + * Caller must free the returned service with rsd_free_service + */ +struct IdeviceFfiError *rsd_get_service_info(struct RsdHandshakeHandle *handle, + const char *service_name, + struct CRsdService **service_info); + +/** + * Clones an RSD handshake + * + * # Safety + * Pass a valid pointer allocated by this library + */ +struct RsdHandshakeHandle *rsd_handshake_clone(struct RsdHandshakeHandle *handshake); + +/** + * Frees a string returned by RSD functions + * + * # Arguments + * * [`string`] - The string to free + * + * # Safety + * Must only be called with strings returned from RSD functions + */ +void rsd_free_string(char *string); + +/** + * Frees a single service returned by rsd_get_service_info + * + * # Arguments + * * [`service`] - The service to free + * + * # Safety + * Must only be called with services returned from rsd_get_service_info + */ +void rsd_free_service(struct CRsdService *service); + +/** + * Frees services array returned by rsd_get_services + * + * # Arguments + * * [`services`] - The services array to free + * + * # Safety + * Must only be called with arrays returned from rsd_get_services + */ +void rsd_free_services(struct CRsdServiceArray *services); + +/** + * Frees an RSD handshake handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to a handle allocated by this library, + * or NULL (in which case this function does nothing) + */ +void rsd_handshake_free(struct RsdHandshakeHandle *handle); + +/** + * Connects to screenshotr service using provider + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated ScreenshotrClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *screenshotr_connect(struct IdeviceProviderHandle *provider, + struct ScreenshotrClientHandle **client); + +/** + * Creates a new ScreenshotService via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated ScreenshotrClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *screenshotr_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct ScreenshotrClientHandle **client); + +/** + * Takes a screenshot from the device + * + * # Arguments + * * `client` - A valid ScreenshotrClient handle + * * `screenshot` - Pointer to store the screenshot data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `screenshot` must be a valid pointer to store the screenshot data + * The caller is responsible for freeing the screenshot data using screenshotr_screenshot_free + */ +struct IdeviceFfiError *screenshotr_take_screenshot(struct ScreenshotrClientHandle *client, + struct ScreenshotData *screenshot); + +/** + * Frees screenshot data + * + * # Arguments + * * `screenshot` - The screenshot data to free + * + * # Safety + * `screenshot` must be a valid ScreenshotData that was allocated by screenshotr_take_screenshot + * or NULL (in which case this function does nothing) + */ +void screenshotr_screenshot_free(struct ScreenshotData screenshot); + +/** + * Frees a ScreenshotrClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void screenshotr_client_free(struct ScreenshotrClientHandle *handle); + +/** + * Connects to the Springboard service using a provider + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated SpringBoardServicesClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *springboard_services_connect(struct IdeviceProviderHandle *provider, + struct SpringBoardServicesClientHandle **client); + +/** + * Creates a new SpringBoardServicesClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated SpringBoardServicesClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *springboard_services_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct SpringBoardServicesClientHandle **client); + +/** + * Creates a new SpringBoardServices client from an existing Idevice connection + * + * # Arguments + * * [`socket`] - An IdeviceSocket handle + * * [`client`] - On success, will be set to point to a newly allocated SpringBoardServicesClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `socket` must be a valid pointer to a handle allocated by this library. The socket is consumed, + * and may not be used again. + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *springboard_services_new(struct IdeviceHandle *socket, + struct SpringBoardServicesClientHandle **client); + +/** + * Gets the icon of the specified app by bundle identifier + * + * # Arguments + * * `client` - A valid SpringBoardServicesClient handle + * * `bundle_identifier` - The identifiers of the app to get icon + * * `out_result` - On success, will be set to point to a newly allocated png data + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `out_result` must be a valid, non-null pointer to a location where the result will be stored + */ +struct IdeviceFfiError *springboard_services_get_icon(struct SpringBoardServicesClientHandle *client, + const char *bundle_identifier, + void **out_result, + size_t *out_result_len); + +/** + * Gets the home screen wallpaper preview as PNG image + * + * # Arguments + * * `client` - A valid SpringBoardServicesClient handle + * * `out_result` - On success, will be set to point to newly allocated png image + * * `out_result_len` - On success, will contain the size of the data in bytes + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `out_result` and `out_result_len` must be valid, non-null pointers + */ +struct IdeviceFfiError *springboard_services_get_home_screen_wallpaper_preview(struct SpringBoardServicesClientHandle *client, + void **out_result, + size_t *out_result_len); + +/** + * Gets the lock screen wallpaper preview as PNG image + * + * # Arguments + * * `client` - A valid SpringBoardServicesClient handle + * * `out_result` - On success, will be set to point to newly allocated png image + * * `out_result_len` - On success, will contain the size of the data in bytes + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `out_result` and `out_result_len` must be valid, non-null pointers + */ +struct IdeviceFfiError *springboard_services_get_lock_screen_wallpaper_preview(struct SpringBoardServicesClientHandle *client, + void **out_result, + size_t *out_result_len); + +/** + * Gets the current interface orientation of the device + * + * # Arguments + * * `client` - A valid SpringBoardServicesClient handle + * * `out_orientation` - On success, will contain the orientation value (0-4) + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `out_orientation` must be a valid, non-null pointer + */ +struct IdeviceFfiError *springboard_services_get_interface_orientation(struct SpringBoardServicesClientHandle *client, + uint8_t *out_orientation); + +/** + * Gets the home screen icon layout metrics + * + * # Arguments + * * `client` - A valid SpringBoardServicesClient handle + * * `res` - On success, will point to a plist dictionary node containing the metrics + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `res` must be a valid, non-null pointer + */ +struct IdeviceFfiError *springboard_services_get_homescreen_icon_metrics(struct SpringBoardServicesClientHandle *client, + plist_t *res); + +/** + * Frees an SpringBoardServicesClient handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void springboard_services_free(struct SpringBoardServicesClientHandle *handle); + +/** + * Automatically creates and connects to syslog relay, returning a client handle + * + * # Arguments + * * [`provider`] - An IdeviceProvider + * * [`client`] - On success, will be set to point to a newly allocated SyslogRelayClient handle + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *syslog_relay_connect_tcp(struct IdeviceProviderHandle *provider, + struct SyslogRelayClientHandle **client); + +/** + * Creates a new SyslogRelayClient via RSD + * + * # Arguments + * * [`provider`] - An adapter created by this library + * * [`handshake`] - An RSD handshake from the same provider + * * [`client`] - On success, will be set to point to a newly allocated SyslogRelayClient handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `provider` must be a valid pointer to a handle allocated by this library + * `handshake` must be a valid pointer to a handle allocated by this library + * `client` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *syslog_relay_connect_rsd(struct AdapterHandle *provider, + struct RsdHandshakeHandle *handshake, + struct SyslogRelayClientHandle **client); + +/** + * Frees a handle + * + * # Arguments + * * [`handle`] - The handle to free + * + * # Safety + * `handle` must be a valid pointer to the handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void syslog_relay_client_free(struct SyslogRelayClientHandle *handle); + +/** + * Gets the next log message from the relay + * + * # Arguments + * * [`client`] - The SyslogRelayClient handle + * * [`log_message`] - On success a newly allocated cstring will be set to point to the log message + * + * # Safety + * `client` must be a valid pointer to a handle allocated by this library + * `log_message` must be a valid, non-null pointer to a location where the log message will be stored + */ +struct IdeviceFfiError *syslog_relay_next(struct SyslogRelayClientHandle *client, + char **log_message); + +/** + * # Safety + * Pass valid pointers. + */ +struct IdeviceFfiError *idevice_tcp_stack_into_sync_objects(const char *our_ip, + const char *their_ip, + struct TcpFeedObject **feeder, + struct TcpEatObject **tcp_receiver, + struct AdapterHandle **adapter_handle); + +/** + * Feed the TCP stack with data + * # Safety + * Pass valid pointers. Data is cloned out of slice. + */ +struct IdeviceFfiError *idevice_tcp_feed_object_write(struct TcpFeedObject *object, + const uint8_t *data, + uintptr_t len); + +/** + * Block on getting a block of data to write to the underlying stream. + * Write this to the stream as is, and free the data with idevice_data_free + * + * # Safety + * Pass valid pointers + */ +struct IdeviceFfiError *idevice_tcp_eat_object_read(struct TcpEatObject *object, + uint8_t **data, + uintptr_t *len); + +/** + * # Safety + * Pass a valid pointer allocated by this library + */ +void idevice_free_tcp_feed_object(struct TcpFeedObject *object); + +/** + * # Safety + * Pass a valid pointer allocated by this library + */ +void idevice_free_tcp_eat_object(struct TcpEatObject *object); + +/** + * Creates a tunnel over USB via CoreDeviceProxy. + * No need to stop remoted. + * + * # Safety + * All pointer arguments must be valid and non-null. + */ +struct IdeviceFfiError *tunnel_create_usb(struct IdeviceProviderHandle *lockdown_provider, + struct AdapterHandle **out_adapter, + struct RsdHandshakeHandle **out_handshake); + +/** + * Pairs via USB CoreDeviceProxy tunnel (no SIGSTOP needed). + * + * For iOS, `pin_callback` can be NULL (defaults to "000000"). + * For Apple TV / Vision Pro, provide a callback returning the on-screen PIN. + * + * # Safety + * All pointer arguments must be valid and non-null (except `pin_callback`/`pin_context`). + */ +struct IdeviceFfiError *tunnel_pair_usb(struct IdeviceProviderHandle *lockdown_provider, + const char *hostname, + const char *(*pin_callback)(void *context), + void *pin_context, + struct RpPairingFileHandle **out_pairing_file); + +/** + * Creates a tunnel over the network via RemoteXPC. + * + * Use this when connecting to a device discovered via `_remoted._tcp` (RSD port). + * The connection goes: RSD → find tunnel service → RemoteXPC → RPPairing → tunnel. + * + * # Safety + * All pointer arguments must be valid and non-null (except `pin_callback`/`pin_context`). + * `pairing_file` is borrowed, not consumed. + */ +struct IdeviceFfiError *tunnel_create_remotexpc(const idevice_sockaddr *addr, + idevice_socklen_t addr_len, + const char *hostname, + struct RpPairingFileHandle *pairing_file, + const char *(*pin_callback)(void *context), + void *pin_context, + struct AdapterHandle **out_adapter, + struct RsdHandshakeHandle **out_handshake); + +/** + * Creates a tunnel over the network via raw RPPairing protocol. + * + * Use this when connecting to a device discovered via `_remotepairing._tcp`. + * The connection goes: direct TCP → RPPairing (JSON) → tunnel. + * + * This path only supports pair-verify (existing pairing file required). + * For initial pairing, use `tunnel_pair_usb`. + * + * # Safety + * All pointer arguments must be valid and non-null (except `pin_callback`/`pin_context`). + * `pairing_file` is borrowed, not consumed. + */ +struct IdeviceFfiError *tunnel_create_rppairing(const idevice_sockaddr *addr, + idevice_socklen_t addr_len, + const char *hostname, + struct RpPairingFileHandle *pairing_file, + const char *(*pin_callback)(void *context), + void *pin_context, + struct AdapterHandle **out_adapter, + struct RsdHandshakeHandle **out_handshake); + +/** + * Connects to a usbmuxd instance over TCP + * + * # Arguments + * * [`addr`] - The socket address to connect to + * * [`addr_len`] - Length of the socket + * * [`tag`] - A tag that will be returned by usbmuxd responses + * * [`usbmuxd_connection`] - On success, will be set to point to a newly allocated UsbmuxdConnection handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `addr` must be a valid sockaddr + * `usbmuxd_connection` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_usbmuxd_new_tcp_connection(const idevice_sockaddr *addr, + idevice_socklen_t addr_len, + uint32_t tag, + struct UsbmuxdConnectionHandle **out); + +/** + * Connects to a usbmuxd instance over unix socket + * + * # Arguments + * * [`addr`] - The socket path to connect to + * * [`tag`] - A tag that will be returned by usbmuxd responses + * * [`usbmuxd_connection`] - On success, will be set to point to a newly allocated UsbmuxdConnection handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `addr` must be a valid CStr + * `usbmuxd_connection` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_usbmuxd_new_unix_socket_connection(const char *addr, + uint32_t tag, + struct UsbmuxdConnectionHandle **usbmuxd_connection); + +/** + * Connects to a usbmuxd instance over the default connection for the platform + * + * # Arguments + * * [`addr`] - The socket path to connect to + * * [`tag`] - A tag that will be returned by usbmuxd responses + * * [`usbmuxd_connection`] - On success, will be set to point to a newly allocated UsbmuxdConnection handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `addr` must be a valid CStr + * `usbmuxd_connection` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_usbmuxd_new_default_connection(uint32_t tag, + struct UsbmuxdConnectionHandle **usbmuxd_connection); + +/** + * Gets a list of connected devices from usbmuxd. + * + * The returned list must be freed with `idevice_usbmuxd_device_list_free`. + * + * # Arguments + * * `usbmuxd_conn` - A valid connection to usbmuxd. + * * `devices` - A pointer to a C-style array of `UsbmuxdDeviceHandle` pointers. On success, this will be filled. + * * `count` - A pointer to an integer. On success, this will be filled with the number of devices found. + * + * # Returns + * An `IdeviceFfiError` on error, `null` on success. + * + * # Safety + * * `usbmuxd_conn` must be a valid pointer. + * * `devices` and `count` must be valid, non-null pointers. + */ +struct IdeviceFfiError *idevice_usbmuxd_get_devices(struct UsbmuxdConnectionHandle *usbmuxd_conn, + struct UsbmuxdDeviceHandle ***devices, + int *count); + +/** + * Connects to a service on a given device. + * + * This function consumes the `UsbmuxdConnectionHandle`. The handle will be invalid after this call + * and must not be used again. The caller is NOT responsible for freeing it. + * A new `IdeviceHandle` is returned on success, which must be freed by the caller. + * + * # Arguments + * * `usbmuxd_connection` - The connection to use. It will be consumed. + * * `device_id` - The ID of the device to connect to. + * * `port` - The TCP port on the device to connect to. + * * `idevice` - On success, points to the new device connection handle. + * + * # Returns + * An `IdeviceFfiError` on error, `null` on success. + * + * # Safety + * * `usbmuxd_connection` must be a valid pointer allocated by this library and never used again. + * The value is consumed. + * * `idevice` must be a valid, non-null pointer. + */ +struct IdeviceFfiError *idevice_usbmuxd_connect_to_device(struct UsbmuxdConnectionHandle *usbmuxd_connection, + uint32_t device_id, + uint16_t port, + const char *label, + struct IdeviceHandle **idevice); + +/** + * Reads the pairing record for a given device UDID. + * + * The returned `PairingFileHandle` must be freed with `idevice_pair_record_free`. + * + * # Arguments + * * `usbmuxd_conn` - A valid connection to usbmuxd. + * * `udid` - The UDID of the device. + * * `pair_record` - On success, points to the new pairing file handle. + * + * # Returns + * An `IdeviceFfiError` on error, `null` on success. + * + * # Safety + * * `usbmuxd_conn` must be a valid pointer. + * * `udid` must be a valid, null-terminated C string. + * * `pair_record` must be a valid, non-null pointer. + */ +struct IdeviceFfiError *idevice_usbmuxd_get_pair_record(struct UsbmuxdConnectionHandle *usbmuxd_conn, + const char *udid, + struct IdevicePairingFile **pair_record); + +/** + * Saves the pairing record for a given device UDID. + * + * # Arguments + * * `usbmuxd_conn` - A valid connection to usbmuxd. + * * `device_id` - The muxer ID for the device + * * `udid` - The UDID of the device. + * * `pair_record` - The bytes of the pairing record plist to save + * * `pair_record_len` - the length of the pairing record bytes + * + * # Returns + * An `IdeviceFfiError` on error, `null` on success. + * + * # Safety + * * `usbmuxd_conn` must be a valid pointer. + * * `udid` must be a valid, null-terminated C string. + * * `pair_record` must be a valid, non-null pointer. + */ +struct IdeviceFfiError *idevice_usbmuxd_save_pair_record(struct UsbmuxdConnectionHandle *usbmuxd_conn, + const char *udid, + uint8_t *pair_record, + uintptr_t pair_record_len); + +/** + * Listens on the socket for connections and disconnections + * + * # Safety + * Pass valid pointers. Free the stream with ``idevice_usbmuxd_listener_handle_free``. + * The stream must outlive the usbmuxd connection, and the usbmuxd connection cannot + * be used for other requests. + */ +struct IdeviceFfiError *idevice_usbmuxd_listen(struct UsbmuxdConnectionHandle *usbmuxd_conn, + struct UsbmuxdListenerHandle **stream_handle); + +/** + * Frees a stream created by ``listen`` or does nothing on null + * + * # Safety + * Pass a valid pointer. + */ +void idevice_usbmuxd_listener_handle_free(struct UsbmuxdListenerHandle *stream_handle); + +/** + * Gets the next event from the stream. + * Connect will be set to true if the event is a connection event, + * and the connection_device will be filled with the device information. + * If connection is false, the mux ID of the device will be filled. + * + * # Arguments + * * `stream_handle` - The handle to the stream returned by listen + * * `connect` - The bool that will be set + * * `connection_device` - The pointer that will be filled on a connect event + * * `disconnection_id` - The mux ID that will be set on a disconnect event + * + * # Safety + * Pass valid pointers + */ +struct IdeviceFfiError *idevice_usbmuxd_listener_next(struct UsbmuxdListenerHandle *stream_handle, + bool *connect, + struct UsbmuxdDeviceHandle **connection_device, + uint32_t *disconnection_id); + +/** + * Reads the BUID (Boot-Unique ID) from usbmuxd. + * + * The returned string must be freed with `idevice_string_free`. + * + * # Arguments + * * `usbmuxd_conn` - A valid connection to usbmuxd. + * * `buid` - On success, points to a newly allocated, null-terminated C string. + * + * # Returns + * An `IdeviceFfiError` on error, `null` on success. + * + * # Safety + * * `usbmuxd_conn` must be a valid pointer. + * * `buid` must be a valid, non-null pointer. + */ +struct IdeviceFfiError *idevice_usbmuxd_get_buid(struct UsbmuxdConnectionHandle *usbmuxd_conn, + char **buid); + +/** + * Frees a UsbmuxdConnection handle + * + * # Arguments + * * [`usbmuxd_connection`] - The UsbmuxdConnection handle to free + * + * # Safety + * `usbmuxd_connection` must be a valid pointer to a UsbmuxdConnection handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void idevice_usbmuxd_connection_free(struct UsbmuxdConnectionHandle *usbmuxd_connection); + +/** + * Creates a usbmuxd TCP address struct + * + * # Arguments + * * [`addr`] - The socket address to connect to + * * [`addr_len`] - Length of the socket + * * [`usbmuxd_addr`] - On success, will be set to point to a newly allocated UsbmuxdAddr handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `addr` must be a valid sockaddr + * `usbmuxd_Addr` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_usbmuxd_tcp_addr_new(const idevice_sockaddr *addr, + idevice_socklen_t addr_len, + struct UsbmuxdAddrHandle **usbmuxd_addr); + +/** + * Creates a new UsbmuxdAddr struct with a unix socket + * + * # Arguments + * * [`addr`] - The socket path to connect to + * * [`usbmuxd_addr`] - On success, will be set to point to a newly allocated UsbmuxdAddr handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `addr` must be a valid CStr + * `usbmuxd_addr` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_usbmuxd_unix_addr_new(const char *addr, + struct UsbmuxdAddrHandle **usbmuxd_addr); + +/** + * Creates a default UsbmuxdAddr struct for the platform + * + * # Arguments + * * [`usbmuxd_addr`] - On success, will be set to point to a newly allocated UsbmuxdAddr handle + * + * # Returns + * An IdeviceFfiError on error, null on success + * + * # Safety + * `usbmuxd_addr` must be a valid, non-null pointer to a location where the handle will be stored + */ +struct IdeviceFfiError *idevice_usbmuxd_default_addr_new(struct UsbmuxdAddrHandle **usbmuxd_addr); + +/** + * Frees a UsbmuxdAddr handle + * + * # Arguments + * * [`usbmuxd_addr`] - The UsbmuxdAddr handle to free + * + * # Safety + * `usbmuxd_addr` must be a valid pointer to a UsbmuxdAddr handle that was allocated by this library, + * or NULL (in which case this function does nothing) + */ +void idevice_usbmuxd_addr_free(struct UsbmuxdAddrHandle *usbmuxd_addr); + +/** + * Frees a list of devices returned by `idevice_usbmuxd_get_devices`. + * + * # Arguments + * * `devices` - The array of device handles to free. + * * `count` - The number of elements in the array. + * + * # Safety + * `devices` must be a valid pointer to an array of `count` device handles + * allocated by this library, or NULL. + */ +void idevice_usbmuxd_device_list_free(struct UsbmuxdDeviceHandle **devices, int count); + +/** + * Frees a usbmuxd device + * + * # Arguments + * * `device` - The device handle to free. + * + * # Safety + * `device` must be a valid pointer to the device handle + * allocated by this library, or NULL. + */ +void idevice_usbmuxd_device_free(struct UsbmuxdDeviceHandle *device); + +/** + * Gets the UDID from a device handle. + * The returned string must be freed by the caller using `idevice_string_free`. + * + * # Safety + * `device` must be a valid pointer to a `UsbmuxdDeviceHandle`. + */ +char *idevice_usbmuxd_device_get_udid(const struct UsbmuxdDeviceHandle *device); + +/** + * Gets the device ID from a device handle. + * + * # Safety + * `device` must be a valid pointer to a `UsbmuxdDeviceHandle`. + */ +uint32_t idevice_usbmuxd_device_get_device_id(const struct UsbmuxdDeviceHandle *device); + +/** + * Gets the connection type (UsbmuxdConnectionType) from a device handle. + * + * # Returns + * The enum value of the connection type, or 0 for null device handles + * + * # Safety + * `device` must be a valid pointer to a `UsbmuxdDeviceHandle`. + */ +uint8_t idevice_usbmuxd_device_get_connection_type(const struct UsbmuxdDeviceHandle *device); + +#endif /* IDEVICE_H */ + + + +// THIS FILE IS UNDER ITS ORIGINAL LICENSE FROM LIBIMOBILEDEVICE +// THIS IS NOT PART OF IDEVICE AND ITS LICENSE +// MORE INFORMATION CAN BE FOUND AT https://github.com/libimobiledevice/libplist + +/** + * @file plist/plist.h + * @brief Main include of libplist + * \internal + * + * Copyright (c) 2012-2023 Nikias Bassen, All Rights Reserved. + * Copyright (c) 2008-2009 Jonathan Beck, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LIBPLIST_H +#define LIBPLIST_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if _MSC_VER && _MSC_VER < 1700 + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + +#else +#include +#endif + +/*{{{ deprecation macros */ +#ifdef __llvm__ + #if defined(__has_extension) + #if (__has_extension(attribute_deprecated_with_message)) + #ifndef PLIST_WARN_DEPRECATED + #define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated(x))) + #endif + #else + #ifndef PLIST_WARN_DEPRECATED + #define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated)) + #endif + #endif + #else + #ifndef PLIST_WARN_DEPRECATED + #define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated)) + #endif + #endif +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 5))) + #ifndef PLIST_WARN_DEPRECATED + #define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated(x))) + #endif +#elif defined(_MSC_VER) + #ifndef PLIST_WARN_DEPRECATED + #define PLIST_WARN_DEPRECATED(x) __declspec(deprecated(x)) + #endif +#else + #define PLIST_WARN_DEPRECATED(x) + #pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#endif +/*}}}*/ + +#ifndef PLIST_API + #ifdef LIBPLIST_STATIC + #define PLIST_API + #elif defined(_WIN32) + #define PLIST_API __declspec(dllimport) + #else + #define PLIST_API + #endif +#endif + +#include +#include +#include + + /** + * libplist : A library to handle Apple Property Lists + * \defgroup PublicAPI Public libplist API + */ + /*@{*/ + + + /** + * The basic plist abstract data type. + */ + typedef void *plist_t; + + /** + * The plist dictionary iterator. + */ + typedef void* plist_dict_iter; + + /** + * The plist array iterator. + */ + typedef void* plist_array_iter; + + /** + * The enumeration of plist node types. + */ + typedef enum + { + PLIST_NONE =-1, /**< No type */ + PLIST_BOOLEAN, /**< Boolean, scalar type */ + PLIST_INT, /**< Integer, scalar type */ + PLIST_REAL, /**< Real, scalar type */ + PLIST_STRING, /**< ASCII string, scalar type */ + PLIST_ARRAY, /**< Ordered array, structured type */ + PLIST_DICT, /**< Unordered dictionary (key/value pair), structured type */ + PLIST_DATE, /**< Date, scalar type */ + PLIST_DATA, /**< Binary data, scalar type */ + PLIST_KEY, /**< Key in dictionaries (ASCII String), scalar type */ + PLIST_UID, /**< Special type used for 'keyed encoding' */ + PLIST_NULL, /**< NULL type */ + } plist_type; + + /* for backwards compatibility */ + #define PLIST_UINT PLIST_INT + + /** + * libplist error values + */ + typedef enum + { + PLIST_ERR_SUCCESS = 0, /**< operation successful */ + PLIST_ERR_INVALID_ARG = -1, /**< one or more of the parameters are invalid */ + PLIST_ERR_FORMAT = -2, /**< the plist contains nodes not compatible with the output format */ + PLIST_ERR_PARSE = -3, /**< parsing of the input format failed */ + PLIST_ERR_NO_MEM = -4, /**< not enough memory to handle the operation */ + PLIST_ERR_IO = -5, /**< I/O error */ + PLIST_ERR_CIRCULAR_REF = -6, /**< circular reference detected */ + PLIST_ERR_MAX_NESTING = -7, /**< maximum nesting depth exceeded */ + PLIST_ERR_UNKNOWN = -255 /**< an unspecified error occurred */ + } plist_err_t; + + /** + * libplist format types + */ + typedef enum + { + PLIST_FORMAT_NONE = 0, /**< No format */ + PLIST_FORMAT_XML = 1, /**< XML format */ + PLIST_FORMAT_BINARY = 2, /**< bplist00 format */ + PLIST_FORMAT_JSON = 3, /**< JSON format */ + PLIST_FORMAT_OSTEP = 4, /**< OpenStep "old-style" plist format */ + /* 5-9 are reserved for possible future use */ + PLIST_FORMAT_PRINT = 10, /**< human-readable output-only format */ + PLIST_FORMAT_LIMD = 11, /**< "libimobiledevice" output-only format (ideviceinfo) */ + PLIST_FORMAT_PLUTIL = 12, /**< plutil-style output-only format */ + } plist_format_t; + + /** + * libplist write options + */ + typedef enum + { + PLIST_OPT_NONE = 0, /**< Default value to use when none of the options is needed. */ + PLIST_OPT_COMPACT = 1 << 0, /**< Use a compact representation (non-prettified). Only valid for #PLIST_FORMAT_JSON and #PLIST_FORMAT_OSTEP. */ + PLIST_OPT_PARTIAL_DATA = 1 << 1, /**< Print 24 bytes maximum of #PLIST_DATA values. If the data is longer than 24 bytes, the first 16 and last 8 bytes will be written. Only valid for #PLIST_FORMAT_PRINT. */ + PLIST_OPT_NO_NEWLINE = 1 << 2, /**< Do not print a final newline character. Only valid for #PLIST_FORMAT_PRINT, #PLIST_FORMAT_LIMD, and #PLIST_FORMAT_PLUTIL. */ + PLIST_OPT_INDENT = 1 << 3, /**< Indent each line of output. Currently only #PLIST_FORMAT_PRINT and #PLIST_FORMAT_LIMD are supported. Use #PLIST_OPT_INDENT_BY() macro to specify the level of indentation. */ + } plist_write_options_t; + + /** To be used with #PLIST_OPT_INDENT - encodes the level of indentation for OR'ing it into the #plist_write_options_t bitfield. */ + #define PLIST_OPT_INDENT_BY(x) ((x & 0xFF) << 24) + + + /******************************************** + * * + * Creation & Destruction * + * * + ********************************************/ + + /** + * Create a new root plist_t type #PLIST_DICT + * + * @return the created plist + * @sa #plist_type + */ + PLIST_API plist_t plist_new_dict(void); + + /** + * Create a new root plist_t type #PLIST_ARRAY + * + * @return the created plist + * @sa #plist_type + */ + PLIST_API plist_t plist_new_array(void); + + /** + * Create a new plist_t type #PLIST_STRING + * + * @param val the sting value, encoded in UTF8. + * @return the created item + * @sa #plist_type + */ + PLIST_API plist_t plist_new_string(const char *val); + + /** + * Create a new plist_t type #PLIST_BOOLEAN + * + * @param val the boolean value, 0 is false, other values are true. + * @return the created item + * @sa #plist_type + */ + PLIST_API plist_t plist_new_bool(uint8_t val); + + /** + * Create a new plist_t type #PLIST_INT with an unsigned integer value + * + * @param val the unsigned integer value + * @return the created item + * @sa #plist_type + * @note The value is always stored as uint64_t internally. + * Use #plist_get_uint_val or #plist_get_int_val to get the unsigned or signed value. + */ + PLIST_API plist_t plist_new_uint(uint64_t val); + + /** + * Create a new plist_t type #PLIST_INT with a signed integer value + * + * @param val the signed integer value + * @return the created item + * @sa #plist_type + * @note The value is always stored as uint64_t internally. + * Use #plist_get_uint_val or #plist_get_int_val to get the unsigned or signed value. + */ + PLIST_API plist_t plist_new_int(int64_t val); + + /** + * Create a new plist_t type #PLIST_REAL + * + * @param val the real value + * @return the created item + * @sa #plist_type + */ + PLIST_API plist_t plist_new_real(double val); + + /** + * Create a new plist_t type #PLIST_DATA + * + * @param val the binary buffer + * @param length the length of the buffer + * @return the created item + * @sa #plist_type + */ + PLIST_API plist_t plist_new_data(const char *val, uint64_t length); + + /** + * Create a new plist_t type #PLIST_DATE + * + * @param sec The number of seconds since 01/01/1970 (UNIX timestamp) + * @return the created item + * @sa #plist_type + */ + PLIST_API plist_t plist_new_unix_date(int64_t sec); + + /** + * Create a new plist_t type #PLIST_UID + * + * @param val the unsigned integer value + * @return the created item + * @sa #plist_type + */ + PLIST_API plist_t plist_new_uid(uint64_t val); + + /** + * Create a new plist_t type #PLIST_NULL + * @return the created item + * @sa #plist_type + * @note This type is not valid for all formats, e.g. the XML format + * does not support it. + */ + PLIST_API plist_t plist_new_null(void); + + /** + * Destruct a plist_t node and all its children recursively + * + * @param plist the plist to free + */ + PLIST_API void plist_free(plist_t plist); + + /** + * Return a copy of passed node and it's children + * + * @param node the plist to copy + * @return copied plist + */ + PLIST_API plist_t plist_copy(plist_t node); + + + /******************************************** + * * + * Array functions * + * * + ********************************************/ + + /** + * Get size of a #PLIST_ARRAY node. + * + * @param node the node of type #PLIST_ARRAY + * @return size of the #PLIST_ARRAY node + */ + PLIST_API uint32_t plist_array_get_size(plist_t node); + + /** + * Get the nth item in a #PLIST_ARRAY node. + * + * @param node the node of type #PLIST_ARRAY + * @param n the index of the item to get. Range is [0, array_size[ + * @return the nth item or NULL if node is not of type #PLIST_ARRAY + */ + PLIST_API plist_t plist_array_get_item(plist_t node, uint32_t n); + + /** + * Get the index of an item. item must be a member of a #PLIST_ARRAY node. + * + * @param node the node + * @return the node index or UINT_MAX if node index can't be determined + */ + PLIST_API uint32_t plist_array_get_item_index(plist_t node); + + /** + * Set the nth item in a #PLIST_ARRAY node. + * The previous item at index n will be freed using #plist_free + * + * @param node the node of type #PLIST_ARRAY + * @param item the new item at index n. The array is responsible for freeing item when it is no longer needed. + * @param n the index of the item to get. Range is [0, array_size[. Assert if n is not in range. + */ + PLIST_API void plist_array_set_item(plist_t node, plist_t item, uint32_t n); + + /** + * Append a new item at the end of a #PLIST_ARRAY node. + * + * @param node the node of type #PLIST_ARRAY + * @param item the new item. The array is responsible for freeing item when it is no longer needed. + */ + PLIST_API void plist_array_append_item(plist_t node, plist_t item); + + /** + * Insert a new item at position n in a #PLIST_ARRAY node. + * + * @param node the node of type #PLIST_ARRAY + * @param item the new item to insert. The array is responsible for freeing item when it is no longer needed. + * @param n The position at which the node will be stored. Range is [0, array_size[. Assert if n is not in range. + */ + PLIST_API void plist_array_insert_item(plist_t node, plist_t item, uint32_t n); + + /** + * Remove an existing position in a #PLIST_ARRAY node. + * Removed position will be freed using #plist_free. + * + * @param node the node of type #PLIST_ARRAY + * @param n The position to remove. Range is [0, array_size[. Assert if n is not in range. + */ + PLIST_API void plist_array_remove_item(plist_t node, uint32_t n); + + /** + * Remove a node that is a child node of a #PLIST_ARRAY node. + * node will be freed using #plist_free. + * + * @param node The node to be removed from its #PLIST_ARRAY parent. + */ + PLIST_API void plist_array_item_remove(plist_t node); + + /** + * Create an iterator of a #PLIST_ARRAY node. + * The allocated iterator should be freed with the standard free function. + * + * @param node The node of type #PLIST_ARRAY + * @param iter Location to store the iterator for the array. + */ + PLIST_API void plist_array_new_iter(plist_t node, plist_array_iter *iter); + + /** + * Increment iterator of a #PLIST_ARRAY node. + * + * @param node The node of type #PLIST_ARRAY. + * @param iter Iterator of the array + * @param item Location to store the item. The caller must *not* free the + * returned item. Will be set to NULL when no more items are left + * to iterate. + */ + PLIST_API void plist_array_next_item(plist_t node, plist_array_iter iter, plist_t *item); + + /** + * Free #PLIST_ARRAY iterator. + * + * @param iter Iterator to free. + */ + PLIST_API void plist_array_free_iter(plist_array_iter iter); + + /******************************************** + * * + * Dictionary functions * + * * + ********************************************/ + + /** + * Get size of a #PLIST_DICT node. + * + * @param node the node of type #PLIST_DICT + * @return size of the #PLIST_DICT node + */ + PLIST_API uint32_t plist_dict_get_size(plist_t node); + + /** + * Create an iterator of a #PLIST_DICT node. + * The allocated iterator should be freed with the standard free function. + * + * @param node The node of type #PLIST_DICT. + * @param iter Location to store the iterator for the dictionary. + */ + PLIST_API void plist_dict_new_iter(plist_t node, plist_dict_iter *iter); + + /** + * Increment iterator of a #PLIST_DICT node. + * + * @param node The node of type #PLIST_DICT + * @param iter Iterator of the dictionary + * @param key Location to store the key, or NULL. The caller is responsible + * for freeing the the returned string. + * @param val Location to store the value, or NULL. The caller must *not* + * free the returned value. Will be set to NULL when no more + * key/value pairs are left to iterate. + */ + PLIST_API void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val); + + /** + * Free #PLIST_DICT iterator. + * + * @param iter Iterator to free. + */ + PLIST_API void plist_dict_free_iter(plist_dict_iter iter); + + /** + * Get key associated key to an item. Item must be member of a dictionary. + * + * @param node the item + * @param key a location to store the key. The caller is responsible for freeing the returned string. + */ + PLIST_API void plist_dict_get_item_key(plist_t node, char **key); + + /** + * Get the nth item in a #PLIST_DICT node. + * + * @param node the node of type #PLIST_DICT + * @param key the identifier of the item to get. + * @return the item or NULL if node is not of type #PLIST_DICT. The caller should not free + * the returned node. + */ + PLIST_API plist_t plist_dict_get_item(plist_t node, const char* key); + + /** + * Get key node associated to an item. Item must be member of a dictionary. + * + * @param node the item + * @return the key node of the given item, or NULL. + */ + PLIST_API plist_t plist_dict_item_get_key(plist_t node); + + /** + * Set item identified by key in a #PLIST_DICT node. + * The previous item identified by key will be freed using #plist_free. + * If there is no item for the given key a new item will be inserted. + * + * @param node the node of type #PLIST_DICT + * @param item the new item associated to key + * @param key the identifier of the item to set. + */ + PLIST_API void plist_dict_set_item(plist_t node, const char* key, plist_t item); + + /** + * Remove an existing position in a #PLIST_DICT node. + * Removed position will be freed using #plist_free + * + * @param node the node of type #PLIST_DICT + * @param key The identifier of the item to remove. Assert if identifier is not present. + */ + PLIST_API void plist_dict_remove_item(plist_t node, const char* key); + + /** + * Merge a dictionary into another. This will add all key/value pairs + * from the source dictionary to the target dictionary, overwriting + * any existing key/value pairs that are already present in target. + * + * @param target pointer to an existing node of type #PLIST_DICT + * @param source node of type #PLIST_DICT that should be merged into target + */ + PLIST_API void plist_dict_merge(plist_t *target, plist_t source); + + /** + * Get a boolean value from a given #PLIST_DICT entry. + * + * The value node can be of type #PLIST_BOOLEAN, but also + * #PLIST_STRING (either 'true' or 'false'), + * #PLIST_INT with a numerical value of 0 or >= 1, + * or #PLIST_DATA with a single byte with a value of 0 or >= 1. + * + * @note This function returns 0 if the dictionary does not contain an + * entry for the given key, if the value node is of any other than + * the above mentioned type, or has any mismatching value. + * + * @param dict A node of type #PLIST_DICT + * @param key The key to look for in dict + * @return 0 or 1 depending on the value of the node. + */ + PLIST_API uint8_t plist_dict_get_bool(plist_t dict, const char *key); + + /** + * Get a signed integer value from a given #PLIST_DICT entry. + * The value node can be of type #PLIST_INT, but also + * #PLIST_STRING with a numerical value as string (decimal or hexadecimal), + * or #PLIST_DATA with a size of 1, 2, 4, or 8 bytes in little endian byte order. + * + * @note This function returns 0 if the dictionary does not contain an + * entry for the given key, if the value node is of any other than + * the above mentioned type, or has any mismatching value. + * + * @param dict A node of type #PLIST_DICT + * @param key The key to look for in dict + * @return Signed integer value depending on the value of the node. + */ + PLIST_API int64_t plist_dict_get_int(plist_t dict, const char *key); + + /** + * Get an unsigned integer value from a given #PLIST_DICT entry. + * The value node can be of type #PLIST_INT, but also + * #PLIST_STRING with a numerical value as string (decimal or hexadecimal), + * or #PLIST_DATA with a size of 1, 2, 4, or 8 bytes in little endian byte order. + * + * @note This function returns 0 if the dictionary does not contain an + * entry for the given key, if the value node is of any other than + * the above mentioned type, or has any mismatching value. + * + * @param dict A node of type #PLIST_DICT + * @param key The key to look for in dict + * @return Signed integer value depending on the value of the node. + */ + PLIST_API uint64_t plist_dict_get_uint(plist_t dict, const char *key); + + /** + * Copy a node from *source_dict* to *target_dict*. + * The node is looked up in *source_dict* with given *key*, unless *alt_source_key* + * is non-NULL, in which case it is looked up with *alt_source_key*. + * The entry in *target_dict* is **always** created with *key*. + * + * @param target_dict The target dictionary to copy to. + * @param source_dict The source dictionary to copy from. + * @param key The key for the node to copy. + * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL. + * + * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain + * any entry with given key or alt_source_key. + */ + PLIST_API plist_err_t plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); + + /** + * Copy a boolean value from *source_dict* to *target_dict*. + * The node is looked up in *source_dict* with given *key*, unless *alt_source_key* + * is non-NULL, in which case it is looked up with *alt_source_key*. + * The entry in *target_dict* is **always** created with *key*. + * + * @note The boolean value from *source_dict* is retrieved with #plist_dict_get_bool, + * but is **always** created as #PLIST_BOOLEAN in *target_dict*. + * + * @param target_dict The target dictionary to copy to. + * @param source_dict The source dictionary to copy from. + * @param key The key for the node to copy. + * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL. + * + * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain + * any entry with given key or alt_source_key. + */ + PLIST_API plist_err_t plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); + + /** + * Copy a signed integer value from *source_dict* to *target_dict*. + * The node is looked up in *source_dict* with given *key*, unless *alt_source_key* + * is non-NULL, in which case it is looked up with *alt_source_key*. + * The entry in *target_dict* is **always** created with *key*. + * + * @note The signed integer value from *source_dict* is retrieved with #plist_dict_get_int, + * but is **always** created as #PLIST_INT. + * + * @param target_dict The target dictionary to copy to. + * @param source_dict The source dictionary to copy from. + * @param key The key for the node value to copy. + * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL. + * + * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain + * any entry with given key or alt_source_key. + */ + PLIST_API plist_err_t plist_dict_copy_int(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); + + /** + * Copy an unsigned integer value from *source_dict* to *target_dict*. + * The node is looked up in *source_dict* with given *key*, unless *alt_source_key* + * is non-NULL, in which case it is looked up with *alt_source_key*. + * The entry in *target_dict* is **always** created with *key*. + * + * @note The unsigned integer value from *source_dict* is retrieved with #plist_dict_get_uint, + * but is **always** created as #PLIST_INT. + * + * @param target_dict The target dictionary to copy to. + * @param source_dict The source dictionary to copy from. + * @param key The key for the node value to copy. + * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL. + * + * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain + * any entry with given key or alt_source_key. + */ + PLIST_API plist_err_t plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); + + /** + * Copy a #PLIST_DATA node from *source_dict* to *target_dict*. + * The node is looked up in *source_dict* with given *key*, unless *alt_source_key* + * is non-NULL, in which case it is looked up with *alt_source_key*. + * The entry in *target_dict* is **always** created with *key*. + * + * @note This function is like #plist_dict_copy_item, except that it fails + * if the source node is not of type #PLIST_DATA. + * + * @param target_dict The target dictionary to copy to. + * @param source_dict The source dictionary to copy from. + * @param key The key for the node value to copy. + * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL. + * + * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain + * any entry with given key or alt_source_key, or if it is not of type #PLIST_DATA. + */ + PLIST_API plist_err_t plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); + + /** + * Copy a #PLIST_STRING node from *source_dict* to *target_dict*. + * The node is looked up in *source_dict* with given *key*, unless *alt_source_key* + * is non-NULL, in which case it is looked up with *alt_source_key*. + * The entry in *target_dict* is **always** created with *key*. + * + * @note This function is like #plist_dict_copy_item, except that it fails + * if the source node is not of type #PLIST_STRING. + * + * @param target_dict The target dictionary to copy to. + * @param source_dict The source dictionary to copy from. + * @param key The key for the node value to copy. + * @param alt_source_key The alternative source key for lookup in *source_dict* or NULL. + * + * @result PLIST_ERR_SUCCESS on success or PLIST_ERR_INVALID_ARG if the source dictionary does not contain + * any entry with given key or alt_source_key, or if it is not of type #PLIST_STRING. + */ + PLIST_API plist_err_t plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); + + /******************************************** + * * + * Getters * + * * + ********************************************/ + + /** + * Get the parent of a node + * + * @param node the parent (NULL if node is root) + */ + PLIST_API plist_t plist_get_parent(plist_t node); + + /** + * Get the #plist_type of a node. + * + * @param node the node + * @return the type of the node + */ + PLIST_API plist_type plist_get_node_type(plist_t node); + + /** + * Get the value of a #PLIST_KEY node. + * This function does nothing if node is not of type #PLIST_KEY + * + * @param node the node + * @param val a pointer to a C-string. This function allocates the memory, + * caller is responsible for freeing it. + * @note Use plist_mem_free() to free the allocated memory. + */ + PLIST_API void plist_get_key_val(plist_t node, char **val); + + /** + * Get the value of a #PLIST_STRING node. + * This function does nothing if node is not of type #PLIST_STRING + * + * @param node the node + * @param val a pointer to a C-string. This function allocates the memory, + * caller is responsible for freeing it. Data is UTF-8 encoded. + * @note Use plist_mem_free() to free the allocated memory. + */ + PLIST_API void plist_get_string_val(plist_t node, char **val); + + /** + * Get a pointer to the buffer of a #PLIST_STRING node. + * + * @note DO NOT MODIFY the buffer. Mind that the buffer is only available + * until the plist node gets freed. Make a copy if needed. + * + * @param node The node + * @param length If non-NULL, will be set to the length of the string + * + * @return Pointer to the NULL-terminated buffer. + */ + PLIST_API const char* plist_get_string_ptr(plist_t node, uint64_t* length); + + /** + * Get the value of a #PLIST_BOOLEAN node. + * This function does nothing if node is not of type #PLIST_BOOLEAN + * + * @param node the node + * @param val a pointer to a uint8_t variable. + */ + PLIST_API void plist_get_bool_val(plist_t node, uint8_t * val); + + /** + * Get the unsigned integer value of a #PLIST_INT node. + * This function does nothing if node is not of type #PLIST_INT + * + * @param node the node + * @param val a pointer to a uint64_t variable. + */ + PLIST_API void plist_get_uint_val(plist_t node, uint64_t * val); + + /** + * Get the signed integer value of a #PLIST_INT node. + * This function does nothing if node is not of type #PLIST_INT + * + * @param node the node + * @param val a pointer to a int64_t variable. + */ + PLIST_API void plist_get_int_val(plist_t node, int64_t * val); + + /** + * Get the value of a #PLIST_REAL node. + * This function does nothing if node is not of type #PLIST_REAL + * + * @param node the node + * @param val a pointer to a double variable. + */ + PLIST_API void plist_get_real_val(plist_t node, double *val); + + /** + * Get the value of a #PLIST_DATA node. + * This function does nothing if node is not of type #PLIST_DATA + * + * @param node the node + * @param val a pointer to an unallocated char buffer. This function allocates the memory, + * caller is responsible for freeing it. + * @param length the length of the buffer + * @note Use plist_mem_free() to free the allocated memory. + */ + PLIST_API void plist_get_data_val(plist_t node, char **val, uint64_t * length); + + /** + * Get a pointer to the data buffer of a #PLIST_DATA node. + * + * @note DO NOT MODIFY the buffer. Mind that the buffer is only available + * until the plist node gets freed. Make a copy if needed. + * + * @param node The node + * @param length Pointer to a uint64_t that will be set to the length of the buffer + * + * @return Pointer to the buffer + */ + PLIST_API const char* plist_get_data_ptr(plist_t node, uint64_t* length); + + /** + * Get the value of a #PLIST_DATE node. + * This function does nothing if node is not of type #PLIST_DATE + * + * @param node the node + * @param sec a pointer to an int64_t variable. Represents the number of seconds since 01/01/1970 (UNIX timestamp). + */ + PLIST_API void plist_get_unix_date_val(plist_t node, int64_t *sec); + + /** + * Get the value of a #PLIST_UID node. + * This function does nothing if node is not of type #PLIST_UID + * + * @param node the node + * @param val a pointer to a uint64_t variable. + */ + PLIST_API void plist_get_uid_val(plist_t node, uint64_t * val); + + + /******************************************** + * * + * Setters * + * * + ********************************************/ + + /** + * Set the value of a node. + * Forces type of node to #PLIST_KEY + * + * @param node the node + * @param val the key value + */ + PLIST_API void plist_set_key_val(plist_t node, const char *val); + + /** + * Set the value of a node. + * Forces type of node to #PLIST_STRING + * + * @param node the node + * @param val the string value. The string is copied when set and will be + * freed by the node. + */ + PLIST_API void plist_set_string_val(plist_t node, const char *val); + + /** + * Set the value of a node. + * Forces type of node to #PLIST_BOOLEAN + * + * @param node the node + * @param val the boolean value + */ + PLIST_API void plist_set_bool_val(plist_t node, uint8_t val); + + /** + * Set the value of a node. + * Forces type of node to #PLIST_INT + * + * @param node the node + * @param val the unsigned integer value + */ + PLIST_API void plist_set_uint_val(plist_t node, uint64_t val); + + /** + * Set the value of a node. + * Forces type of node to #PLIST_INT + * + * @param node the node + * @param val the signed integer value + */ + PLIST_API void plist_set_int_val(plist_t node, int64_t val); + + /** + * Set the value of a node. + * Forces type of node to #PLIST_REAL + * + * @param node the node + * @param val the real value + */ + PLIST_API void plist_set_real_val(plist_t node, double val); + + /** + * Set the value of a node. + * Forces type of node to #PLIST_DATA + * + * @param node the node + * @param val the binary buffer. The buffer is copied when set and will + * be freed by the node. + * @param length the length of the buffer + */ + PLIST_API void plist_set_data_val(plist_t node, const char *val, uint64_t length); + + /** + * Set the value of a node. + * Forces type of node to #PLIST_DATE + * + * @param node the node + * @param sec the number of seconds since 01/01/1970 (UNIX timestamp) + */ + PLIST_API void plist_set_unix_date_val(plist_t node, int64_t sec); + + /** + * Set the value of a node. + * Forces type of node to #PLIST_UID + * + * @param node the node + * @param val the unsigned integer value + */ + PLIST_API void plist_set_uid_val(plist_t node, uint64_t val); + + + /******************************************** + * * + * Import & Export * + * * + ********************************************/ + + /** + * Export the #plist_t structure to XML format. + * + * @param plist the root node to export + * @param plist_xml a pointer to a C-string. This function allocates the memory, + * caller is responsible for freeing it. Data is UTF-8 encoded. + * @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + * @note Use plist_mem_free() to free the allocated memory. + */ + PLIST_API plist_err_t plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length); + + /** + * Export the #plist_t structure to binary format. + * + * @param plist the root node to export + * @param plist_bin a pointer to a char* buffer. This function allocates the memory, + * caller is responsible for freeing it. + * @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + * @note Use plist_mem_free() to free the allocated memory. + */ + PLIST_API plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length); + + /** + * Export the #plist_t structure to JSON format. + * + * @param plist the root node to export + * @param plist_json a pointer to a char* buffer. This function allocates the memory, + * caller is responsible for freeing it. + * @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer. + * @param prettify pretty print the output if != 0 + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + * @note Use plist_mem_free() to free the allocated memory. + */ + PLIST_API plist_err_t plist_to_json(plist_t plist, char **plist_json, uint32_t* length, int prettify); + + /** + * Export the #plist_t structure to OpenStep format. + * + * @param plist the root node to export + * @param plist_openstep a pointer to a char* buffer. This function allocates the memory, + * caller is responsible for freeing it. + * @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer. + * @param prettify pretty print the output if != 0 + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + * @note Use plist_mem_free() to free the allocated memory. + */ + PLIST_API plist_err_t plist_to_openstep(plist_t plist, char **plist_openstep, uint32_t* length, int prettify); + + + /** + * Import the #plist_t structure from XML format. + * + * @param plist_xml a pointer to the xml buffer. + * @param length length of the buffer to read. + * @param plist a pointer to the imported plist. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + */ + PLIST_API plist_err_t plist_from_xml(const char *plist_xml, uint32_t length, plist_t * plist); + + /** + * Import the #plist_t structure from binary format. + * + * @param plist_bin a pointer to the xml buffer. + * @param length length of the buffer to read. + * @param plist a pointer to the imported plist. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + */ + PLIST_API plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist); + + /** + * Import the #plist_t structure from JSON format. + * + * @param json a pointer to the JSON buffer. + * @param length length of the buffer to read. + * @param plist a pointer to the imported plist. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + */ + PLIST_API plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist); + + /** + * Import the #plist_t structure from OpenStep plist format. + * + * @param openstep a pointer to the OpenStep plist buffer. + * @param length length of the buffer to read. + * @param plist a pointer to the imported plist. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + */ + PLIST_API plist_err_t plist_from_openstep(const char *openstep, uint32_t length, plist_t * plist); + + /** + * Import the #plist_t structure from memory data. + * + * This function will look at the first bytes of plist_data + * to determine if plist_data contains a binary, JSON, OpenStep, or XML plist + * and tries to parse the data in the appropriate format. + * @note This is just a convenience function and the format detection is + * very basic. It checks with plist_is_binary() if the data supposedly + * contains binary plist data, if not it checks if the first bytes have + * either '{' or '[' and assumes JSON format, and XML tags will result + * in parsing as XML, otherwise it will try to parse as OpenStep. + * + * @param plist_data A pointer to the memory buffer containing plist data. + * @param length Length of the buffer to read. + * @param plist A pointer to the imported plist. + * @param format If non-NULL, the #plist_format_t value pointed to will be set to the parsed format. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + */ + PLIST_API plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t *plist, plist_format_t *format); + + /** + * Import the #plist_t structure directly from file. + * + * This function will look at the first bytes of the file data + * to determine if it contains a binary, JSON, OpenStep, or XML plist + * and tries to parse the data in the appropriate format. + * Uses plist_from_memory() internally. + * + * @param filename The name of the file to parse. + * @param plist A pointer to the imported plist. + * @param format If non-NULL, the #plist_format_t value pointed to will be set to the parsed format. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure + */ + PLIST_API plist_err_t plist_read_from_file(const char *filename, plist_t *plist, plist_format_t *format); + + /** + * Write the #plist_t structure to a NULL-terminated string using the given format and options. + * + * @param plist The input plist structure + * @param output Pointer to a char* buffer. This function allocates the memory, + * caller is responsible for freeing it. + * @param length A pointer to a uint32_t value that will receive the lenght of the allocated buffer. + * @param format A #plist_format_t value that specifies the output format to use. + * @param options One or more bitwise ORed values of #plist_write_options_t. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure. + * @note Use plist_mem_free() to free the allocated memory. + * @note #PLIST_FORMAT_BINARY is not supported by this function. + */ + PLIST_API plist_err_t plist_write_to_string(plist_t plist, char **output, uint32_t* length, plist_format_t format, plist_write_options_t options); + + /** + * Write the #plist_t structure to a FILE* stream using the given format and options. + * + * @param plist The input plist structure + * @param stream A writeable FILE* stream that the data will be written to. + * @param format A #plist_format_t value that specifies the output format to use. + * @param options One or more bitwise ORed values of #plist_write_options_t. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure. + * @note While this function allows all formats to be written to the given stream, + * only the formats #PLIST_FORMAT_PRINT, #PLIST_FORMAT_LIMD, and #PLIST_FORMAT_PLUTIL + * (basically all output-only formats) are directly and efficiently written to the stream; + * the other formats are written to a memory buffer first. + */ + PLIST_API plist_err_t plist_write_to_stream(plist_t plist, FILE* stream, plist_format_t format, plist_write_options_t options); + + /** + * Write the #plist_t structure to a file at given path using the given format and options. + * + * @param plist The input plist structure + * @param filename The file name of the file to write to. Existing files will be overwritten. + * @param format A #plist_format_t value that specifies the output format to use. + * @param options One or more bitwise ORed values of #plist_write_options_t. + * @return PLIST_ERR_SUCCESS on success or a #plist_err_t on failure. + * @note Use plist_mem_free() to free the allocated memory. + */ + PLIST_API plist_err_t plist_write_to_file(plist_t plist, const char *filename, plist_format_t format, plist_write_options_t options); + + /** + * Print the given plist in human-readable format to standard output. + * This is equivalent to + * plist_write_to_stream(plist, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_PARTIAL_DATA); + * @param plist The #plist_t structure to print + * @note For #PLIST_DATA nodes, only a maximum of 24 bytes (first 16 and last 8) are written. + */ + PLIST_API void plist_print(plist_t plist); + + /** + * Test if in-memory plist data is in binary format. + * This function will look at the first bytes of plist_data to determine + * if it supposedly contains a binary plist. + * @note The function is not validating the whole memory buffer to check + * if the content is truly a plist, it is only using some heuristic on + * the first few bytes of plist_data. + * + * @param plist_data a pointer to the memory buffer containing plist data. + * @param length length of the buffer to read. + * @return 1 if the buffer is a binary plist, 0 otherwise. + */ + PLIST_API int plist_is_binary(const char *plist_data, uint32_t length); + + /******************************************** + * * + * Utils * + * * + ********************************************/ + + /** + * Get a node from its path. Each path element depends on the associated father node type. + * For Dictionaries, var args are casted to const char*, for arrays, var args are caster to uint32_t + * Search is breath first order. + * + * @param plist the node to access result from. + * @param length length of the path to access + * @return the value to access. + */ + PLIST_API plist_t plist_access_path(plist_t plist, uint32_t length, ...); + + /** + * Variadic version of #plist_access_path. + * + * @param plist the node to access result from. + * @param length length of the path to access + * @param v list of array's index and dic'st key + * @return the value to access. + */ + PLIST_API plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v); + + /** + * Compare two node values + * + * @param node_l left node to compare + * @param node_r rigth node to compare + * @return TRUE is type and value match, FALSE otherwise. + */ + PLIST_API char plist_compare_node_value(plist_t node_l, plist_t node_r); + + /** Helper macro used by PLIST_IS_* macros that will evaluate the type of a plist node. */ + #define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type)) + + /* Helper macros for the different plist types */ + /** Evaluates to true if the given plist node is of type PLIST_BOOLEAN */ + #define PLIST_IS_BOOLEAN(__plist) _PLIST_IS_TYPE(__plist, BOOLEAN) + /** Evaluates to true if the given plist node is of type PLIST_INT */ + #define PLIST_IS_INT(__plist) _PLIST_IS_TYPE(__plist, INT) + /** Evaluates to true if the given plist node is of type PLIST_REAL */ + #define PLIST_IS_REAL(__plist) _PLIST_IS_TYPE(__plist, REAL) + /** Evaluates to true if the given plist node is of type PLIST_STRING */ + #define PLIST_IS_STRING(__plist) _PLIST_IS_TYPE(__plist, STRING) + /** Evaluates to true if the given plist node is of type PLIST_ARRAY */ + #define PLIST_IS_ARRAY(__plist) _PLIST_IS_TYPE(__plist, ARRAY) + /** Evaluates to true if the given plist node is of type PLIST_DICT */ + #define PLIST_IS_DICT(__plist) _PLIST_IS_TYPE(__plist, DICT) + /** Evaluates to true if the given plist node is of type PLIST_DATE */ + #define PLIST_IS_DATE(__plist) _PLIST_IS_TYPE(__plist, DATE) + /** Evaluates to true if the given plist node is of type PLIST_DATA */ + #define PLIST_IS_DATA(__plist) _PLIST_IS_TYPE(__plist, DATA) + /** Evaluates to true if the given plist node is of type PLIST_KEY */ + #define PLIST_IS_KEY(__plist) _PLIST_IS_TYPE(__plist, KEY) + /** Evaluates to true if the given plist node is of type PLIST_UID */ + #define PLIST_IS_UID(__plist) _PLIST_IS_TYPE(__plist, UID) + /* for backwards compatibility */ + #define PLIST_IS_UINT PLIST_IS_INT + + /** + * Helper function to check the value of a PLIST_BOOL node. + * + * @param boolnode node of type PLIST_BOOL + * @return 1 if the boolean node has a value of TRUE or 0 if FALSE. + */ + PLIST_API int plist_bool_val_is_true(plist_t boolnode); + + /** + * Helper function to test if a given #PLIST_INT node's value is negative + * + * @param intnode node of type PLIST_INT + * @return 1 if the node's value is negative, or 0 if positive. + */ + PLIST_API int plist_int_val_is_negative(plist_t intnode); + + /** + * Helper function to compare the value of a PLIST_INT node against + * a given signed integer value. + * + * @param uintnode node of type PLIST_INT + * @param cmpval value to compare against + * @return 0 if the node's value and cmpval are equal, + * 1 if the node's value is greater than cmpval, + * or -1 if the node's value is less than cmpval. + */ + PLIST_API int plist_int_val_compare(plist_t uintnode, int64_t cmpval); + + /** + * Helper function to compare the value of a PLIST_INT node against + * a given unsigned integer value. + * + * @param uintnode node of type PLIST_INT + * @param cmpval value to compare against + * @return 0 if the node's value and cmpval are equal, + * 1 if the node's value is greater than cmpval, + * or -1 if the node's value is less than cmpval. + */ + PLIST_API int plist_uint_val_compare(plist_t uintnode, uint64_t cmpval); + + /** + * Helper function to compare the value of a PLIST_UID node against + * a given value. + * + * @param uidnode node of type PLIST_UID + * @param cmpval value to compare against + * @return 0 if the node's value and cmpval are equal, + * 1 if the node's value is greater than cmpval, + * or -1 if the node's value is less than cmpval. + */ + PLIST_API int plist_uid_val_compare(plist_t uidnode, uint64_t cmpval); + + /** + * Helper function to compare the value of a PLIST_REAL node against + * a given value. + * + * @note WARNING: Comparing floating point values can give inaccurate + * results because of the nature of floating point values on computer + * systems. While this function is designed to be as accurate as + * possible, please don't rely on it too much. + * + * @param realnode node of type PLIST_REAL + * @param cmpval value to compare against + * @return 0 if the node's value and cmpval are (almost) equal, + * 1 if the node's value is greater than cmpval, + * or -1 if the node's value is less than cmpval. + */ + PLIST_API int plist_real_val_compare(plist_t realnode, double cmpval); + + /** + * Helper function to compare the value of a PLIST_DATE node against + * a given number of seconds since epoch (UNIX timestamp). + * + * @param datenode node of type PLIST_DATE + * @param cmpval Number of seconds to compare against (UNIX timestamp) + * @return 0 if the node's date is equal to the supplied values, + * 1 if the node's date is greater than the supplied values, + * or -1 if the node's date is less than the supplied values. + */ + PLIST_API int plist_unix_date_val_compare(plist_t datenode, int64_t cmpval); + + /** + * Helper function to compare the value of a PLIST_STRING node against + * a given value. + * This function basically behaves like strcmp. + * + * @param strnode node of type PLIST_STRING + * @param cmpval value to compare against + * @return 0 if the node's value and cmpval are equal, + * > 0 if the node's value is lexicographically greater than cmpval, + * or < 0 if the node's value is lexicographically less than cmpval. + */ + PLIST_API int plist_string_val_compare(plist_t strnode, const char* cmpval); + + /** + * Helper function to compare the value of a PLIST_STRING node against + * a given value, while not comparing more than n characters. + * This function basically behaves like strncmp. + * + * @param strnode node of type PLIST_STRING + * @param cmpval value to compare against + * @param n maximum number of characters to compare + * @return 0 if the node's value and cmpval are equal, + * > 0 if the node's value is lexicographically greater than cmpval, + * or < 0 if the node's value is lexicographically less than cmpval. + */ + PLIST_API int plist_string_val_compare_with_size(plist_t strnode, const char* cmpval, size_t n); + + /** + * Helper function to match a given substring in the value of a + * PLIST_STRING node. + * + * @param strnode node of type PLIST_STRING + * @param substr value to match + * @return 1 if the node's value contains the given substring, + * or 0 if not. + */ + PLIST_API int plist_string_val_contains(plist_t strnode, const char* substr); + + /** + * Helper function to compare the value of a PLIST_KEY node against + * a given value. + * This function basically behaves like strcmp. + * + * @param keynode node of type PLIST_KEY + * @param cmpval value to compare against + * @return 0 if the node's value and cmpval are equal, + * > 0 if the node's value is lexicographically greater than cmpval, + * or < 0 if the node's value is lexicographically less than cmpval. + */ + PLIST_API int plist_key_val_compare(plist_t keynode, const char* cmpval); + + /** + * Helper function to compare the value of a PLIST_KEY node against + * a given value, while not comparing more than n characters. + * This function basically behaves like strncmp. + * + * @param keynode node of type PLIST_KEY + * @param cmpval value to compare against + * @param n maximum number of characters to compare + * @return 0 if the node's value and cmpval are equal, + * > 0 if the node's value is lexicographically greater than cmpval, + * or < 0 if the node's value is lexicographically less than cmpval. + */ + PLIST_API int plist_key_val_compare_with_size(plist_t keynode, const char* cmpval, size_t n); + + /** + * Helper function to match a given substring in the value of a + * PLIST_KEY node. + * + * @param keynode node of type PLIST_KEY + * @param substr value to match + * @return 1 if the node's value contains the given substring, + * or 0 if not. + */ + PLIST_API int plist_key_val_contains(plist_t keynode, const char* substr); + + /** + * Helper function to compare the data of a PLIST_DATA node against + * a given blob and size. + * This function basically behaves like memcmp after making sure the + * size of the node's data value is equal to the size of cmpval (n), + * making this a "full match" comparison. + * + * @param datanode node of type PLIST_DATA + * @param cmpval data blob to compare against + * @param n size of data blob passed in cmpval + * @return 0 if the node's data blob and cmpval are equal, + * > 0 if the node's value is lexicographically greater than cmpval, + * or < 0 if the node's value is lexicographically less than cmpval. + */ + PLIST_API int plist_data_val_compare(plist_t datanode, const uint8_t* cmpval, size_t n); + + /** + * Helper function to compare the data of a PLIST_DATA node against + * a given blob and size, while no more than n bytes are compared. + * This function basically behaves like memcmp after making sure the + * size of the node's data value is at least n, making this a + * "starts with" comparison. + * + * @param datanode node of type PLIST_DATA + * @param cmpval data blob to compare against + * @param n size of data blob passed in cmpval + * @return 0 if the node's value and cmpval are equal, + * > 0 if the node's value is lexicographically greater than cmpval, + * or < 0 if the node's value is lexicographically less than cmpval. + */ + PLIST_API int plist_data_val_compare_with_size(plist_t datanode, const uint8_t* cmpval, size_t n); + + /** + * Helper function to match a given data blob within the value of a + * PLIST_DATA node. + * + * @param datanode node of type PLIST_KEY + * @param cmpval data blob to match + * @param n size of data blob passed in cmpval + * @return 1 if the node's value contains the given data blob + * or 0 if not. + */ + PLIST_API int plist_data_val_contains(plist_t datanode, const uint8_t* cmpval, size_t n); + + /** + * Sort all PLIST_DICT key/value pairs in a property list lexicographically + * by key. Recurses into the child nodes if necessary. + * + * @param plist The property list to perform the sorting operation on. + */ + PLIST_API void plist_sort(plist_t plist); + + /** + * Free memory allocated by relevant libplist API calls: + * - plist_to_xml() + * - plist_to_bin() + * - plist_get_key_val() + * - plist_get_string_val() + * - plist_get_data_val() + * + * @param ptr pointer to the memory to free + * + * @note Do not use this function to free plist_t nodes, use plist_free() + * instead. + */ + PLIST_API void plist_mem_free(void* ptr); + + /** + * Set debug level for the format parsers. + * @note This function does nothing if libplist was not configured with --enable-debug . + * + * @param debug Debug level. Currently, only 0 (off) and 1 (enabled) are supported. + */ + PLIST_API void plist_set_debug(int debug); + + /** + * Returns a static string of the libplist version. + * + * @return The libplist version as static ascii string + */ + PLIST_API const char* libplist_version(); + + + /******************************************** + * * + * Deprecated API * + * * + ********************************************/ + + /** + * Create a new plist_t type #PLIST_DATE + * + * @deprecated Deprecated. Use plist_new_unix_date instead. + * + * @param sec the number of seconds since 01/01/2001 + * @param usec the number of microseconds + * @return the created item + * @sa #plist_type + */ + PLIST_WARN_DEPRECATED("use plist_new_unix_date instead") + PLIST_API plist_t plist_new_date(int32_t sec, int32_t usec); + + /** + * Get the value of a #PLIST_DATE node. + * This function does nothing if node is not of type #PLIST_DATE + * + * @deprecated Deprecated. Use plist_get_unix_date_val instead. + * + * @param node the node + * @param sec a pointer to an int32_t variable. Represents the number of seconds since 01/01/2001. + * @param usec a pointer to an int32_t variable. Represents the number of microseconds + */ + PLIST_WARN_DEPRECATED("use plist_get_unix_date_val instead") + PLIST_API void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec); + + /** + * Set the value of a node. + * Forces type of node to #PLIST_DATE + * + * @deprecated Deprecated. Use plist_set_unix_date_val instead. + * + * @param node the node + * @param sec the number of seconds since 01/01/2001 + * @param usec the number of microseconds + */ + PLIST_WARN_DEPRECATED("use plist_set_unix_date_val instead") + PLIST_API void plist_set_date_val(plist_t node, int32_t sec, int32_t usec); + + /** + * Helper function to compare the value of a PLIST_DATE node against + * a given set of seconds and fraction of a second since epoch. + * + * @deprecated Deprecated. Use plist_unix_date_val_compare instead. + * + * @param datenode node of type PLIST_DATE + * @param cmpsec number of seconds since epoch to compare against + * @param cmpusec fraction of a second in microseconds to compare against + * @return 0 if the node's date is equal to the supplied values, + * 1 if the node's date is greater than the supplied values, + * or -1 if the node's date is less than the supplied values. + */ + PLIST_WARN_DEPRECATED("use plist_unix_date_val_compare instead") + PLIST_API int plist_date_val_compare(plist_t datenode, int32_t cmpsec, int32_t cmpusec); + + /*@}*/ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/idevice/libidevice_ffi.a b/idevice/libidevice_ffi.a new file mode 100644 index 0000000000000000000000000000000000000000..58f0b92b11aac2ffdbc4c0df1bf61f7408c38385 GIT binary patch literal 97089368 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