// Bounded UTF-8 and BOM-marked UTF-16 XML input. ZIP entry names stay UTF-8.
///|
fn ods_xml_decode(data : Bytes) -> String raise OdsError {
if data.length() > 4194304 {
raise Invalid("XML byte limit")
}
let little = data.length() >= 2 && data[0] == b'\xFF' && data[1] == b'\xFE'
let big = data.length() >= 2 && data[0] == b'\xFE' && data[1] == b'\xFF'
let encoding = if little {
"utf-16le"
} else if big {
"utf-16be"
} else {
"utf-8"
}
let text = if little || big {
if data.length() % 2 != 0 {
raise Invalid("odd UTF-16 byte count")
}
let b = StringBuilder()
b.write_char('\uFEFF')
let mut i = 2
while i < data.length() {
let first = if little {
data[i].to_int() | (data[i + 1].to_int() << 8)
} else {
(data[i].to_int() << 8) | data[i + 1].to_int()
}
i += 2
let scalar = if first >= 0xD800 && first <= 0xDBFF {
if i >= data.length() {
raise Invalid("truncated UTF-16 surrogate")
}
let second = if little {
data[i].to_int() | (data[i + 1].to_int() << 8)
} else {
(data[i].to_int() << 8) | data[i + 1].to_int()
}
if second < 0xDC00 || second > 0xDFFF {
raise Invalid("invalid UTF-16 surrogate pair")
}
i += 2
0x10000 + ((first - 0xD800) << 10) + second - 0xDC00
} else {
if first >= 0xDC00 && first <= 0xDFFF {
raise Invalid("unpaired UTF-16 low surrogate")
}
first
}
b.write_char(scalar.unsafe_to_char())
}
b.to_string()
} else {
ods_zip_utf8(data)
}
let chars : Array[Char] = []
for c in text {
chars.push(c)
}
let p : ReadXml = {
chars,
at: 0,
nodes: 0,
normalize_lines: true,
document_part: "",
location: "declaration",
events: [],
standalone: false,
dtd: None,
expansion: { units: 0, active: [], },
declared_types: Map([]),
other_ids: [],
}
if p.peek() == '\uFEFF' {
p.at += 1
}
p.declaration(encoding)
text
}