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