lotus_lib/cache_pair/
cache_pair_reader.rs

1use std::fs::File;
2use std::io::{Read, Seek, SeekFrom};
3use std::path::PathBuf;
4
5use anyhow::Result;
6
7use crate::cache_pair::cache_pair::CachePair;
8use crate::compression::post_ensmallening::decompress_post_ensmallening;
9use crate::compression::pre_ensmallening::decompress_pre_ensmallening;
10use crate::toc::{FileNode, Node, Toc};
11
12/// A cache pair reader.
13pub struct CachePairReader {
14    is_post_ensmallening: bool,
15    toc_path: PathBuf,
16    cache_path: PathBuf,
17    toc: Toc,
18}
19
20impl CachePair for CachePairReader {
21    fn new(toc_path: PathBuf, cache_path: PathBuf, is_post_ensmallening: bool) -> Self {
22        let toc = Toc::new(toc_path.clone());
23        Self {
24            is_post_ensmallening,
25            toc_path,
26            cache_path,
27            toc,
28        }
29    }
30
31    fn is_post_ensmallening(&self) -> bool {
32        self.is_post_ensmallening
33    }
34
35    fn toc_path(&self) -> PathBuf {
36        self.toc_path.clone()
37    }
38
39    fn cache_path(&self) -> PathBuf {
40        self.cache_path.clone()
41    }
42
43    fn read_toc(&mut self) -> Result<()> {
44        self.toc.read_toc()
45    }
46
47    fn unread_toc(&mut self) {
48        self.toc.unread_toc()
49    }
50}
51
52impl CachePairReader {
53    /// Get the directory node for the given path.
54    pub fn get_directory_node<T: Into<PathBuf>>(&self, path: T) -> Option<Node> {
55        self.toc.get_directory_node(path.into())
56    }
57
58    /// Get the file node for the given path.
59    pub fn get_file_node<T: Into<PathBuf>>(&self, path: T) -> Option<Node> {
60        self.toc.get_file_node(path.into())
61    }
62
63    /// Get the directory nodes
64    pub fn directories(&self) -> &Vec<Node> {
65        self.toc.directories()
66    }
67
68    /// Get the file nodes
69    pub fn files(&self) -> &Vec<Node> {
70        self.toc.files()
71    }
72
73    /// Read the data without decompressing it for the given file node.
74    pub fn get_data(&self, file_node: Node) -> Result<Vec<u8>> {
75        let mut cache_reader = File::open(self.cache_path.clone()).unwrap();
76        cache_reader
77            .seek(SeekFrom::Start(file_node.cache_offset() as u64))
78            .unwrap();
79
80        let mut data = vec![0; file_node.comp_len() as usize];
81        cache_reader.read_exact(&mut data).unwrap();
82        Ok(data)
83    }
84
85    /// Read and decompress the data for the given file node.
86    ///
87    /// If the file is not compressed, the data is read without decompressing it.
88    pub fn decompress_data(&self, file_node: Node) -> Result<Vec<u8>> {
89        if file_node.comp_len() == file_node.len() {
90            return self.get_data(file_node);
91        }
92
93        let mut cache_reader = File::open(self.cache_path.clone()).unwrap();
94        cache_reader.seek(SeekFrom::Start(file_node.cache_offset() as u64))?;
95
96        if self.is_post_ensmallening {
97            return decompress_post_ensmallening(
98                file_node.comp_len() as usize,
99                file_node.len() as usize,
100                &mut cache_reader,
101            );
102        } else {
103            return decompress_pre_ensmallening(
104                file_node.comp_len() as usize,
105                file_node.len() as usize,
106                &mut cache_reader,
107            );
108        }
109    }
110}