mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-28 20:37:10 -06:00
DOCX strict parse: reject an undefined entity and markup after the root
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
2fcb589b72
commit
457f7069fd
@@ -395,7 +395,7 @@ mod tests {
|
||||
// A hyperlink whose relationship id is written without the prefix: the reader resolves
|
||||
// it (the alias `El::attr` accepts), so the part it names is not carried over twice.
|
||||
let named = package(
|
||||
r#"<w:p><w:r><w:hyperlink id="rIdDoc1"><w:r><w:t>link</w:t></w:r></w:hyperlink></w:r></w:p>"#,
|
||||
r#"<w:p><w:hyperlink id="rIdDoc1"><w:r><w:t>link</w:t></w:r></w:hyperlink></w:p>"#,
|
||||
&[("rIdDoc1", "keep.bin")],
|
||||
&[("word/keep.bin", b"kept")],
|
||||
);
|
||||
|
||||
+24
-3
@@ -346,6 +346,9 @@ fn parse_with(bytes: &[u8], extra: &[(&'static str, &str)], strict: bool) -> Res
|
||||
};
|
||||
match ev {
|
||||
Event::Start(ref e) | Event::Empty(ref e) => {
|
||||
if strict && root.is_some() && stack.is_empty() {
|
||||
return Err(DocxError::Xml("more than one root element".into()));
|
||||
}
|
||||
count += 1;
|
||||
if count > MAX_ELEMENTS {
|
||||
return Err(DocxError::Limit("too many XML elements".into()));
|
||||
@@ -433,15 +436,17 @@ fn parse_with(bytes: &[u8], extra: &[(&'static str, &str)], strict: bool) -> Res
|
||||
}
|
||||
Err(_) => None,
|
||||
};
|
||||
if let Some(c) = ch {
|
||||
push_text(top, &c);
|
||||
match ch {
|
||||
Some(c) => push_text(top, &c),
|
||||
None if strict => return Err(DocxError::Xml("an entity is not defined".into())),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::Eof => break,
|
||||
_ => {}
|
||||
}
|
||||
if root.is_some() && stack.is_empty() {
|
||||
if !strict && root.is_some() && stack.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -567,6 +572,22 @@ pub fn body_ns() -> Vec<(String, String)> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn strict_parsing_rejects_a_dropped_entity_and_trailing_markup() {
|
||||
let bad = [&b"<w:t>before &unknown; after</w:t>"[..], b"<a></a><b></b>", b"<a></a><b>"];
|
||||
for xml in bad {
|
||||
assert!(parse_strict(xml).is_err(), "{}", String::from_utf8_lossy(xml));
|
||||
}
|
||||
assert!(
|
||||
parse_strict(
|
||||
b"<a>x & y</a>
|
||||
"
|
||||
)
|
||||
.is_ok()
|
||||
);
|
||||
assert!(parse(b"<a></a><b></b>").is_ok(), "lenient parsing still stops at the root");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_relationship_attribute_is_the_namespaced_one_or_the_alias_of_one() {
|
||||
// The relationship namespace, and VML's `o:relid`.
|
||||
|
||||
Reference in New Issue
Block a user