use std::collections::BTreeMap;
#[derive(Debug, Clone)]
pub struct DefaultExt {
pub extension: String,
pub content_type: String,
}
impl DefaultExt {
pub fn new(ext: impl Into<String>, ct: impl Into<String>) -> Self {
DefaultExt {
extension: ext.into().trim_start_matches('.').to_string(),
content_type: ct.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct Override {
pub partname: String,
pub content_type: String,
}
#[derive(Debug, Clone, Default)]
pub struct ContentTypes {
pub defaults: Vec<DefaultExt>,
pub overrides: Vec<Override>,
by_partname: BTreeMap<String, usize>,
}
impl ContentTypes {
#[allow(clippy::field_reassign_with_default)]
pub fn new_default() -> Self {
let mut ct = ContentTypes::default();
ct.defaults.push(DefaultExt::new("xml", "application/xml"));
ct.defaults.push(DefaultExt::new(
"rels",
"application/vnd.openxmlformats-package.relationships+xml",
));
ct.defaults.push(DefaultExt::new("png", "image/png"));
ct.defaults.push(DefaultExt::new("jpeg", "image/jpeg"));
ct.defaults.push(DefaultExt::new("jpg", "image/jpeg"));
ct.defaults.push(DefaultExt::new("gif", "image/gif"));
ct.defaults.push(DefaultExt::new("bmp", "image/bmp"));
ct.defaults.push(DefaultExt::new("svg", "image/svg+xml"));
ct
}
pub fn add_override(&mut self, partname: &str, content_type: &str) {
if self.by_partname.contains_key(partname) {
return;
}
let idx = self.overrides.len();
self.overrides.push(Override {
partname: partname.to_string(),
content_type: content_type.to_string(),
});
self.by_partname.insert(partname.to_string(), idx);
}
pub fn has_override(&self, partname: &str) -> bool {
self.by_partname.contains_key(partname)
}
pub fn to_xml(&self) -> String {
let mut s = String::with_capacity(512);
s.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
s.push_str(
"<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">",
);
for d in &self.defaults {
s.push_str(&format!(
"<Default Extension=\"{}\" ContentType=\"{}\"/>",
super::rels::xml_escape(&d.extension),
super::rels::xml_escape(&d.content_type),
));
}
for o in &self.overrides {
s.push_str(&format!(
"<Override PartName=\"{}\" ContentType=\"{}\"/>",
super::rels::xml_escape(&o.partname),
super::rels::xml_escape(&o.content_type),
));
}
s.push_str("</Types>");
s
}
}