Files
vphone-cli/sources/FirmwarePatcher/Binary/BinaryBuffer.swift
Managed via Tart d042596cc0 Complete Swift firmware patcher parity and CLI wiring
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
2026-03-11 15:05:49 +08:00

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)
}
}