167 lines
6.2 KiB
Swift
167 lines
6.2 KiB
Swift
extension PureXML.Parsing.ByteDecoder {
|
||
/// To-Unicode mappings for the single-byte legacy encodings. Each maps one
|
||
/// byte to its Unicode scalar; bytes `0x00`-`0x7F` are ASCII in every case.
|
||
/// A few encodings are expressed exactly (ISO-8859-1 with substitutions, or a
|
||
/// contiguous block); the rest are vendored verbatim from the authoritative
|
||
/// `unicode.org` mapping files (see `SingleByteTables.swift`).
|
||
enum SingleByte {
|
||
/// ISO-8859-15 (Latin-9): ISO-8859-1 with the euro sign and seven other
|
||
/// substitutions.
|
||
static func iso8859_15(_ byte: UInt8) -> Unicode.Scalar {
|
||
switch byte {
|
||
case 0xA4: "\u{20AC}" // €
|
||
case 0xA6: "\u{0160}" // Š
|
||
case 0xA8: "\u{0161}" // š
|
||
case 0xB4: "\u{017D}" // Ž
|
||
case 0xB8: "\u{017E}" // ž
|
||
case 0xBC: "\u{0152}" // Œ
|
||
case 0xBD: "\u{0153}" // œ
|
||
case 0xBE: "\u{0178}" // Ÿ
|
||
default: Unicode.Scalar(byte)
|
||
}
|
||
}
|
||
|
||
/// ISO-8859-9 (Latin-5, Turkish): ISO-8859-1 with six Turkish letters
|
||
/// replacing the Icelandic ones.
|
||
static func iso8859_9(_ byte: UInt8) -> Unicode.Scalar {
|
||
switch byte {
|
||
case 0xD0: "\u{011E}" // Ğ
|
||
case 0xDD: "\u{0130}" // İ
|
||
case 0xDE: "\u{015E}" // Ş
|
||
case 0xF0: "\u{011F}" // ğ
|
||
case 0xFD: "\u{0131}" // ı
|
||
case 0xFE: "\u{015F}" // ş
|
||
default: Unicode.Scalar(byte)
|
||
}
|
||
}
|
||
|
||
/// Windows-1254 (Turkish): Windows-1252 with the same six Turkish letters
|
||
/// as ISO-8859-9 (the only differences fall in the Latin-1 upper half).
|
||
static func windows1254(_ byte: UInt8) -> Unicode.Scalar {
|
||
switch byte {
|
||
case 0xD0: "\u{011E}" // Ğ
|
||
case 0xDD: "\u{0130}" // İ
|
||
case 0xDE: "\u{015E}" // Ş
|
||
case 0xF0: "\u{011F}" // ğ
|
||
case 0xFD: "\u{0131}" // ı
|
||
case 0xFE: "\u{015F}" // ş
|
||
default: PureXML.Parsing.ByteDecoder.windows1252Scalar(byte)
|
||
}
|
||
}
|
||
|
||
/// ISO-8859-5 (Latin/Cyrillic): the Cyrillic alphabet laid out as a
|
||
/// contiguous block from `0xB0`, with a handful of named exceptions.
|
||
static func iso8859_5(_ byte: UInt8) -> Unicode.Scalar {
|
||
switch byte {
|
||
case 0xA1 ... 0xAC: scalar(0x0401 + UInt32(byte) - 0xA1) // Ё..Ќ
|
||
case 0xAE ... 0xAF: scalar(0x040E + UInt32(byte) - 0xAE) // Ў Џ
|
||
case 0xB0 ... 0xEF: scalar(0x0410 + UInt32(byte) - 0xB0) // А..я
|
||
case 0xF0: "\u{2116}" // №
|
||
case 0xF1 ... 0xFC: scalar(0x0451 + UInt32(byte) - 0xF1) // ё..ќ
|
||
case 0xFD: "\u{00A7}" // §
|
||
case 0xFE ... 0xFF: scalar(0x045E + UInt32(byte) - 0xFE) // ў џ
|
||
default: Unicode.Scalar(byte) // ASCII, C1, NBSP (0xA0), SHY (0xAD)
|
||
}
|
||
}
|
||
|
||
/// The table-driven encodings, vendored from the Unicode mapping files.
|
||
static func iso8859_2(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, latin2Upper)
|
||
}
|
||
|
||
static func iso8859_3(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, latin3Upper)
|
||
}
|
||
|
||
static func iso8859_4(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, latin4Upper)
|
||
}
|
||
|
||
static func iso8859_7(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, greekUpper)
|
||
}
|
||
|
||
static func iso8859_13(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, latin7Upper)
|
||
}
|
||
|
||
static func iso8859_6(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, arabicUpper)
|
||
}
|
||
|
||
static func iso8859_8(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, hebrewUpper)
|
||
}
|
||
|
||
static func iso8859_10(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, latin6Upper)
|
||
}
|
||
|
||
static func iso8859_14(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, latin8Upper)
|
||
}
|
||
|
||
static func iso8859_16(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, latin10Upper)
|
||
}
|
||
|
||
static func iso8859_11(_ byte: UInt8) -> Unicode.Scalar {
|
||
upperHalf(byte, thaiUpper)
|
||
}
|
||
|
||
static func windows1250(_ byte: UInt8) -> Unicode.Scalar {
|
||
fullHigh(byte, windows1250High)
|
||
}
|
||
|
||
static func windows1251(_ byte: UInt8) -> Unicode.Scalar {
|
||
fullHigh(byte, windows1251High)
|
||
}
|
||
|
||
static func windows1253(_ byte: UInt8) -> Unicode.Scalar {
|
||
fullHigh(byte, windows1253High)
|
||
}
|
||
|
||
static func windows1257(_ byte: UInt8) -> Unicode.Scalar {
|
||
fullHigh(byte, windows1257High)
|
||
}
|
||
|
||
static func koi8r(_ byte: UInt8) -> Unicode.Scalar {
|
||
fullHigh(byte, koi8rHigh)
|
||
}
|
||
|
||
static func windows1255(_ byte: UInt8) -> Unicode.Scalar {
|
||
fullHigh(byte, windows1255High)
|
||
}
|
||
|
||
static func windows1256(_ byte: UInt8) -> Unicode.Scalar {
|
||
fullHigh(byte, windows1256High)
|
||
}
|
||
|
||
static func windows1258(_ byte: UInt8) -> Unicode.Scalar {
|
||
fullHigh(byte, windows1258High)
|
||
}
|
||
|
||
static func koi8u(_ byte: UInt8) -> Unicode.Scalar {
|
||
fullHigh(byte, koi8uHigh)
|
||
}
|
||
|
||
/// Maps a byte through a 96-entry upper-half table (`0xA0`-`0xFF`); bytes
|
||
/// below `0xA0` are ASCII or C1 controls (identity). Used by the encodings
|
||
/// whose upper half is vendored from the Unicode mapping files.
|
||
static func upperHalf(_ byte: UInt8, _ table: [UInt16]) -> Unicode.Scalar {
|
||
byte >= 0xA0 ? scalar(UInt32(table[Int(byte) - 0xA0])) : Unicode.Scalar(byte)
|
||
}
|
||
|
||
/// Maps a byte through a 128-entry high-half table (`0x80`-`0xFF`); bytes
|
||
/// below `0x80` are ASCII. Used by the Windows code pages and KOI8, which
|
||
/// remap the `0x80`-`0x9F` range too.
|
||
static func fullHigh(_ byte: UInt8, _ table: [UInt16]) -> Unicode.Scalar {
|
||
byte >= 0x80 ? scalar(UInt32(table[Int(byte) - 0x80])) : Unicode.Scalar(byte)
|
||
}
|
||
|
||
static func scalar(_ value: UInt32) -> Unicode.Scalar {
|
||
Unicode.Scalar(value) ?? "\u{FFFD}"
|
||
}
|
||
}
|
||
}
|