mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-24 09:57:08 -06:00
Decode numeric character references in File Info XMP text
Found while testing crates/engine/src/file_cmds.rs:690 (xml_unescape), used by li_values, find_attr and read_file_info Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 5.5
parent
46e538b3a2
commit
afeea2f643
@@ -657,7 +657,42 @@ fn xml_escape(s: &str) -> String {
|
||||
}
|
||||
|
||||
fn xml_unescape(s: &str) -> String {
|
||||
s.replace("<", "<").replace(">", ">").replace(""", "\"").replace("'", "'").replace("&", "&")
|
||||
let mut out = String::with_capacity(s.len());
|
||||
let mut rest = s;
|
||||
while let Some(i) = rest.find('&') {
|
||||
out.push_str(&rest[..i]);
|
||||
rest = &rest[i..];
|
||||
let decoded = rest.find(';').filter(|&e| e <= 12).and_then(|e| {
|
||||
let c = match &rest[1..e] {
|
||||
"lt" => '<',
|
||||
"gt" => '>',
|
||||
"quot" => '"',
|
||||
"apos" => '\'',
|
||||
"amp" => '&',
|
||||
n => {
|
||||
let n = n.strip_prefix('#')?;
|
||||
let code = match n.strip_prefix(['x', 'X']) {
|
||||
Some(h) => u32::from_str_radix(h, 16).ok()?,
|
||||
None => n.parse().ok()?,
|
||||
};
|
||||
char::from_u32(code)?
|
||||
}
|
||||
};
|
||||
Some((c, e + 1))
|
||||
});
|
||||
match decoded {
|
||||
Some((c, len)) => {
|
||||
out.push(c);
|
||||
rest = &rest[len..];
|
||||
}
|
||||
None => {
|
||||
out.push('&');
|
||||
rest = &rest[1..];
|
||||
}
|
||||
}
|
||||
}
|
||||
out.push_str(rest);
|
||||
out
|
||||
}
|
||||
|
||||
/// The element `<tag …>…</tag>` (first occurrence) as (start, end, inner).
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
use photocraft_engine::file_cmds::read_file_info;
|
||||
|
||||
#[test]
|
||||
fn numeric_character_references_are_decoded() {
|
||||
let xmp = "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"><rdf:RDF><rdf:Description>\
|
||||
<dc:description><rdf:Alt><rdf:li xml:lang=\"x-default\">Line one
Line two © & co A &#38;</rdf:li></rdf:Alt></dc:description>\
|
||||
</rdf:Description></rdf:RDF></x:xmpmeta>";
|
||||
let info = read_file_info(Some(xmp));
|
||||
assert_eq!(info["description"], "Line one\nLine two © & co A &");
|
||||
}
|
||||
Reference in New Issue
Block a user