1use std::{
2 collections::HashMap,
3 io::{Read, Seek, SeekFrom},
4 ops::DerefMut,
5 str,
6 sync::{Arc, Mutex},
7};
8
9use super::resource::Resource;
10use crate::global::{error::*, flags::Flags, header::Header, reg_entry::RegistryEntry};
11
12#[cfg(feature = "crypto")]
13use crate::crypto;
14
15#[cfg(feature = "compression")]
16use crate::global::compressor::*;
17
18#[derive(Debug)]
21pub struct Archive<T> {
22 handle: Mutex<T>,
25
26 header: Header,
28 entries: HashMap<Arc<str>, RegistryEntry>,
29
30 #[cfg(feature = "crypto")]
32 decryptor: Option<crypto::Encryptor>,
33 #[cfg(feature = "crypto")]
34 key: Option<crypto::VerifyingKey>,
35}
36
37impl<T> std::fmt::Display for Archive<T> {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 let bytes = self
40 .entries
41 .values()
42 .map(|re| re.offset)
43 .reduce(|a, b| a + b)
44 .unwrap_or(0);
45
46 write!(
47 f,
48 "[Archive Header] Version: {}, Members: {}, Compressed Size: {bytes}B, Header-Flags: <{:#x} : {:#016b}>",
49 self.header.version,
50 self.entries.len(),
51 self.header.flags.bits,
52 self.header.flags.bits,
53 )
54 }
55}
56
57impl<T> Archive<T> {
58 pub fn into_inner(self) -> Result<T, std::sync::PoisonError<T>> {
60 self.handle.into_inner()
61 }
62
63 #[inline(never)]
65 fn process(&self, entry: &RegistryEntry, mut raw: Vec<u8>) -> InternalResult<(Vec<u8>, bool)> {
66 let mut decrypted = None;
70 let mut verified = false;
71
72 #[cfg(feature = "crypto")]
75 if let Some(pk) = self.key {
76 if let Some(signature) = entry.signature {
78 let raw_size = raw.len();
79
80 let entry_bytes = entry.to_bytes(true)?;
81 raw.extend_from_slice(&entry_bytes);
82
83 verified = pk.verify_strict(&raw, &signature).is_ok();
84 raw.truncate(raw_size);
85 }
86 }
87
88 if entry.flags.contains(Flags::ENCRYPTED_FLAG) {
90 #[cfg(feature = "crypto")]
91 match self.decryptor.as_ref() {
92 Some(dc) => {
93 decrypted = Some(dc.decrypt(&raw)?);
94 },
95 None => return Err(InternalError::NoKeypairError),
96 }
97
98 #[cfg(not(feature = "crypto"))]
99 return Err(InternalError::MissingFeatureError("crypto"));
100 }
101
102 if entry.flags.contains(Flags::COMPRESSED_FLAG) {
104 #[cfg(feature = "compression")]
105 {
106 let (source, mut target) = match decrypted {
107 Some(vec) => {
109 raw.clear();
110 (vec, raw)
111 },
112 None => {
114 let capacity = raw.capacity();
115 (raw, Vec::with_capacity(capacity))
116 },
117 };
118
119 if entry.flags.contains(Flags::LZ4_COMPRESSED) {
120 Compressor::new(source.as_slice()).decompress(CompressionAlgorithm::LZ4, &mut target)?
121 } else if entry.flags.contains(Flags::BROTLI_COMPRESSED) {
122 Compressor::new(source.as_slice()).decompress(CompressionAlgorithm::Brotli(0), &mut target)?
123 } else if entry.flags.contains(Flags::SNAPPY_COMPRESSED) {
124 Compressor::new(source.as_slice()).decompress(CompressionAlgorithm::Snappy, &mut target)?
125 } else {
126 return InternalResult::Err(InternalError::OtherError(
127 format!(
128 "Unable to determine the compression algorithm used for entry: {}",
129 entry
130 )
131 .into(),
132 ));
133 };
134
135 Ok((target, verified))
136 }
137
138 #[cfg(not(feature = "compression"))]
139 Err(InternalError::MissingFeatureError("compression"))
140 } else {
141 match decrypted {
142 Some(decrypted) => Ok((decrypted, verified)),
143 None => Ok((raw, verified)),
144 }
145 }
146 }
147}
148
149impl<T> Archive<T>
150where
151 T: Seek + Read,
152{
153 pub fn new(mut handle: T) -> InternalResult<Archive<T>> {
155 handle.seek(SeekFrom::Start(0))?;
157
158 let header = Header::from_handle(&mut handle)?;
159 header.validate()?;
160
161 let mut entries = HashMap::new();
163
164 for _ in 0..header.capacity {
166 let entry = RegistryEntry::from_handle(&mut handle)?;
167 entries.insert(entry.id.clone(), entry);
168 }
169
170 let archive = Archive {
171 header,
172 handle: Mutex::new(handle),
173 entries,
174
175 #[cfg(feature = "crypto")]
176 key: None,
177 #[cfg(feature = "crypto")]
178 decryptor: None,
179 };
180
181 Ok(archive)
182 }
183
184 #[cfg(feature = "crypto")]
186 pub fn with_key(mut handle: T, vk: &ed25519_dalek::VerifyingKey) -> InternalResult<Archive<T>> {
187 handle.seek(SeekFrom::Start(0))?;
189
190 let header = Header::from_handle(&mut handle)?;
191 header.validate()?;
192
193 let mut entries = HashMap::new();
195
196 for _ in 0..header.capacity {
198 let entry = RegistryEntry::from_handle(&mut handle)?;
199 entries.insert(entry.id.clone(), entry);
200 }
201
202 let archive = Archive {
203 header,
204 handle: Mutex::new(handle),
205 entries,
206
207 key: Some(vk.clone()),
208 decryptor: Some(crypto::Encryptor::new(vk)),
209 };
210
211 Ok(archive)
212 }
213
214 pub fn fetch_entry(&self, id: impl AsRef<str>) -> Option<RegistryEntry> {
217 self.entries.get(id.as_ref()).cloned()
218 }
219
220 #[inline(always)]
222 pub fn entries(&self) -> &HashMap<Arc<str>, RegistryEntry> {
223 &self.entries
224 }
225
226 #[inline(always)]
228 pub fn flags(&self) -> &Flags {
229 &self.header.flags
230 }
231}
232
233impl<T> Archive<T>
234where
235 T: Read + Seek,
236{
237 pub(crate) fn read_raw(handle: &mut T, entry: &RegistryEntry) -> InternalResult<Vec<u8>> {
239 let mut buffer = Vec::with_capacity(entry.offset as usize + 64);
240 handle.seek(SeekFrom::Start(entry.location))?;
241
242 let mut take = handle.take(entry.offset);
243 take.read_to_end(&mut buffer)?;
244
245 Ok(buffer)
246 }
247
248 pub fn fetch_mut(&mut self, id: impl AsRef<str>) -> InternalResult<Resource> {
250 if let Some(entry) = self.fetch_entry(&id) {
252 let raw = Archive::read_raw(self.handle.get_mut().unwrap(), &entry)?;
253
254 let (buffer, verified) = self.process(&entry, raw)?;
257
258 Ok(Resource {
259 content_version: entry.content_version,
260 flags: entry.flags,
261 data: buffer.into_boxed_slice(),
262 verified,
263 })
264 } else {
265 Err(InternalError::MissingResourceError(id.as_ref().to_string()))
266 }
267 }
268
269 pub fn fetch(&self, id: impl AsRef<str>) -> InternalResult<Resource> {
272 if let Some(entry) = self.fetch_entry(&id) {
274 let raw = {
275 let mut guard = self.handle.lock().unwrap();
276 Archive::read_raw(guard.deref_mut(), &entry)?
277 };
278
279 let (buffer, is_secure) = self.process(&entry, raw)?;
282
283 Ok(Resource {
284 content_version: entry.content_version,
285 flags: entry.flags,
286 data: buffer.into_boxed_slice(),
287 verified: is_secure,
288 })
289 } else {
290 Err(InternalError::MissingResourceError(id.as_ref().to_string()))
291 }
292 }
293}