1#![cfg_attr(docsrs, feature(doc_cfg))]
70#![deny(
71 clippy::all,
72 clippy::correctness,
73 clippy::suspicious,
74 clippy::style,
75 clippy::complexity,
76 clippy::perf
77)]
78
79#[macro_use]
80pub mod util;
81pub mod checksum;
82pub mod definition;
83pub mod error;
84pub mod extension;
85pub mod loader;
86
87#[doc(inline)]
88pub use error::Error;
89use error::Result;
90
91use checksum::Checksum;
92#[cfg(feature = "rs3")]
93use checksum::{RsaChecksum, RsaKeys};
94use runefs::codec::{Buffer, Decoded, Encoded};
95use runefs::error::{Error as RuneFsError, ReadError};
96use runefs::{ArchiveRef, Dat2, Indices, MAIN_DATA};
97use std::{io::Write, path::Path};
98
99#[derive(Debug)]
101pub struct Cache {
102 data: Dat2,
103 pub(crate) indices: Indices,
104}
105
106impl Cache {
107 pub fn new<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
119 Ok(Self {
120 data: Dat2::new(path.as_ref().join(MAIN_DATA))?,
121 indices: Indices::new(path)?,
122 })
123 }
124
125 pub fn checksum(&self) -> crate::Result<Checksum> {
131 Checksum::new(self)
132 }
133
134 #[cfg(feature = "rs3")]
139 #[cfg_attr(docsrs, doc(cfg(feature = "rs3")))]
140 pub fn checksum_with<'a>(&self, keys: RsaKeys<'a>) -> crate::Result<RsaChecksum<'a>> {
141 RsaChecksum::with_keys(self, keys)
142 }
143
144 pub fn read(&self, index_id: u8, archive_id: u32) -> crate::Result<Buffer<Encoded>> {
154 let index = self
155 .indices
156 .get(&index_id)
157 .ok_or(RuneFsError::Read(ReadError::IndexNotFound(index_id)))?;
158
159 let archive = index
160 .archive_refs
161 .get(&archive_id)
162 .ok_or(RuneFsError::Read(ReadError::ArchiveNotFound {
163 idx: index_id,
164 arc: archive_id,
165 }))?;
166
167 let buffer = self.data.read(archive)?;
168
169 assert_eq!(buffer.len(), archive.length);
170
171 Ok(buffer)
172 }
173
174 pub(crate) fn read_archive(&self, archive: &ArchiveRef) -> crate::Result<Buffer<Encoded>> {
175 self.read(archive.index_id, archive.id)
176 }
177
178 pub fn read_into_writer<W: Write>(
184 &self,
185 index_id: u8,
186 archive_id: u32,
187 writer: &mut W,
188 ) -> crate::Result<()> {
189 let index = self
190 .indices
191 .get(&index_id)
192 .ok_or(RuneFsError::Read(ReadError::IndexNotFound(index_id)))?;
193
194 let archive = index
195 .archive_refs
196 .get(&archive_id)
197 .ok_or(RuneFsError::Read(ReadError::ArchiveNotFound {
198 idx: index_id,
199 arc: archive_id,
200 }))?;
201 Ok(self.data.read_into_writer(archive, writer)?)
202 }
203
204 pub fn huffman_table(&self) -> crate::Result<Buffer<Decoded>> {
208 let index_id = 10;
209
210 let archive = self.archive_by_name(index_id, "huffman")?;
211 let buffer = self.read_archive(archive)?;
212
213 assert_eq!(buffer.len(), archive.length);
214
215 Ok(buffer.decode()?)
216 }
217
218 pub(crate) fn archive_by_name<T: AsRef<str>>(
219 &self,
220 index_id: u8,
221 name: T,
222 ) -> crate::Result<&ArchiveRef> {
223 let index = self
224 .indices
225 .get(&index_id)
226 .ok_or(RuneFsError::Read(ReadError::IndexNotFound(index_id)))?;
227 let hash = util::djd2::hash(&name);
228
229 let archive = index
230 .metadata
231 .iter()
232 .find(|archive| archive.name_hash == hash)
233 .ok_or_else(|| crate::error::NameHashMismatch {
234 hash,
235 name: name.as_ref().into(),
236 idx: index_id,
237 })?;
238
239 let archive_ref = index
240 .archive_refs
241 .get(&archive.id)
242 .ok_or(RuneFsError::Read(ReadError::ArchiveNotFound {
243 idx: index_id,
244 arc: archive.id,
245 }))?;
246
247 Ok(archive_ref)
248 }
249}
250
251#[cfg(test)]
252mod test_util {
253 use super::Cache;
254 use sha1::Sha1;
255
256 fn is_normal<T: Send + Sync + Sized + Unpin>() {}
257
258 #[test]
259 fn normal_types() {
260 is_normal::<super::Cache>();
261 }
262
263 pub fn osrs_cache() -> crate::Result<Cache> {
264 Cache::new("./data/osrs_cache")
265 }
266
267 #[cfg(all(test, feature = "rs3"))]
268 pub fn rs3_cache() -> crate::Result<Cache> {
269 Cache::new("./data/rs3_cache")
270 }
271
272 pub fn hash(buffer: &[u8]) -> String {
273 let mut m = Sha1::new();
274
275 m.update(buffer);
276 m.digest().to_string()
277 }
278}
279
280#[cfg(test)]
281mod read {
282 mod osrs {
283 use crate::test_util;
284
285 #[test]
286 fn ref_table() -> crate::Result<()> {
287 let cache = test_util::osrs_cache()?;
288 let buffer = cache.read(255, 10)?;
289 let hash = test_util::hash(&buffer);
290 assert_eq!(&hash, "9a9a50a0bd25d6246ad5fe3ebc5b14e9a5df7227");
291 assert_eq!(buffer.len(), 77);
292 Ok(())
293 }
294 #[test]
295 fn random_read() -> crate::Result<()> {
296 let cache = test_util::osrs_cache()?;
297 let buffer = cache.read(0, 191)?;
298 let hash = test_util::hash(&buffer);
299 assert_eq!(&hash, "cd459f6ccfbd81c1e3bfadf899624f2519e207a9");
300 assert_eq!(buffer.len(), 2055);
301 Ok(())
302 }
303 #[test]
304 fn large_read() -> crate::Result<()> {
305 let cache = test_util::osrs_cache()?;
306 let buffer = cache.read(2, 10)?;
307 let hash = test_util::hash(&buffer);
308 assert_eq!(&hash, "6d3396a9d5a7729b3b8069ac32e384e5da58096b");
309 assert_eq!(buffer.len(), 282396);
310 Ok(())
311 }
312 #[test]
313 fn deep_archive() -> crate::Result<()> {
314 let cache = test_util::osrs_cache()?;
315 let buffer = cache.read(7, 24918)?;
316 let hash = test_util::hash(&buffer);
317 assert_eq!(&hash, "fe91e9e9170a5a05ed2684c1db1169aa7ef4906e");
318 assert_eq!(buffer.len(), 803);
319 Ok(())
320 }
321
322 #[test]
323 fn single_data_len() -> crate::Result<()> {
324 let cache = test_util::osrs_cache()?;
325 let buffer = cache.read(3, 278)?;
326
327 let hash = test_util::hash(&buffer);
328 assert_eq!(&hash, "036abb64d3f1734d892f69b1253a87639b7bcb44");
329 assert_eq!(buffer.len(), 512);
330 Ok(())
331 }
332
333 #[test]
334 fn double_data_len() -> crate::Result<()> {
335 let cache = test_util::osrs_cache()?;
336 let buffer = cache.read(0, 1077)?;
337
338 let hash = test_util::hash(&buffer);
339 assert_eq!(&hash, "fbe9d365cf0c3efa94e0d4a2c5e607b28a1279b9");
340 assert_eq!(buffer.len(), 1024);
341 Ok(())
342 }
343
344 #[test]
345 fn fails() -> crate::Result<()> {
346 let cache = test_util::osrs_cache()?;
347 assert!(cache.read(2, 25_000).is_err());
348 Ok(())
349 }
350 }
351
352 #[cfg(feature = "rs3")]
353 mod rs3 {
354 use crate::test_util;
355
356 #[test]
357 fn random_0_read() -> crate::Result<()> {
358 let cache = test_util::rs3_cache()?;
359 let buffer = cache.read(0, 25)?;
360 let hash = test_util::hash(&buffer);
361 assert_eq!(&hash, "81e455fc58fe5ac98fee4df5b78600bbf43e83f7");
362 assert_eq!(buffer.len(), 1576);
363 Ok(())
364 }
365
366 #[test]
367 fn between_single_double() -> crate::Result<()> {
368 let cache = test_util::rs3_cache()?;
369 let buffer = cache.read(7, 0)?;
370
371 let hash = test_util::hash(&buffer);
372 assert_eq!(&hash, "b33919c6e4677abc6ec1c0bdd9557f820a163559");
373 assert_eq!(buffer.len(), 529);
374 Ok(())
375 }
376
377 #[test]
378 fn fails() -> crate::Result<()> {
379 let cache = test_util::rs3_cache()?;
380 assert!(cache.read(2, 25_000).is_err());
381 Ok(())
382 }
383 }
384}
385
386#[cfg(test)]
387mod osrs {
388 use super::test_util;
389 use super::Cache;
390
391 #[test]
392 fn new() {
393 assert!(Cache::new("./data/osrs_cache").is_ok());
394 }
395
396 #[test]
397 fn new_wrong_path() {
398 assert!(Cache::new("./wrong/path").is_err());
399 }
400
401 #[test]
402 fn huffman_table() -> crate::Result<()> {
403 let cache = test_util::osrs_cache()?;
404 let buffer = cache.huffman_table()?;
405
406 let hash = test_util::hash(&buffer);
407 assert_eq!(&hash, "664e89cf25a0af7da138dd0f3904ca79cd1fe767");
408 assert_eq!(buffer.len(), 256);
409
410 Ok(())
411 }
412}
413
414#[cfg(all(test, feature = "rs3"))]
415mod rs3 {
416 use super::test_util;
417 use super::Cache;
418
419 #[test]
420 fn new() {
421 assert!(Cache::new("./data/rs3_cache").is_ok());
422 }
423
424 #[test]
425 fn new_wrong_path() {
426 assert!(Cache::new("./wrong/path").is_err());
427 }
428
429 #[test]
430 fn huffman_table() -> crate::Result<()> {
431 let cache = test_util::rs3_cache()?;
432 let buffer = cache.huffman_table()?;
433
434 let hash = test_util::hash(&buffer);
435 assert_eq!(&hash, "664e89cf25a0af7da138dd0f3904ca79cd1fe767");
436 assert_eq!(buffer.len(), 256);
437
438 Ok(())
439 }
440}