1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
use std::collections::BTreeMap; use std::io::{Cursor, Read}; use std::path::*; use std::str::FromStr; use xml::reader::{EventReader, XmlEvent}; use super::errors::*; use super::*; #[derive(Debug, Clone, PartialEq)] pub struct ReadDocumentRels { rels: BTreeMap<String, PathBuf>, } impl ReadDocumentRels { pub fn find_target_path(&self, target: &str) -> Option<PathBuf> { self.rels.get(target).cloned() } } pub fn read_document_rels( archive: &mut zip::read::ZipArchive<Cursor<&[u8]>>, main_path: impl AsRef<Path>, ) -> Result<ReadDocumentRels, ReaderError> { let dir = &main_path .as_ref() .parent() .ok_or(ReaderError::DocumentRelsNotFoundError)?; let p = find_rels_filename(&main_path)?; let p = p.to_str().ok_or(ReaderError::DocumentRelsNotFoundError)?; let data = read_zip(archive, &p)?; let rels = read_rels_xml(&data[..], dir)?; Ok(rels) } fn read_rels_xml<R: Read>( reader: R, dir: impl AsRef<Path>, ) -> Result<ReadDocumentRels, ReaderError> { let mut parser = EventReader::new(reader); let mut rels = ReadDocumentRels { rels: BTreeMap::new(), }; loop { let e = parser.next(); match e { Ok(XmlEvent::StartElement { attributes, name, .. }) => { let e = XMLElement::from_str(&name.local_name).unwrap(); if let XMLElement::Relationship = e { let mut rel_type = "".to_owned(); let mut target = PathBuf::default(); for a in attributes { let local_name = &a.name.local_name; if local_name == "Type" { rel_type = a.value.to_owned(); } else if local_name == "Target" { target = Path::new(dir.as_ref()).join(a.value); } } rels.rels.insert(rel_type, target); continue; } } Ok(XmlEvent::EndElement { name, .. }) => { let e = XMLElement::from_str(&name.local_name).unwrap(); if let XMLElement::Relationships = e { break; } } Err(_) => return Err(ReaderError::XMLReadError), _ => {} } } Ok(rels) } fn find_rels_filename(main_path: impl AsRef<Path>) -> Result<PathBuf, ReaderError> { let path = main_path.as_ref(); let dir = path .parent() .ok_or(ReaderError::DocumentRelsNotFoundError)?; let base = path .file_stem() .ok_or(ReaderError::DocumentRelsNotFoundError)?; Ok(Path::new(dir) .join("_rels") .join(base) .with_extension("xml.rels")) }