chrome_cache_parser/
lib.rs1pub mod block_file;
4pub mod cache_address;
5pub mod cache_index;
6pub mod error;
7pub mod time;
8
9pub use crate::cache_address::CacheAddr;
10use crate::cache_index::CacheVersion;
11pub use crate::cache_index::IndexHeader;
12pub use crate::error::{CCPError, CCPResult};
13
14use block_file::{DataFiles, LazyBlockFileCacheEntry, LazyBlockFileCacheEntryIterator};
15use cache_address::CACHE_ADDRESS_SIZE;
16use cache_index::INDEX_HEADER_SIZE;
17use std::cell::RefCell;
18use std::collections::HashMap;
19use std::fs;
20use std::io::Read;
21use std::path::{Path, PathBuf};
22use std::rc::Rc;
23use zerocopy::{FromBytes, Ref};
24
25pub struct ChromeCache {
28 path: PathBuf,
29 buffer: Vec<u8>,
30}
31
32impl ChromeCache {
33 pub fn from_path(path: PathBuf) -> CCPResult<ChromeCache> {
34 let index = Self::path_to_index(&path);
35 if !index.exists() {
36 return Err(CCPError::IndexDoesNotExist(
37 index.to_string_lossy().to_string(),
38 ));
39 }
40
41 let mut index_buffer = Vec::new();
42 let mut f = fs::File::open(index)?;
43 f.read_to_end(&mut index_buffer)?;
44
45 let chrome_cache = ChromeCache {
46 path,
47 buffer: index_buffer,
48 };
49
50 let header = ChromeCache::header(&chrome_cache)?;
51 let version = CacheVersion::from(header.version);
52
53 if header.magic != cache_index::INDEX_MAGIC {
54 return Err(CCPError::InvalidData("invalid index magic".to_string()));
55 }
56
57 if let CacheVersion::Unknown(version) = version {
58 return Err(CCPError::UnsupportedVersion(format!(
59 "unsupported version ({:x})",
60 version
61 )));
62 }
63
64 Ok(chrome_cache)
65 }
66
67 pub fn header(&self) -> CCPResult<&IndexHeader> {
68 IndexHeader::ref_from(&self.buffer[0..INDEX_HEADER_SIZE]).ok_or(CCPError::DataMisalignment(
69 "index header misalignment".to_string(),
70 ))
71 }
72
73 pub fn addresses(&self) -> CCPResult<&[CacheAddr]> {
74 let table_len = self.header()?.table_len as usize;
75 let begin = INDEX_HEADER_SIZE;
76 let end = begin + table_len * CACHE_ADDRESS_SIZE;
77 let addresses = Ref::<_, [CacheAddr]>::new_slice(&self.buffer[begin..end]).ok_or(
78 CCPError::DataMisalignment("cache address table misalignment".to_string()),
79 )?;
80
81 Ok(addresses.into_slice())
82 }
83
84 fn path_to_index(cache_dir: &Path) -> PathBuf {
85 cache_dir.join("index")
86 }
87
88 pub fn entries(&self) -> CCPResult<impl Iterator<Item = LazyBlockFileCacheEntry> + '_> {
89 let data_files = Rc::new(RefCell::new(DataFiles::new(
91 HashMap::new(),
92 self.path.to_path_buf(),
93 )));
94
95 let entries = self
96 .addresses()?
97 .iter()
98 .filter(|addr| addr.is_initialized())
99 .zip(std::iter::repeat(data_files))
100 .flat_map(|(addr, data_files)| {
101 LazyBlockFileCacheEntryIterator::new(data_files, *addr, self.path.to_path_buf())
102 });
103
104 Ok(entries)
105 }
106}