lib3mf_core/utils/
c14n.rs1use crate::error::Result;
2use quick_xml::events::{BytesStart, Event};
3use std::collections::BTreeMap;
4use std::io::Write;
5
6pub struct Canonicalizer;
16
17impl Canonicalizer {
18 pub fn canonicalize_subtree(input_xml: &str, target_tag: &str) -> Result<Vec<u8>> {
20 let mut reader = quick_xml::Reader::from_str(input_xml);
21 reader.config_mut().trim_text(true);
22 let mut writer = Vec::new();
23 let mut buf = Vec::new();
24 let mut capturing = false;
25 let mut depth = 0;
26
27 loop {
28 match reader.read_event_into(&mut buf) {
29 Ok(Event::Start(ref e)) => {
30 let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
31 if name == target_tag {
32 capturing = true;
33 depth = 1;
34 write_start_tag(&mut writer, e)?;
35 } else if capturing {
36 depth += 1;
37 write_start_tag(&mut writer, e)?;
38 }
39 }
40 Ok(Event::End(ref e)) => {
41 if capturing {
42 write!(writer, "</{}>", String::from_utf8_lossy(e.name().as_ref()))
43 .map_err(crate::error::Lib3mfError::Io)?;
44 depth -= 1;
45 if depth == 0 {
46 break; }
48 }
49 }
50 Ok(Event::Empty(ref e)) => {
51 let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
52 if name == target_tag {
53 write_start_tag(&mut writer, e)?;
55 write!(writer, "</{}>", name).map_err(crate::error::Lib3mfError::Io)?;
56 break;
57 } else if capturing {
58 write_start_tag(&mut writer, e)?;
59 write!(writer, "</{}>", name).map_err(crate::error::Lib3mfError::Io)?;
60 }
61 }
62 Ok(Event::Text(e)) => {
63 if capturing {
64 let content = String::from_utf8_lossy(&e.into_inner()).to_string();
65 writer
66 .write_all(content.as_bytes())
67 .map_err(crate::error::Lib3mfError::Io)?;
68 }
69 }
70 Ok(Event::Eof) => break,
71 Err(e) => return Err(crate::error::Lib3mfError::InvalidStructure(e.to_string())),
72 _ => {}
73 }
74 buf.clear();
75 }
76
77 if writer.is_empty() {
78 return Err(crate::error::Lib3mfError::Validation(format!(
79 "Tag <{}> not found for C14N",
80 target_tag
81 )));
82 }
83
84 Ok(writer)
85 }
86
87 pub fn canonicalize(input_xml: &str) -> Result<Vec<u8>> {
89 let mut reader = quick_xml::Reader::from_str(input_xml);
90 reader.config_mut().trim_text(true);
91 let mut writer = Vec::new();
92 let mut buf = Vec::new();
93
94 loop {
103 match reader.read_event_into(&mut buf) {
104 Ok(Event::Start(ref e)) => {
105 write_start_tag(&mut writer, e)?;
106 }
107 Ok(Event::End(ref e)) => {
108 write!(writer, "</{}>", String::from_utf8_lossy(e.name().as_ref()))
109 .map_err(crate::error::Lib3mfError::Io)?;
110 }
111 Ok(Event::Empty(ref e)) => {
112 write_start_tag(&mut writer, e)?;
114 write!(writer, "</{}>", String::from_utf8_lossy(e.name().as_ref()))
115 .map_err(crate::error::Lib3mfError::Io)?;
116 }
117 Ok(Event::Text(e)) => {
118 let content = String::from_utf8_lossy(&e.into_inner()).to_string();
120 writer
126 .write_all(content.as_bytes())
127 .map_err(crate::error::Lib3mfError::Io)?;
128 }
129 Ok(Event::Eof) => break,
130 Err(e) => return Err(crate::error::Lib3mfError::InvalidStructure(e.to_string())),
131 _ => {} }
133 buf.clear();
134 }
135
136 Ok(writer)
137 }
138}
139
140fn write_start_tag(writer: &mut Vec<u8>, e: &BytesStart) -> Result<()> {
141 write!(writer, "<{}", String::from_utf8_lossy(e.name().as_ref()))
142 .map_err(crate::error::Lib3mfError::Io)?;
143
144 let mut attrs: BTreeMap<Vec<u8>, Vec<u8>> = BTreeMap::new();
146 for attr in e.attributes() {
147 let attr = attr.map_err(|e| crate::error::Lib3mfError::InvalidStructure(e.to_string()))?;
148 let val: &[u8] = attr.value.as_ref();
149 attrs.insert(attr.key.as_ref().to_vec(), val.to_vec());
150 }
151
152 for (key, value) in &attrs {
153 write!(
154 writer,
155 " {}=\"{}\"",
156 String::from_utf8_lossy(key),
157 String::from_utf8_lossy(value)
158 )
159 .map_err(crate::error::Lib3mfError::Io)?;
160 }
161
162 write!(writer, ">").map_err(crate::error::Lib3mfError::Io)?;
163 Ok(())
164}