Skip to main content

epub_parser/
zip_handler.rs

1use crate::epub::Error;
2use std::fs::File;
3use std::io::{Read, Seek};
4use std::path::Path;
5use zip::ZipArchive;
6
7pub struct ZipHandler<R: Read + Seek> {
8    archive: ZipArchive<R>,
9}
10
11impl ZipHandler<File> {
12    pub fn new(path: &Path) -> Result<Self, Error> {
13        let file = File::open(path)?;
14        let archive = ZipArchive::new(file)?;
15        Ok(ZipHandler { archive })
16    }
17}
18
19impl<R: Read + Seek> ZipHandler<R> {
20    pub fn new_from_reader(reader: R) -> Result<Self, Error> {
21        let archive = ZipArchive::new(reader)?;
22        Ok(ZipHandler { archive })
23    }
24
25    pub fn get_opf_path(&mut self) -> Result<String, Error> {
26        let container_content = self.read_file("META-INF/container.xml")?;
27
28        let mut reader = quick_xml::Reader::from_str(&container_content);
29        let mut opf_path = String::new();
30
31        let mut buf = Vec::new();
32
33        loop {
34            match reader.read_event_into(&mut buf) {
35                Ok(quick_xml::events::Event::Start(ref e)) => {
36                    let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
37
38                    if name == "rootfile" || name.ends_with(":rootfile") {
39                        for attr_result in e.attributes() {
40                            if let Ok(attr) = attr_result {
41                                let attr_name =
42                                    String::from_utf8_lossy(attr.key.as_ref()).to_string();
43
44                                if attr_name == "full-path" || attr_name.ends_with(":full-path") {
45                                    opf_path = attr
46                                        .decode_and_unescape_value(reader.decoder())?
47                                        .to_string();
48                                    break;
49                                }
50                            }
51                        }
52                        if !opf_path.is_empty() {
53                            break;
54                        }
55                    }
56                }
57                Ok(quick_xml::events::Event::Empty(ref e)) => {
58                    let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
59
60                    if name == "rootfile" || name.ends_with(":rootfile") {
61                        for attr_result in e.attributes() {
62                            if let Ok(attr) = attr_result {
63                                let attr_name =
64                                    String::from_utf8_lossy(attr.key.as_ref()).to_string();
65
66                                if attr_name == "full-path" || attr_name.ends_with(":full-path") {
67                                    opf_path = attr
68                                        .decode_and_unescape_value(reader.decoder())?
69                                        .to_string();
70                                    break;
71                                }
72                            }
73                        }
74                        if !opf_path.is_empty() {
75                            break;
76                        }
77                    }
78                }
79                Ok(quick_xml::events::Event::Eof) => break,
80                Err(e) => return Err(Error::XmlError(e.to_string())),
81                _ => {}
82            }
83            buf.clear();
84        }
85
86        if opf_path.is_empty() {
87            return Err(Error::MissingOpf);
88        }
89
90        Ok(opf_path)
91    }
92
93    pub fn read_file(&mut self, path: &str) -> Result<String, Error> {
94        let mut file = self.archive.by_name(path)?;
95        let mut content = String::new();
96        file.read_to_string(&mut content)?;
97        Ok(content)
98    }
99
100    pub fn read_file_as_bytes(&mut self, path: &str) -> Result<Vec<u8>, Error> {
101        let mut file = self.archive.by_name(path)?;
102        let mut content = Vec::new();
103        file.read_to_end(&mut content)?;
104        Ok(content)
105    }
106}