mirror of
https://github.com/morluto/rea
synced 2026-10-27 14:42:18 -04:00
4034883e98
Integrate the numeric precision correction from #1135 with complete supplemental metadata handling. Keep decoded numbers with an explicit limitation for mixed XML content or unclassified integer text, rather than assigning another literal's exact decimal. Project nonnumeric UID and CF$UID dictionary values recursively while preserving numeric references, graph identity and original byte digests. Add filesystem, built CLI and MCP regressions for the review findings, adjacent XML representations and numeric reference controls. Retain the original native Foundation qualification fixtures and verifier. Verification: 84 focused tests; npm run check; npm run docs:check; npm run verify:test-discovery; npm run verify:keyed-archive (real Foundation, CLI and stdio MCP). No real Hopper or Ghidra verification was needed or run. Co-authored-by: Rudy Mizrahi Celekli <47457359+rudycelekli@users.noreply.github.com> Signed-off-by: morluto <76467478+morluto@users.noreply.github.com>
135 lines
6.0 KiB
Swift
135 lines
6.0 KiB
Swift
import Foundation
|
|
import CryptoKit
|
|
|
|
// Foundation writes the archive. XMLParser only observes inert plist element types.
|
|
final class PlistElements: NSObject, XMLParserDelegate {
|
|
struct Frame {
|
|
let kind: String
|
|
var values: [Any] = []
|
|
var fields: [String: Any] = [:]
|
|
var key: String?
|
|
var text = ""
|
|
}
|
|
var frames: [Frame] = []
|
|
var value: Any?
|
|
func parser(_ parser: XMLParser, didStartElement name: String, namespaceURI: String?, qualifiedName: String?, attributes: [String: String]) {
|
|
frames.append(Frame(kind: name))
|
|
}
|
|
func parser(_ parser: XMLParser, foundCharacters text: String) {
|
|
if !frames.isEmpty { frames[frames.count - 1].text += text }
|
|
}
|
|
func parser(_ parser: XMLParser, didEndElement name: String, namespaceURI: String?, qualifiedName: String?) {
|
|
let frame = frames.removeLast()
|
|
if name == "key" {
|
|
frames[frames.count - 1].key = frame.text
|
|
return
|
|
}
|
|
let item: Any
|
|
switch name {
|
|
case "dict": item = frame.fields
|
|
case "array": item = frame.values
|
|
case "integer", "real":
|
|
item = ["numberKind": name, "literal": frame.text.trimmingCharacters(in: .whitespacesAndNewlines)]
|
|
case "string": item = frame.text
|
|
case "true": item = true
|
|
case "false": item = false
|
|
case "plist": value = frame.values.first; return
|
|
default: parser.abortParsing(); return
|
|
}
|
|
if frames.last?.kind == "dict" {
|
|
guard let key = frames.last?.key else { parser.abortParsing(); return }
|
|
frames[frames.count - 1].fields[key] = item
|
|
frames[frames.count - 1].key = nil
|
|
} else if !frames.isEmpty {
|
|
frames[frames.count - 1].values.append(item)
|
|
}
|
|
}
|
|
}
|
|
func elements(_ bytes: Data) throws -> [String: Any] {
|
|
let delegate = PlistElements()
|
|
let parser = XMLParser(data: bytes)
|
|
parser.shouldResolveExternalEntities = false
|
|
parser.delegate = delegate
|
|
guard parser.parse(), let value = delegate.value as? [String: Any] else {
|
|
throw NSError(domain: "REA.IntegerOracle", code: 1)
|
|
}
|
|
return value
|
|
}
|
|
func rows(_ value: Any, path: [Any] = []) -> [[String: Any]] {
|
|
if let fields = value as? [String: Any] {
|
|
// Reference markers identify objects; their UID is not an archived numeric value.
|
|
if fields.count == 1 && fields["CF$UID"] != nil { return [] }
|
|
if let kind = fields["numberKind"] as? String, let literal = fields["literal"] as? String {
|
|
return [["path": path, "kind": kind, "literal": literal]]
|
|
}
|
|
return fields.keys.sorted().flatMap { rows(fields[$0]!, path: path + [$0]) }
|
|
}
|
|
if let values = value as? [Any] {
|
|
return values.enumerated().flatMap { rows($0.element, path: path + [$0.offset]) }
|
|
}
|
|
return []
|
|
}
|
|
func literal(_ value: Any?, kind: String) throws -> String {
|
|
guard let fields = value as? [String: String], fields["numberKind"] == kind, let text = fields["literal"] else {
|
|
throw NSError(domain: "REA.IntegerOracle", code: 2)
|
|
}
|
|
return text
|
|
}
|
|
let output = URL(fileURLWithPath: CommandLine.arguments[1])
|
|
let positive: Int64 = 9_007_199_254_740_993
|
|
let negative: Int64 = Int64.min
|
|
let unsigned: UInt64 = 9_007_199_254_740_993
|
|
let real: Double = 9_007_199_254_740_992
|
|
var archives: [String: Any] = [:]
|
|
for format in ["xml", "binary"] {
|
|
let archiver = NSKeyedArchiver(requiringSecureCoding: false)
|
|
archiver.outputFormat = format == "xml" ? .xml : .binary
|
|
archiver.encode(positive, forKey: "unsafeSigned")
|
|
archiver.encode(negative, forKey: "unsafeNegative")
|
|
archiver.encode(Int64(9_007_199_254_740_991), forKey: "safeInteger")
|
|
archiver.encode(Int64(-42), forKey: "safeNegative")
|
|
archiver.encode(real, forKey: "integralReal")
|
|
archiver.encode(NSNumber(value: unsigned), forKey: "boxedUnsigned")
|
|
archiver.encode(NSNumber(value: real), forKey: "boxedReal")
|
|
archiver.finishEncoding()
|
|
let bytes = archiver.encodedData
|
|
let native = try PropertyListSerialization.propertyList(from: bytes, options: [], format: nil)
|
|
let xml = try PropertyListSerialization.data(fromPropertyList: native, format: .xml, options: 0)
|
|
let parsed = try elements(xml)
|
|
guard let top = parsed["$top"] as? [String: Any], let table = parsed["$objects"] as? [Any] else {
|
|
throw NSError(domain: "REA.IntegerOracle", code: 3)
|
|
}
|
|
guard try literal(top["unsafeSigned"], kind: "integer") == String(positive),
|
|
try literal(top["unsafeNegative"], kind: "integer") == String(negative),
|
|
try literal(top["safeInteger"], kind: "integer") == "9007199254740991",
|
|
try literal(top["safeNegative"], kind: "integer") == "-42",
|
|
Double(try literal(top["integralReal"], kind: "real")) == real else {
|
|
throw NSError(domain: "REA.IntegerOracle", code: 4)
|
|
}
|
|
var selectedRows: [[String: Any]] = []
|
|
for key in ["unsafeSigned", "unsafeNegative", "safeInteger", "safeNegative", "integralReal"] {
|
|
for row in rows(top[key]!) {
|
|
selectedRows.append(row.merging(["container": "roots", "path": [key], "root": key]) { _, rhs in rhs })
|
|
}
|
|
}
|
|
for key in ["boxedUnsigned", "boxedReal"] {
|
|
guard let reference = top[key] as? [String: Any],
|
|
let uid = Int(try literal(reference["CF$UID"], kind: "integer")), uid > 0, uid < table.count else {
|
|
throw NSError(domain: "REA.IntegerOracle", code: 5)
|
|
}
|
|
let numericRows = rows(table[uid])
|
|
let expectedKind = key == "boxedUnsigned" ? "integer" : "real"
|
|
guard numericRows.contains(where: { row in
|
|
guard row["kind"] as? String == expectedKind, let text = row["literal"] as? String else { return false }
|
|
return key == "boxedUnsigned" ? text == String(unsigned) : Double(text) == real
|
|
}) else { throw NSError(domain: "REA.IntegerOracle", code: 6) }
|
|
for row in numericRows {
|
|
selectedRows.append(row.merging(["container": "objects", "objectId": uid, "root": key]) { _, rhs in rhs })
|
|
}
|
|
}
|
|
let filename = "numbers.\(format).plist"
|
|
try bytes.write(to: output.appendingPathComponent(filename))
|
|
archives[format] = ["filename": filename, "sha256": SHA256.hash(data: bytes).map { String(format: "%02x", $0) }.joined(), "rows": selectedRows]
|
|
}
|
|
try JSONSerialization.data(withJSONObject: archives, options: [.sortedKeys]).write(to: output.appendingPathComponent("oracle.json"))
|