Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Switch to from fast_xml to quick_xml #805

Merged
merged 3 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -90,7 +90,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
Loading