Skip to content

Commit

Permalink
fix: Switch to from fast_xml to quick_xml (#805)
Browse files Browse the repository at this point in the history
* fix: Switch to from fast_xml to quick_xml
  • Loading branch information
cdmurph32 authored Jan 8, 2025
1 parent 8767514 commit acd429a
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 85 deletions.
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ conv = "0.3.3"
coset = "0.3.1"
extfmt = "0.1.1"
ed25519-dalek = "2.1.1"
fast-xml = "0.23.1"
quick-xml = "0.37.1"
hex = "0.4.3"
# Version 1.13.0 doesn't compile under Rust < 1.75, pinning to 1.12.0
id3 = "=1.14.0"
Expand Down
100 changes: 53 additions & 47 deletions sdk/src/asset_handlers/svg_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
// each license.

use std::{
borrow::Cow,
fs::{self, File, OpenOptions},
io::{BufReader, Cursor, Seek, SeekFrom, Write},
path::Path,
};

use c2pa_crypto::base64;
use conv::ValueFrom;
use fast_xml::{
use quick_xml::{
events::{BytesText, Event},
Reader, Writer,
};
Expand Down Expand Up @@ -169,8 +170,8 @@ impl AssetIO for SvgIO {
}

// create manifest entry
fn create_manifest_tag(data: &[u8], with_meta: bool) -> Result<Vec<u8>> {
let mut output: Vec<u8> = Vec::with_capacity(data.len() + 256);
fn create_manifest_tag(data: &[u8], with_meta: bool) -> Result<Event> {
let output: Vec<u8> = Vec::with_capacity(data.len() + 256);
let mut writer = Writer::new(Cursor::new(output));

let encoded = base64::encode(data);
Expand All @@ -182,21 +183,23 @@ fn create_manifest_tag(data: &[u8], with_meta: bool) -> Result<Vec<u8>> {
writer
.create_element(MANIFEST)
.with_attribute((MANIFEST_NS, MANIFEST_NS_VAL))
.write_text_content(BytesText::from_plain_str(&encoded))?;
.write_text_content(BytesText::from_escaped(&encoded))?;
Ok(())
})
.map_err(|_e| Error::XmlWriteError)?;
} else {
writer
.create_element(MANIFEST)
.with_attribute((MANIFEST_NS, MANIFEST_NS_VAL))
.write_text_content(BytesText::from_plain_str(&encoded))
.write_text_content(BytesText::from_escaped(&encoded))
.map_err(|_e| Error::XmlWriteError)?;
}

output = writer.into_inner().into_inner();
let output = writer.into_inner().into_inner();
let output_str = String::from_utf8(output).map_err(|_e| Error::XmlWriteError)?;
let event = Event::Text(BytesText::from_escaped(Cow::Owned(output_str)));

Ok(output)
Ok(event)
}

enum DetectedTagsDepth {
Expand All @@ -221,9 +224,9 @@ fn detect_manifest_location(
let mut output: Option<Vec<u8>> = None;

loop {
match xml_reader.read_event(&mut buf) {
match xml_reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => {
let name = String::from_utf8_lossy(e.name()).into_owned();
let name = String::from_utf8_lossy(e.name().into_inner()).into_owned();
xml_path.push(name);

if xml_path.len() == 2 && xml_path[0] == SVG && xml_path[1] == METADATA {
Expand All @@ -238,41 +241,48 @@ fn detect_manifest_location(
{
detected_level = DetectedTagsDepth::Manifest;
insertion_point = xml_reader.buffer_position();

let mut temp_buf = Vec::new();
let s = xml_reader
.read_text(e.name(), &mut temp_buf)
.map_err(|_e| {
Error::InvalidAsset("XML manifest tag invalid content".to_string())
})?;

output = Some(base64::decode(&s).map_err(|_e| {
dbg!(_e);
Error::InvalidAsset("XML bad base64 encoding".to_string())
})?);
}

if xml_path.len() == 1 && xml_path[0] == SVG {
detected_level = DetectedTagsDepth::Empty;
insertion_point = xml_reader.buffer_position();
}
}
Ok(Event::Text(e)) => {
if xml_path.len() == 3
&& xml_path[0] == SVG
&& xml_path[1] == METADATA
&& xml_path[2] == MANIFEST
{
let encoded_content = e
.unescape()
.map_err(|_e| {
Error::InvalidAsset("XML incorrectly escaped character".to_string())
})?
.into_owned();
output = Some(base64::decode(&encoded_content).map_err(|_e| {
Error::InvalidAsset("XML bad base64 encoding".to_string())
})?);
}
}
Ok(Event::End(_)) => {
let _p = xml_path.pop();
}
Ok(Event::Eof) => break,
Err(_) => return Err(Error::InvalidAsset("XML invalid".to_string())),
_ => (),
}
buf.clear();
}
let insertion_point = usize::try_from(insertion_point)?;

Ok((output, detected_level, insertion_point))
}

fn read_xmp(input_stream: &mut dyn CAIRead) -> Result<(Option<String>, DetectedTagsDepth, usize)> {
input_stream.rewind()?;

let mut insertion_point = usize::try_from(stream_len(input_stream)?)?;
let mut insertion_point = stream_len(input_stream)?;
let mut buf = Vec::new();
let buf_reader = BufReader::new(input_stream);
let mut xml_reader = Reader::from_reader(buf_reader);
Expand All @@ -281,9 +291,9 @@ fn read_xmp(input_stream: &mut dyn CAIRead) -> Result<(Option<String>, DetectedT
let mut output = None;

loop {
match xml_reader.read_event(&mut buf) {
match xml_reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => {
let name: String = String::from_utf8_lossy(e.name()).into_owned();
let name: String = String::from_utf8_lossy(e.name().into_inner()).into_owned();
xml_path.push(name);

if xml_path.len() == 1 && xml_path[0] == SVG {
Expand All @@ -298,9 +308,7 @@ fn read_xmp(input_stream: &mut dyn CAIRead) -> Result<(Option<String>, DetectedT
}
Ok(Event::PI(e)) => {
let possible_insertion_point = xml_reader.buffer_position();
let pi = e.unescape_and_decode(&xml_reader).map_err(|_e| {
Error::InvalidAsset("XML bad processing instructions".to_string())
})?;
let pi = String::from_utf8_lossy(&e);

if pi.contains(XPACKET) && pi.contains(XMP_ID) {
// reconstruct opening XMP PI tag
Expand All @@ -309,7 +317,7 @@ fn read_xmp(input_stream: &mut dyn CAIRead) -> Result<(Option<String>, DetectedT
detected_level = DetectedTagsDepth::Xmp;
// adjust to include the opening XMP PI
insertion_point = possible_insertion_point
.checked_sub(tag.len())
.checked_sub(tag.len() as u64)
.ok_or(Error::BadParam("file read out of range".into()))?;
} else if pi.contains(XPACKET) {
// this has read to the end of xpacket
Expand Down Expand Up @@ -337,7 +345,9 @@ fn read_xmp(input_stream: &mut dyn CAIRead) -> Result<(Option<String>, DetectedT
Err(_) => return Err(Error::InvalidAsset("XML invalid".to_string())),
_ => (),
}
buf.clear();
}
let insertion_point = usize::try_from(insertion_point)?;

Ok((output, detected_level, insertion_point))
}
Expand Down Expand Up @@ -397,12 +407,10 @@ impl CAIWriter for SvgIO {
match detected_tag_location {
DetectedTagsDepth::Metadata => {
// add manifest case
let manifest_data = create_manifest_tag(store_bytes, false)?;

loop {
match reader.read_event(&mut buf) {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => {
let name = String::from_utf8_lossy(e.name()).into_owned();
let name = String::from_utf8_lossy(e.name().into_inner()).into_owned();
xml_path.push(name);

// writes the event to the writer
Expand All @@ -414,7 +422,7 @@ impl CAIWriter for SvgIO {
if xml_path.len() == 2 && xml_path[0] == SVG && xml_path[1] == METADATA
{
writer
.write(&manifest_data)
.write_event(create_manifest_tag(store_bytes, false)?)
.map_err(|_e| Error::XmlWriteError)?;
}
}
Expand All @@ -425,7 +433,7 @@ impl CAIWriter for SvgIO {
.write_event(Event::End(e))
.map_err(|_e| Error::XmlWriteError)?;
}
Ok(e) => writer.write_event(&e).map_err(|_e| Error::XmlWriteError)?,
Ok(e) => writer.write_event(e).map_err(|_e| Error::XmlWriteError)?,
Err(_e) => return Err(Error::InvalidAsset("XML invalid".to_string())),
}
buf.clear();
Expand All @@ -436,9 +444,9 @@ impl CAIWriter for SvgIO {
let encoded = base64::encode(store_bytes);

loop {
match reader.read_event(&mut buf) {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => {
let name = String::from_utf8_lossy(e.name()).into_owned();
let name = String::from_utf8_lossy(e.name().into_inner()).into_owned();
xml_path.push(name);

// writes the event to the writer
Expand All @@ -454,7 +462,7 @@ impl CAIWriter for SvgIO {
&& xml_path[2] == MANIFEST
{
writer
.write(encoded.as_bytes())
.write_event(Event::Text(BytesText::new(&encoded)))
.map_err(|_e| Error::XmlWriteError)?;
} else {
writer
Expand All @@ -469,20 +477,18 @@ impl CAIWriter for SvgIO {
.write_event(Event::End(e))
.map_err(|_e| Error::XmlWriteError)?;
}
Ok(e) => writer.write_event(&e).map_err(|_e| Error::XmlWriteError)?,
Ok(e) => writer.write_event(e).map_err(|_e| Error::XmlWriteError)?,
Err(_e) => return Err(Error::InvalidAsset("XML invalid".to_string())),
}
buf.clear();
}
}
_ => {
//add metadata & manifest case
let manifest_data = create_manifest_tag(store_bytes, true)?;

loop {
match reader.read_event(&mut buf) {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => {
let name = String::from_utf8_lossy(e.name()).into_owned();
let name = String::from_utf8_lossy(e.name().into_inner()).into_owned();
xml_path.push(name);

// writes the event to the writer
Expand All @@ -493,7 +499,7 @@ impl CAIWriter for SvgIO {
// add manifest data
if xml_path.len() == 1 && xml_path[0] == SVG {
writer
.write(&manifest_data)
.write_event(create_manifest_tag(store_bytes, true)?)
.map_err(|_e| Error::XmlWriteError)?;
}
}
Expand All @@ -504,7 +510,7 @@ impl CAIWriter for SvgIO {
.write_event(Event::End(e))
.map_err(|_e| Error::XmlWriteError)?;
}
Ok(e) => writer.write_event(&e).map_err(|_e| Error::XmlWriteError)?,
Ok(e) => writer.write_event(e).map_err(|_e| Error::XmlWriteError)?,
Err(_e) => return Err(Error::InvalidAsset("XML invalid".to_string())),
}
buf.clear();
Expand Down Expand Up @@ -574,9 +580,9 @@ impl CAIWriter for SvgIO {
let mut xml_path: Vec<String> = Vec::new();

loop {
match reader.read_event(&mut buf) {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => {
let name = String::from_utf8_lossy(e.name()).into_owned();
let name = String::from_utf8_lossy(e.name().into_inner()).into_owned();
xml_path.push(name);

if xml_path.len() == 3
Expand Down Expand Up @@ -623,7 +629,7 @@ impl CAIWriter for SvgIO {
.map_err(|_e| Error::XmlWriteError)?; // pass Event through
}
}
Ok(e) => writer.write_event(&e).map_err(|_e| Error::XmlWriteError)?,
Ok(e) => writer.write_event(e).map_err(|_e| Error::XmlWriteError)?,
Err(_e) => return Err(Error::InvalidAsset("XML invalid".to_string())),
}
buf.clear();
Expand Down
Loading

0 comments on commit acd429a

Please sign in to comment.