#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(
clippy::all,
clippy::correctness,
clippy::suspicious,
clippy::style,
clippy::complexity,
clippy::perf
)]
#[macro_use]
pub mod util;
pub mod checksum;
pub mod definition;
pub mod error;
pub mod extension;
pub mod loader;
#[doc(inline)]
pub use error::Error;
use error::Result;
use checksum::Checksum;
#[cfg(feature = "rs3")]
use checksum::{RsaChecksum, RsaKeys};
use runefs::codec::{Buffer, Decoded, Encoded};
use runefs::error::{Error as RuneFsError, ReadError};
use runefs::{ArchiveRef, Dat2, Indices, MAIN_DATA};
use std::{io::Write, path::Path};
#[derive(Debug)]
pub struct Cache {
pub(crate) data: Dat2,
pub(crate) indices: Indices,
}
impl Cache {
pub fn new<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
Ok(Self {
data: Dat2::new(path.as_ref().join(MAIN_DATA))?,
indices: Indices::new(path)?,
})
}
pub fn checksum(&self) -> crate::Result<Checksum> {
Checksum::new(self)
}
#[cfg(feature = "rs3")]
#[cfg_attr(docsrs, doc(cfg(feature = "rs3")))]
pub fn checksum_with<'a>(&self, keys: RsaKeys<'a>) -> crate::Result<RsaChecksum<'a>> {
RsaChecksum::with_keys(self, keys)
}
pub fn read(&self, index_id: u8, archive_id: u32) -> crate::Result<Buffer<Encoded>> {
let index = self
.indices
.get(&index_id)
.ok_or(RuneFsError::Read(ReadError::IndexNotFound(index_id)))?;
let archive = index
.archive_refs
.get(&archive_id)
.ok_or(RuneFsError::Read(ReadError::ArchiveNotFound {
idx: index_id,
arc: archive_id,
}))?;
let buffer = self.data.read(archive)?;
assert_eq!(buffer.len(), archive.length);
Ok(buffer)
}
pub(crate) fn read_archive(&self, archive: &ArchiveRef) -> crate::Result<Buffer<Encoded>> {
self.read(archive.index_id, archive.id)
}
pub fn read_into_writer<W: Write>(
&self,
index_id: u8,
archive_id: u32,
writer: &mut W,
) -> crate::Result<()> {
let index = self
.indices
.get(&index_id)
.ok_or(RuneFsError::Read(ReadError::IndexNotFound(index_id)))?;
let archive = index
.archive_refs
.get(&archive_id)
.ok_or(RuneFsError::Read(ReadError::ArchiveNotFound {
idx: index_id,
arc: archive_id,
}))?;
Ok(self.data.read_into_writer(archive, writer)?)
}
pub fn huffman_table(&self) -> crate::Result<Buffer<Decoded>> {
let index_id = 10;
let archive = self.archive_by_name(index_id, "huffman")?;
let buffer = self.read_archive(archive)?;
assert_eq!(buffer.len(), archive.length);
Ok(buffer.decode()?)
}
pub(crate) fn archive_by_name<T: AsRef<str>>(
&self,
index_id: u8,
name: T,
) -> crate::Result<&ArchiveRef> {
let index = self
.indices
.get(&index_id)
.ok_or(RuneFsError::Read(ReadError::IndexNotFound(index_id)))?;
let hash = util::djd2::hash(&name);
let archive = index
.metadata
.iter()
.find(|archive| archive.name_hash == hash)
.ok_or_else(|| crate::error::NameHashMismatch {
hash,
name: name.as_ref().into(),
idx: index_id,
})?;
let archive_ref = index
.archive_refs
.get(&archive.id)
.ok_or(RuneFsError::Read(ReadError::ArchiveNotFound {
idx: index_id,
arc: archive.id,
}))?;
Ok(archive_ref)
}
}
#[cfg(test)]
fn is_normal<T: Send + Sync + Sized + Unpin>() {}
#[test]
fn normal_types() {
is_normal::<Cache>();
}