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
93
94
95
96
97
98
99
100
101
102
103
use std::cell::RefCell;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::path::PathBuf;
use std::rc::Rc;

use anyhow::Result;

use crate::cache_pair::cache_pair::CachePair;
use crate::compression::post_ensmallening::decompress_post_ensmallening;
use crate::compression::pre_ensmallening::decompress_pre_ensmallening;
use crate::toc::{FileNode, Node, Toc};

pub struct CachePairReader {
    is_post_ensmallening: bool,
    toc_path: PathBuf,
    cache_path: PathBuf,
    toc: Rc<RefCell<Toc>>,
}

impl CachePair for CachePairReader {
    fn new(toc_path: PathBuf, cache_path: PathBuf, is_post_ensmallening: bool) -> Self {
        let toc = Rc::new(RefCell::new(Toc::new(toc_path.clone())));
        Self {
            is_post_ensmallening,
            toc_path,
            cache_path,
            toc,
        }
    }

    fn is_post_ensmallening(&self) -> bool {
        self.is_post_ensmallening
    }

    fn toc_path(&self) -> PathBuf {
        self.toc_path.clone()
    }

    fn cache_path(&self) -> PathBuf {
        self.cache_path.clone()
    }

    fn read_toc(&self) -> Result<()> {
        self.toc.borrow_mut().read_toc()
    }

    fn unread_toc(&self) {
        self.toc.borrow_mut().unread_toc();
    }
}

impl CachePairReader {
    pub fn get_directory_node<T: Into<PathBuf>>(&self, path: T) -> Option<Node> {
        self.toc.borrow().get_directory_node(path.into())
    }

    pub fn get_file_node<T: Into<PathBuf>>(&self, path: T) -> Option<Node> {
        self.toc.borrow().get_file_node(path.into())
    }

    pub fn directories(&self) -> Vec<Node> {
        self.toc.borrow().directories()
    }

    pub fn files(&self) -> Vec<Node> {
        self.toc.borrow().files()
    }

    pub fn get_data(&self, file_node: Node) -> Result<Vec<u8>> {
        let mut cache_reader = File::open(self.cache_path.clone()).unwrap();
        cache_reader
            .seek(SeekFrom::Start(file_node.cache_offset() as u64))
            .unwrap();

        let mut data = vec![0; file_node.comp_len() as usize];
        cache_reader.read_exact(&mut data).unwrap();
        Ok(data)
    }

    pub fn decompress_data(&self, file_node: Node) -> Result<Vec<u8>> {
        if file_node.comp_len() == file_node.len() {
            return self.get_data(file_node);
        }

        let mut cache_reader = File::open(self.cache_path.clone()).unwrap();
        cache_reader.seek(SeekFrom::Start(file_node.cache_offset() as u64))?;

        if self.is_post_ensmallening {
            return decompress_post_ensmallening(
                file_node.comp_len() as usize,
                file_node.len() as usize,
                &mut cache_reader,
            );
        } else {
            return decompress_pre_ensmallening(
                file_node.comp_len() as usize,
                file_node.len() as usize,
                &mut cache_reader,
            );
        }
    }
}