The two monolithic XSD content/identity rules only satisfied the OpenAPIKit validation idiom at the wrong granularity: no per-constraint removability, no isolable failing/near-miss tests. Split them into 32 named rules, each finding tagged at its origin and cached per XSDContext so the walk still runs once per document (the #101 decision against duplicating XSD's recursive type resolution still holds). Wired the streaming path's ID/IDREF and identity checks through the same framework instead of calling the validators imperatively, and added the unwrapAndLookup combinator the rule already named as required. Also includes the mandated repo-wide swiftformat/swiftlint pass.
59 lines
2.5 KiB
Swift
59 lines
2.5 KiB
Swift
extension PureXML.Parsing.ByteDecoder {
|
|
/// The Big5 decoder (the WHATWG `big5` algorithm): ASCII directly, and a lead
|
|
/// in `0x81`-`0xFE` followed by a trail in `0x40`-`0x7E` or `0xA1`-`0xFE`
|
|
/// resolved through the index. Four pointers decode to a base letter plus a
|
|
/// combining mark (a two-scalar sequence); the rest are single scalars,
|
|
/// including the astral HKSCS ideographs.
|
|
enum Big5 {
|
|
static func decode(_ bytes: ArraySlice<UInt8>) -> String {
|
|
var scalars = String.UnicodeScalarView()
|
|
var lead: UInt8 = 0
|
|
for byte in bytes {
|
|
if lead != 0 {
|
|
let saved = lead
|
|
lead = 0
|
|
if let sequence = mapping(lead: saved, trail: byte) {
|
|
scalars.append(contentsOf: sequence)
|
|
} else {
|
|
scalars.append("\u{FFFD}")
|
|
if byte <= 0x7F {
|
|
scalars.append(Unicode.Scalar(byte))
|
|
}
|
|
}
|
|
} else if byte <= 0x7F {
|
|
scalars.append(Unicode.Scalar(byte))
|
|
} else if (0x81 ... 0xFE).contains(byte) {
|
|
lead = byte
|
|
} else {
|
|
scalars.append("\u{FFFD}")
|
|
}
|
|
}
|
|
if lead != 0 {
|
|
scalars.append("\u{FFFD}")
|
|
}
|
|
return String(scalars)
|
|
}
|
|
|
|
/// The scalar sequence for a `(lead, trail)` pair through the Big5 index,
|
|
/// or nil for an invalid or unmapped pair. Most pairs map to one scalar;
|
|
/// four pointers map to a base letter plus a combining mark.
|
|
static func mapping(lead: UInt8, trail: UInt8) -> [Unicode.Scalar]? {
|
|
guard (0x40 ... 0x7E).contains(trail) || (0xA1 ... 0xFE).contains(trail) else { return nil }
|
|
let offset = trail < 0x7F ? 0x40 : 0x62
|
|
let pointer = (Int(lead) - 0x81) * 157 + Int(trail) - offset
|
|
switch pointer {
|
|
case 1133: return ["\u{00CA}", "\u{0304}"]
|
|
case 1135: return ["\u{00CA}", "\u{030C}"]
|
|
case 1164: return ["\u{00EA}", "\u{0304}"]
|
|
case 1166: return ["\u{00EA}", "\u{030C}"]
|
|
default: break
|
|
}
|
|
let index = pointer - big5Base
|
|
guard index >= 0, index < big5.count, big5[index] != 0,
|
|
let scalar = Unicode.Scalar(big5[index])
|
|
else { return nil }
|
|
return [scalar]
|
|
}
|
|
}
|
|
}
|