rusty_jar/
jarfile.rs

1use crate::error::{IoSnafu, JarError, Result};
2use snafu::ResultExt;
3use std::collections::HashMap;
4use std::fs::File;
5use std::io::{BufReader, Read};
6use std::path::Path;
7use zip::ZipArchive;
8
9/// Represents a JAR (Java ARchive) file, which is essentially a ZIP file with a specific structure.
10#[derive(Debug)]
11pub struct JarFile {
12    zip_file: ZipArchive<BufReader<File>>,
13    file_name_index: HashMap<String, usize>,
14}
15
16impl JarFile {
17    /// Opens a JAR file from the specified path.
18    pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
19        let file = File::open(path.as_ref()).context(IoSnafu {
20            path: path.as_ref().to_path_buf(),
21        })?;
22        let reader = BufReader::new(file);
23        let mut zip_file = ZipArchive::new(reader)?;
24
25        let mut file_name_index = HashMap::with_capacity(zip_file.len());
26        for i in 0..zip_file.len() {
27            let file = zip_file.by_index(i)?;
28            if file.is_file() {
29                let name = file.name().to_string();
30                file_name_index.insert(name, i);
31            }
32        }
33
34        Ok(JarFile {
35            zip_file,
36            file_name_index,
37        })
38    }
39
40    /// Returns a vector of the names of the files contained in the JAR file.
41    pub fn file_names(&self) -> Vec<String> {
42        self.file_name_index.keys().cloned().collect()
43    }
44
45    /// Retrieves the content of a file within the JAR by its name.
46    pub fn content_by_name(&mut self, name: &str) -> Result<Vec<u8>> {
47        let index = self
48            .file_name_index
49            .get(name)
50            .ok_or_else(|| JarError::EntryNotFound {
51                entry_name: name.to_string(),
52            })?;
53        let mut file = self.zip_file.by_index(*index)?;
54        let mut buffer = Vec::with_capacity(file.size() as usize);
55        file.read_to_end(&mut buffer).map_err(|e| JarError::Io {
56            source: e,
57            path: name.into(),
58        })?;
59        Ok(buffer)
60    }
61}