#![allow(clippy::tabs_in_doc_comments)]
use serde::{Deserialize, Serialize};
pub use plist::{
from_bytes, from_file, from_reader, from_reader_xml, to_file_binary, to_file_xml,
to_writer_binary, to_writer_xml,
};
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct WebResource {
#[serde(rename = "WebResourceData", with = "serde_bytes")]
pub data: Vec<u8>,
#[serde(rename = "WebResourceURL")]
pub url: String,
#[serde(
rename = "WebResourceFrameName",
default,
deserialize_with = "ruma_serde::empty_string_as_none"
)]
pub frame_name: Option<String>,
#[serde(rename = "WebResourceMIMEType")]
pub mime_type: String,
#[serde(
rename = "WebResourceTextEncodingName",
default,
deserialize_with = "ruma_serde::empty_string_as_none"
)]
pub text_encoding_name: Option<String>,
#[serde(rename = "WebResourceResponse", default, with = "serde_bytes")]
pub response: Option<Vec<u8>>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct WebArchive {
#[serde(rename = "WebMainResource")]
pub main_resource: WebResource,
#[serde(rename = "WebSubresources")]
pub subresources: Option<Vec<WebResource>>,
#[serde(rename = "WebSubframeArchives")]
pub subframe_archives: Option<Vec<WebArchive>>,
}
impl WebArchive {
pub fn print_list(&self) {
let subresource_count = match &self.subresources {
Some(subresources) => subresources.len(),
None => 0,
};
let subframe_archive_count = match &self.subframe_archives {
Some(subframe_archives) => subframe_archives.len(),
None => 0,
};
println!(
"WebArchive of \"{}\" ({:?}, {} bytes): {} subresource{}, {} subframe archive{} totalling {} bytes",
self.main_resource.url,
self.main_resource.mime_type,
self.main_resource.data.len(),
subresource_count,
if subresource_count == 1 { "" } else { "s" },
subframe_archive_count,
if subframe_archive_count == 1 { "" } else { "s" },
self.total_size(),
);
if let Some(subresources) = &self.subresources {
subresources.iter().for_each(|subresource| {
println!(
" - \"{}\" ({:?}, {} bytes)",
subresource.url,
subresource.mime_type,
subresource.data.len()
)
});
}
if let Some(webarchives) = &self.subframe_archives {
webarchives
.iter()
.for_each(|webarchive| webarchive.print_list());
}
}
pub fn total_size(&self) -> usize {
let subresource_size = match &self.subresources {
Some(subresources) => subresources
.iter()
.map(|subresource| subresource.data.len())
.sum(),
None => 0,
};
let subframe_archive_size = match &self.subframe_archives {
Some(webarchives) => webarchives
.iter()
.map(|webarchive| webarchive.total_size())
.sum(),
None => 0,
};
self.main_resource.data.len() + subresource_size + subframe_archive_size
}
}
#[cfg(test)]
mod tests {
#[test]
fn parse_crouton() {
let bytes = include_bytes!("../fixtures/crouton.webarchive");
let webarchive: super::WebArchive =
super::from_bytes(bytes).expect("Could not read Crouton webarchive fixture");
assert_eq!(webarchive.main_resource.data.len(), 134);
assert_eq!(
webarchive.main_resource.data.get(0..10).expect("No data"),
[60, 104, 116, 109, 108, 62, 60, 104, 101, 97]
);
assert_eq!(webarchive.main_resource.url, "https://crouton.net/");
assert!(webarchive.main_resource.frame_name.is_none());
assert_eq!(webarchive.main_resource.mime_type, "text/html");
let text_encoding_name = webarchive
.main_resource
.text_encoding_name
.as_ref()
.expect("text_encoding_name not found");
assert_eq!(text_encoding_name, "UTF-8");
assert!(webarchive.main_resource.response.is_none());
let subresources = webarchive
.subresources
.as_ref()
.expect("No subresources found");
assert_eq!(subresources.len(), 1);
let first_subresource = &subresources[0];
assert_eq!(first_subresource.data.len(), 5182);
assert_eq!(
first_subresource.data.get(0..10).expect("No data"),
[137, 80, 78, 71, 13, 10, 26, 10, 0, 0]
);
assert_eq!(first_subresource.url, "https://crouton.net/crouton.png");
assert!(first_subresource.frame_name.is_none());
assert_eq!(first_subresource.mime_type, "image/png");
assert!(first_subresource.text_encoding_name.is_none());
let response = first_subresource
.response
.as_ref()
.expect("response not found");
assert_eq!(response.len(), 1825);
assert_eq!(
response.get(0..10).expect("No data"),
[98, 112, 108, 105, 115, 116, 48, 48, 212, 1]
);
assert!(webarchive.subframe_archives.is_none());
}
}