hyper_archive/
lib.rs

1use std::sync::OnceLock;
2use aes_gcm::aead::{Aead, OsRng};
3use aes_gcm::aes::Aes256;
4use aes_gcm::{AeadCore, Aes256Gcm, Key, KeyInit, Nonce};
5use lz4_flex;
6use tokio::fs::{File, OpenOptions};
7use tokio::io::{AsyncReadExt, AsyncWriteExt};
8use tokio::sync::RwLock;
9use rayon::prelude::*;
10
11static PASSWORD: OnceLock<RwLock<String>> = OnceLock::new();
12
13pub async fn set_password(pw: &str) {
14    let lock = PASSWORD.get_or_init(|| RwLock::new(String::new()));
15    let mut write_guard = lock.write().await;
16    *write_guard = pw.to_string();
17}
18
19async fn get_password() -> String {
20    let lock = PASSWORD.get_or_init(|| RwLock::new(String::new()));
21    let read_guard = lock.read().await;
22    read_guard.clone()
23}
24
25fn fix_key(key: &[u8]) -> [u8; 32] {
26    let mut fixed_key = [0u8; 32];
27    let len = key.len().min(32);
28    fixed_key[..len].copy_from_slice(&key[..len]);
29    fixed_key
30}
31
32async fn aes_256_encode(data: Vec<u8>) -> (Vec<u8>, Vec<u8>) {
33    let fixed_key = fix_key(get_password().await.as_bytes());
34
35    tokio::task::spawn_blocking(move || {
36        let key = Key::<Aes256>::from_slice(&fixed_key);
37        let cipher = Aes256Gcm::new(&key);
38        let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
39
40        let encoded_data = cipher.encrypt(&nonce, &*data).expect("There was an error while Encoding");
41
42        (encoded_data, nonce.as_slice().to_vec())
43    }).await.unwrap()
44}
45
46async fn aes_256_decode(data: Vec<u8>, nonce: Vec<u8>) -> Vec<u8> {
47    let fixed_key = fix_key(get_password().await.as_bytes());
48
49    tokio::task::spawn_blocking(move || {
50        let key = Key::<Aes256>::from_slice(&fixed_key);
51        let cipher = Aes256Gcm::new(&key);
52        let nonce_from_slice = Nonce::from_slice(nonce.as_slice());
53
54        cipher.decrypt(nonce_from_slice, &*data).unwrap()
55    }).await.unwrap()
56}
57
58async fn lz4_compress(data: Vec<u8>) -> Vec<u8> {
59    tokio::task::spawn_blocking(move || {
60        lz4_flex::compress_prepend_size(&data)
61    }).await.unwrap_or_else(|e1| panic!("There was an error while Compression task: {e1}"))
62}
63
64async fn lz4_decompress(data: Vec<u8>) -> Vec<u8> {
65    tokio::task::spawn_blocking(move || {
66        lz4_flex::decompress_size_prepended(data.as_slice()).unwrap_or_else(|e| panic!("There was an error while decompressing file: {e}"))
67    }).await.unwrap_or_else(|e1| panic!("There was an error while Compression task: {e1}"))
68}
69
70pub async fn write_structure(name: &str, hpa_file: &str, encrypt: bool) {
71    let mut file = File::open(name).await.expect("Error opening file");
72    let mut file_data = Vec::new();
73    file.read_to_end(&mut file_data).await.expect("There was an error while reading Data");
74
75    if tokio::fs::metadata(hpa_file).await.is_ok() {
76        println!("File is already exist");
77        return;
78    }
79
80    let mut data = Vec::new();
81    let compressed_data = lz4_compress(file_data).await;
82
83    tokio::join!(async {
84        if encrypt {
85            let encrypted_data = aes_256_encode(compressed_data).await;
86
87            let ln = encrypted_data.0.len();
88            let wrs = format!("{name}.hpa: {ln}|");
89            data.extend_from_slice(wrs.as_bytes());
90            if ln > 16384 {
91                data.par_extend(encrypted_data.0);
92            } else {
93                data.extend(encrypted_data.0);
94            }
95            data.extend_from_slice(";".as_bytes());
96
97            let ln = encrypted_data.1.len();
98            let wrs = format!("{name}.nonce.hpa: {ln}|");
99            data.extend_from_slice(wrs.as_bytes());
100            data.extend_from_slice(encrypted_data.1.as_slice());
101            data.extend_from_slice(";".as_bytes());
102        } else {
103            let ln = compressed_data.len();
104            let wrs = format!("{name}.hpa: {ln}|");
105            data.extend_from_slice(wrs.as_bytes());
106            if ln > 16384 {
107                data.par_extend(compressed_data);
108            } else {
109                data.extend(compressed_data);
110            }
111            data.extend_from_slice(";".as_bytes());
112
113        }
114
115        let mut file = File::create(hpa_file).await.expect("There was an error while Creating file");
116        let _ = file.write_all(data.as_slice()).await;
117    });
118}
119
120pub async fn find_line(line_to_find: &[u8], content: &[u8]) -> Vec<u8> {
121    let mut search_pattern = Vec::from(line_to_find);
122    search_pattern.extend_from_slice(&[b':', b' ']);
123
124    let content = content.to_vec();
125
126    tokio::task::spawn_blocking(move || {
127        if let Some(start) = memchr::memmem::find(content.as_slice(), &search_pattern) {
128            let start_index = start + search_pattern.len();
129
130            if let Some(pipe_index) = memchr::memmem::find(&content.as_slice()[start_index..], b"|") {
131                let len_bytes = &content.as_slice()[start_index..start_index + pipe_index];
132                let len = len_bytes.iter().fold(0usize, |acc, &b| acc * 10 + (b - b'0') as usize);
133                let value_start = start_index + pipe_index + 1;
134                return content.as_slice()[value_start..value_start + len].to_vec();
135            }
136        }
137
138        Vec::new()
139    }).await.unwrap_or_else(|e| panic!("There was an error while finding line: {e}"))
140}
141
142pub async fn read_structure(name: &str, hpa_file: &str, is_encrypted: bool) -> Vec<u8> {
143    let mut file = File::open(hpa_file).await.expect("There was an error while opening File");
144    let mut file_data = Vec::new();
145    file.read_to_end(&mut file_data).await.expect("There was an error while reading File");
146
147    let final_data = find_line(format!("{name}.hpa").as_bytes(), file_data.as_slice()).await;
148
149    tokio::join!(async {
150        if is_encrypted {
151            let nonce = find_line(format!("{name}.nonce.hpa").as_bytes(), file_data.as_slice()).await;
152            let decrypted = aes_256_decode(final_data, nonce).await;
153            lz4_decompress(decrypted).await
154        } else {
155            lz4_decompress(final_data).await
156        }
157    }).0
158}
159
160pub async fn add_structure(data_file_name: &str, hpa_file_name: &str, encrypt: bool) {
161    let mut data_file = File::open(data_file_name).await.expect("Failed to open data file");
162    let mut data_file_data = Vec::new();
163    data_file.read_to_end(&mut data_file_data).await.expect("Failed to read data file");
164
165    let compressed_data = lz4_compress(data_file_data).await;
166
167    let mut hpa_file = OpenOptions::new().read(true).write(true).open(hpa_file_name).await.unwrap();
168    let mut hpa_file_data = Vec::new();
169    hpa_file.read_to_end(&mut hpa_file_data).await.expect("Failed to read HPA file");
170
171    let line_to_find = format!("{data_file_name}.hpa: ");
172    if hpa_file_data.windows(line_to_find.len()).any(|window| window == line_to_find.as_bytes()) && find_line(line_to_find.as_bytes(), hpa_file_data.as_slice()).await.is_empty() {
173        println!("{} already exists. Did you mean to update?", data_file_name);
174        return;
175    }
176
177    tokio::join!(async {
178        let mut content = Vec::new();
179        if encrypt {
180            let encrypted_data = aes_256_encode(compressed_data).await;
181
182            let ln = encrypted_data.0.len();
183            let wrs = format!("{data_file_name}.hpa: {ln}|");
184            content.extend_from_slice(wrs.as_bytes());
185            if ln > 16384 {
186                content.par_extend(encrypted_data.0);
187            } else {
188                content.extend(encrypted_data.0)
189            }
190            content.extend_from_slice(";".as_bytes());
191
192            let ln = encrypted_data.1.len();
193            let wrs = format!("{data_file_name}.nonce.hpa: {ln}|");
194            content.extend_from_slice(wrs.as_bytes());
195            content.extend_from_slice(encrypted_data.1.as_slice());
196            content.extend_from_slice(";".as_bytes());
197        } else {
198            let ln = compressed_data.len();
199            let wrs = format!("{data_file_name}.hpa: {ln}|");
200            content.extend_from_slice(wrs.as_bytes());
201            if ln > 16384 {
202                content.par_extend(compressed_data)
203            } else {
204                content.extend(compressed_data)
205            }
206            content.extend_from_slice(";".as_bytes());
207        }
208
209        hpa_file.write(content.as_slice()).await.expect("Failed to write to HPA file");
210    });
211}
212
213pub async fn remove_structure(name: &str, hpa_file: &str, is_encrypted: bool) {
214    let mut file = File::open(hpa_file).await.expect("Failed to open HPA file");
215    let mut data = Vec::new();
216    file.read_to_end(&mut data).await.expect("Failed to read HPA file");
217
218    let name = format!("{name}.hpa");
219
220    let remove_entry = |entry_name: &str, file_data: &mut Vec<u8>| {
221        let mut search_pattern = Vec::from(entry_name.as_bytes());
222        search_pattern.extend_from_slice(&[b':', b' ']);
223
224        if let Some(start) = file_data.windows(search_pattern.len()).position(|window| window == search_pattern) {
225            let start_index = start + search_pattern.len();
226
227            if let Some(pipe_index) = file_data[start_index..].iter().position(|&b| b == b'|') {
228                let len_bytes = &file_data[start_index..start_index + pipe_index];
229                let len = len_bytes.iter().fold(0usize, |acc, &b| acc * 10 + (b - b'0') as usize);
230                let value_start = start_index + pipe_index + 1;
231                let value_end = value_start + len;
232
233                if value_end < file_data.len() {
234                    let end = file_data[value_end..].iter().position(|&b| b == b';').map(|e| value_end + e).unwrap_or(file_data.len());
235
236                    file_data.par_drain(start..=end);
237                }
238            }
239        }
240    };
241
242    tokio::join!(async {
243        if is_encrypted {
244            remove_entry(name.as_str(), &mut data);
245            let nonce_name = format!("{name}.nonce.hpa");
246            remove_entry(&nonce_name, &mut data);
247        } else {
248            let name_2 = format!("{name}.hpa");
249            if data.windows(data.len()).any(|window| window == name_2.as_bytes()) {
250                println!("{} already exists. Did you mean to update?", name_2);
251                return;
252            }
253
254            remove_entry(name.as_str(), &mut data);
255        }
256
257        let mut file = OpenOptions::new().write(true).truncate(true).open(hpa_file).await.expect("Failed to open HPA file for writing");
258        file.write_all(&data).await.expect("Failed to write to HPA file");
259    });
260}
261
262
263pub async fn update_structure(data_file_name: &str, hpa_file_name: &str, is_encrypted: bool) {
264    tokio::join!(async {
265        remove_structure(data_file_name, hpa_file_name, is_encrypted).await;
266        add_structure(data_file_name, hpa_file_name, is_encrypted).await
267    });
268}
269
270pub async fn export_structure(name: &str, hpa_file: &str, is_encrypted: bool) {
271    tokio::join!(async {
272        let read = read_structure(name, hpa_file, is_encrypted).await;
273
274        let file = File::create(name).await;
275        let _ = file.unwrap().write_all(read.as_slice()).await;
276    });
277}