use crate::error::Result;
use quick_xml::events::{BytesStart, Event};
use std::collections::BTreeMap;
use std::io::Write;
pub struct Canonicalizer;
impl Canonicalizer {
pub fn canonicalize_subtree(input_xml: &str, target_tag: &str) -> Result<Vec<u8>> {
let mut reader = quick_xml::Reader::from_str(input_xml);
reader.config_mut().trim_text(true);
let mut writer = Vec::new();
let mut buf = Vec::new();
let mut capturing = false;
let mut depth = 0;
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => {
let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
if name == target_tag {
capturing = true;
depth = 1;
write_start_tag(&mut writer, e)?;
} else if capturing {
depth += 1;
write_start_tag(&mut writer, e)?;
}
}
Ok(Event::End(ref e)) => {
if capturing {
write!(writer, "</{}>", String::from_utf8_lossy(e.name().as_ref()))
.map_err(crate::error::Lib3mfError::Io)?;
depth -= 1;
if depth == 0 {
break; }
}
}
Ok(Event::Empty(ref e)) => {
let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
if name == target_tag {
write_start_tag(&mut writer, e)?;
write!(writer, "</{}>", name).map_err(crate::error::Lib3mfError::Io)?;
break;
} else if capturing {
write_start_tag(&mut writer, e)?;
write!(writer, "</{}>", name).map_err(crate::error::Lib3mfError::Io)?;
}
}
Ok(Event::Text(e)) => {
if capturing {
let content = String::from_utf8_lossy(&e.into_inner()).to_string();
writer
.write_all(content.as_bytes())
.map_err(crate::error::Lib3mfError::Io)?;
}
}
Ok(Event::Eof) => break,
Err(e) => return Err(crate::error::Lib3mfError::InvalidStructure(e.to_string())),
_ => {}
}
buf.clear();
}
if writer.is_empty() {
return Err(crate::error::Lib3mfError::Validation(format!(
"Tag <{}> not found for C14N",
target_tag
)));
}
Ok(writer)
}
pub fn canonicalize(input_xml: &str) -> Result<Vec<u8>> {
let mut reader = quick_xml::Reader::from_str(input_xml);
reader.config_mut().trim_text(true);
let mut writer = Vec::new();
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => {
write_start_tag(&mut writer, e)?;
}
Ok(Event::End(ref e)) => {
write!(writer, "</{}>", String::from_utf8_lossy(e.name().as_ref()))
.map_err(crate::error::Lib3mfError::Io)?;
}
Ok(Event::Empty(ref e)) => {
write_start_tag(&mut writer, e)?;
write!(writer, "</{}>", String::from_utf8_lossy(e.name().as_ref()))
.map_err(crate::error::Lib3mfError::Io)?;
}
Ok(Event::Text(e)) => {
let content = String::from_utf8_lossy(&e.into_inner()).to_string();
writer
.write_all(content.as_bytes())
.map_err(crate::error::Lib3mfError::Io)?;
}
Ok(Event::Eof) => break,
Err(e) => return Err(crate::error::Lib3mfError::InvalidStructure(e.to_string())),
_ => {} }
buf.clear();
}
Ok(writer)
}
}
fn write_start_tag(writer: &mut Vec<u8>, e: &BytesStart) -> Result<()> {
write!(writer, "<{}", String::from_utf8_lossy(e.name().as_ref()))
.map_err(crate::error::Lib3mfError::Io)?;
let mut attrs: BTreeMap<Vec<u8>, Vec<u8>> = BTreeMap::new();
for attr in e.attributes() {
let attr = attr.map_err(|e| crate::error::Lib3mfError::InvalidStructure(e.to_string()))?;
let val: &[u8] = attr.value.as_ref();
attrs.insert(attr.key.as_ref().to_vec(), val.to_vec());
}
for (key, value) in &attrs {
write!(
writer,
" {}=\"{}\"",
String::from_utf8_lossy(key),
String::from_utf8_lossy(value)
)
.map_err(crate::error::Lib3mfError::Io)?;
}
write!(writer, ">").map_err(crate::error::Lib3mfError::Io)?;
Ok(())
}