148 lines
6.0 KiB
Swift
148 lines
6.0 KiB
Swift
extension PureXML.Parsing.StreamingDecoder {
|
|
/// Streams one character from a multi-byte CJK encoding.
|
|
mutating func nextCJK(_ encoding: PureXML.Parsing.InputEncoding) -> Character? {
|
|
switch encoding {
|
|
case .shiftJIS: nextShiftJIS()
|
|
case .eucJP: nextEUCJP()
|
|
case .eucKR: nextEUCKR()
|
|
case .gbk: nextGBK()
|
|
case .gb18030: nextGB18030()
|
|
case .big5: nextBig5()
|
|
case .iso2022jp: nextISO2022JP()
|
|
case .eucTW: nextEUCTW()
|
|
default: nextUTF8()
|
|
}
|
|
}
|
|
|
|
/// Streams one GBK character: ASCII, `0x80` (euro), or a lead+trail.
|
|
private mutating func nextGBK() -> Character? {
|
|
guard let lead = nextByte() else {
|
|
finished = true
|
|
return nil
|
|
}
|
|
if lead <= 0x7F {
|
|
return Character(Unicode.Scalar(lead))
|
|
}
|
|
if lead == 0x80 {
|
|
return "\u{20AC}"
|
|
}
|
|
guard (0x81 ... 0xFE).contains(lead) else { return Self.replacement }
|
|
guard let trail = nextByte() else { finished = true
|
|
return Self.replacement
|
|
}
|
|
return PureXML.Parsing.ByteDecoder.GBK.twoByteScalar(lead: lead, trail: trail).map(Character.init) ?? Self.replacement
|
|
}
|
|
|
|
/// Streams one GB18030 character: ASCII, `0x80` (euro), a four-byte
|
|
/// sequence when the lead is followed by a digit, or a two-byte GBK pair.
|
|
private mutating func nextGB18030() -> Character? {
|
|
guard let lead = nextByte() else {
|
|
finished = true
|
|
return nil
|
|
}
|
|
if lead <= 0x7F {
|
|
return Character(Unicode.Scalar(lead))
|
|
}
|
|
if lead == 0x80 {
|
|
return "\u{20AC}"
|
|
}
|
|
guard (0x81 ... 0xFE).contains(lead) else { return Self.replacement }
|
|
guard let second = nextByte() else { finished = true
|
|
return Self.replacement
|
|
}
|
|
if (0x30 ... 0x39).contains(second) {
|
|
guard let third = nextByte(), let fourth = nextByte() else { finished = true
|
|
return Self.replacement
|
|
}
|
|
guard (0x81 ... 0xFE).contains(third), (0x30 ... 0x39).contains(fourth) else { return Self.replacement }
|
|
let pointer = PureXML.Parsing.ByteDecoder.GB18030.fourBytePointer(lead, second, third, fourth)
|
|
return PureXML.Parsing.ByteDecoder.GB18030.rangeScalar(pointer).map(Character.init) ?? Self.replacement
|
|
}
|
|
return PureXML.Parsing.ByteDecoder.GBK.twoByteScalar(lead: lead, trail: second).map(Character.init) ?? Self.replacement
|
|
}
|
|
|
|
/// Streams one Big5 character: ASCII, or a lead+trail through the index
|
|
/// (a two-scalar combining sequence stays one grapheme, one `Character`).
|
|
private mutating func nextBig5() -> Character? {
|
|
guard let lead = nextByte() else {
|
|
finished = true
|
|
return nil
|
|
}
|
|
if lead <= 0x7F {
|
|
return Character(Unicode.Scalar(lead))
|
|
}
|
|
guard (0x81 ... 0xFE).contains(lead) else { return Self.replacement }
|
|
guard let trail = nextByte() else { finished = true
|
|
return Self.replacement
|
|
}
|
|
guard let sequence = PureXML.Parsing.ByteDecoder.Big5.mapping(lead: lead, trail: trail) else {
|
|
return Self.replacement
|
|
}
|
|
return Character(String(String.UnicodeScalarView(sequence)))
|
|
}
|
|
|
|
/// Streams one EUC-KR character: ASCII, or a lead+trail through CP949.
|
|
private mutating func nextEUCKR() -> Character? {
|
|
guard let lead = nextByte() else {
|
|
finished = true
|
|
return nil
|
|
}
|
|
if lead <= 0x7F {
|
|
return Character(Unicode.Scalar(lead))
|
|
}
|
|
guard (0x81 ... 0xFE).contains(lead) else { return Self.replacement }
|
|
guard let trail = nextByte() else { finished = true
|
|
return Self.replacement
|
|
}
|
|
return PureXML.Parsing.ByteDecoder.EUCKR.twoByteScalar(lead: lead, trail: trail).map(Character.init) ?? Self.replacement
|
|
}
|
|
|
|
/// Streams one EUC-JP character: ASCII, `0x8E`+byte (half-width katakana),
|
|
/// `0x8F`+two bytes (JIS X 0212), or a lead+byte through JIS X 0208.
|
|
private mutating func nextEUCJP() -> Character? {
|
|
guard let lead = nextByte() else {
|
|
finished = true
|
|
return nil
|
|
}
|
|
if lead <= 0x7F {
|
|
return Character(Unicode.Scalar(lead))
|
|
}
|
|
if lead == 0x8E {
|
|
guard let byte = nextByte() else { finished = true
|
|
return Self.replacement
|
|
}
|
|
guard (0xA1 ... 0xDF).contains(byte) else { return Self.replacement }
|
|
return Character(Unicode.Scalar(0xFF61 + UInt32(byte) - 0xA1) ?? "\u{FFFD}")
|
|
}
|
|
if lead == 0x8F {
|
|
guard let mid = nextByte(), let trail = nextByte() else { finished = true
|
|
return Self.replacement
|
|
}
|
|
return PureXML.Parsing.ByteDecoder.EUCJP.twoByteScalar(lead: mid, trail: trail, useJis0212: true).map(Character.init) ?? Self.replacement
|
|
}
|
|
guard let trail = nextByte() else { finished = true
|
|
return Self.replacement
|
|
}
|
|
return PureXML.Parsing.ByteDecoder.EUCJP.twoByteScalar(lead: lead, trail: trail, useJis0212: false).map(Character.init) ?? Self.replacement
|
|
}
|
|
|
|
/// Streams one Shift-JIS character: a single byte (ASCII or half-width
|
|
/// katakana) or a lead+trail two-byte sequence resolved through JIS X 0208.
|
|
private mutating func nextShiftJIS() -> Character? {
|
|
guard let lead = nextByte() else {
|
|
finished = true
|
|
return nil
|
|
}
|
|
if let single = PureXML.Parsing.ByteDecoder.ShiftJIS.singleByteScalar(lead) {
|
|
return Character(single)
|
|
}
|
|
guard PureXML.Parsing.ByteDecoder.ShiftJIS.isLead(lead) else { return Self.replacement }
|
|
guard let trail = nextByte() else {
|
|
finished = true
|
|
return Self.replacement
|
|
}
|
|
guard let scalar = PureXML.Parsing.ByteDecoder.ShiftJIS.twoByteScalar(lead: lead, trail: trail) else { return Self.replacement }
|
|
return Character(scalar)
|
|
}
|
|
}
|