mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-04-05 13:09:06 +08:00
Run SwiftFormat on firmware patcher Remove legacy Python firmware patchers Fix compare pipeline pyimg4 PATH handling Restore Python patchers and prefer fresh restore Update BinaryBuffer.swift Avoid double scanning in patcher apply Prefer Python TXM site before fallback Retarget TXM trustcache finder for 26.1 Remove legacy Python firmware patchers Fail fast on nested virtualization hosts Return nonzero on fatal boot startup Add amfidont helper for signed boot binary Stage AMFI boot args for next host reboot Add host preflight for boot entitlements Fail fast when boot entitlements are unavailable Switch firmware patch targets to Swift CLI Record real Swift firmware parity results Verify Swift firmware pipeline end-to-end parity Fix Swift firmware pipeline JB dry-run
136 lines
4.6 KiB
Swift
136 lines
4.6 KiB
Swift
// BinaryBuffer.swift — Mutable binary data buffer with read/write helpers.
|
|
|
|
import Foundation
|
|
|
|
extension Data {
|
|
/// Load a little-endian integer without assuming the buffer is naturally aligned.
|
|
@inlinable
|
|
func loadLE<T: FixedWidthInteger>(_: T.Type, at offset: Int) -> T {
|
|
precondition(offset >= 0 && offset + MemoryLayout<T>.size <= count)
|
|
var value: T = .zero
|
|
_ = Swift.withUnsafeMutableBytes(of: &value) { dst in
|
|
copyBytes(to: dst, from: offset ..< offset + MemoryLayout<T>.size)
|
|
}
|
|
return T(littleEndian: value)
|
|
}
|
|
}
|
|
|
|
/// A mutable binary buffer for reading and patching firmware data.
|
|
public final class BinaryBuffer: @unchecked Sendable {
|
|
/// The mutable working data.
|
|
public var data: Data
|
|
|
|
/// The original immutable snapshot (for before/after comparison).
|
|
public let original: Data
|
|
|
|
public var count: Int {
|
|
data.count
|
|
}
|
|
|
|
public init(_ data: Data) {
|
|
// Rebase to startIndex 0 so zero-based subscripts are always valid.
|
|
let rebased = data.startIndex == 0 ? data : Data(data)
|
|
self.data = rebased
|
|
original = rebased
|
|
}
|
|
|
|
public convenience init(contentsOf url: URL) throws {
|
|
try self.init(Data(contentsOf: url))
|
|
}
|
|
|
|
// MARK: - Read Helpers
|
|
|
|
/// Read a little-endian UInt32 at the given byte offset.
|
|
@inlinable
|
|
public func readU32(at offset: Int) -> UInt32 {
|
|
data.loadLE(UInt32.self, at: offset)
|
|
}
|
|
|
|
/// Read a little-endian UInt64 at the given byte offset.
|
|
@inlinable
|
|
public func readU64(at offset: Int) -> UInt64 {
|
|
data.loadLE(UInt64.self, at: offset)
|
|
}
|
|
|
|
/// Read bytes at the given range.
|
|
public func readBytes(at offset: Int, count: Int) -> Data {
|
|
data[offset ..< offset + count]
|
|
}
|
|
|
|
// MARK: - Write Helpers
|
|
|
|
/// Write a little-endian UInt32 at the given byte offset.
|
|
@inlinable
|
|
public func writeU32(at offset: Int, value: UInt32) {
|
|
withUnsafeBytes(of: value.littleEndian) { src in
|
|
data.replaceSubrange(offset ..< offset + 4, with: src)
|
|
}
|
|
}
|
|
|
|
/// Write raw bytes at the given offset.
|
|
public func writeBytes(at offset: Int, bytes: Data) {
|
|
data.replaceSubrange(offset ..< offset + bytes.count, with: bytes)
|
|
}
|
|
|
|
// MARK: - Search Helpers
|
|
|
|
/// Find all occurrences of a byte pattern in the data.
|
|
public func findAll(_ pattern: Data, in range: Range<Int>? = nil) -> [Int] {
|
|
let searchRange = range ?? 0 ..< data.count
|
|
var results: [Int] = []
|
|
var offset = searchRange.lowerBound
|
|
while offset < searchRange.upperBound - pattern.count + 1 {
|
|
if let found = data.range(of: pattern, in: offset ..< searchRange.upperBound) {
|
|
results.append(found.lowerBound)
|
|
offset = found.lowerBound + 1
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
return results
|
|
}
|
|
|
|
/// Find a null-terminated C string at the given offset.
|
|
public func readCString(at offset: Int) -> String? {
|
|
data.withUnsafeBytes { buf in
|
|
guard offset < buf.count else { return nil }
|
|
let ptr = buf.baseAddress!.advanced(by: offset)
|
|
.assumingMemoryBound(to: CChar.self)
|
|
return String(cString: ptr)
|
|
}
|
|
}
|
|
|
|
/// Find the first occurrence of a C string in the data.
|
|
/// Matches Python `find_string()`: walks backward from the match to the
|
|
/// preceding NUL byte so that the returned offset is the C-string start.
|
|
public func findString(_ string: String, from: Int = 0) -> Int? {
|
|
guard let encoded = string.data(using: .utf8) else { return nil }
|
|
// Try with null terminator first (exact C-string match)
|
|
var pattern = encoded
|
|
pattern.append(0)
|
|
if let range = data.range(of: pattern, in: from ..< data.count) {
|
|
// Walk backward to the preceding NUL — that's the C string start
|
|
var cstr = range.lowerBound
|
|
while cstr > 0, data[cstr - 1] != 0 {
|
|
cstr -= 1
|
|
}
|
|
return cstr
|
|
}
|
|
// Try without null terminator (substring match)
|
|
if let range = data.range(of: encoded, in: from ..< data.count) {
|
|
var cstr = range.lowerBound
|
|
while cstr > 0, data[cstr - 1] != 0 {
|
|
cstr -= 1
|
|
}
|
|
return cstr
|
|
}
|
|
return nil
|
|
}
|
|
|
|
/// Find all occurrences of a C string in the data.
|
|
public func findAllStrings(_ string: String) -> [Int] {
|
|
guard let encoded = string.data(using: .utf8) else { return [] }
|
|
return findAll(encoded)
|
|
}
|
|
}
|