summaryrefslogtreecommitdiff
path: root/shared/src/respack.rs
diff options
context:
space:
mode:
Diffstat (limited to 'shared/src/respack.rs')
-rw-r--r--shared/src/respack.rs123
1 files changed, 83 insertions, 40 deletions
diff --git a/shared/src/respack.rs b/shared/src/respack.rs
index 8c0b9d8..dee0cd0 100644
--- a/shared/src/respack.rs
+++ b/shared/src/respack.rs
@@ -18,6 +18,7 @@ use crate::{packets::Resource, resources::RespackEntry, store::ResourceStore};
use anyhow::{Result, bail};
use log::{info, warn};
use std::{
+ collections::HashMap,
io::{Read, Seek, SeekFrom, Write},
marker::PhantomData,
};
@@ -49,59 +50,101 @@ pub fn save_respack(
Ok(())
}
+/// Copies the entire respack to the store. This is usually a dumb idea because the pack supportes on-demand reading.
pub fn load_respack(
- mut input: impl Read + Seek,
+ input: impl Read + Seek,
store: &ResourceStore,
) -> Result<Option<Resource<RespackEntry>>> {
- let mut magic = [0u8; MAGIC.len()];
- input.read_exact(&mut magic)?;
- if magic != *MAGIC {
- bail!("wrong magic bytes");
- }
- let mut entry = [0u8; 32];
- input.read_exact(&mut entry)?;
- let entry = if entry != [0u8; 32] {
- Some(Resource(entry, PhantomData))
- } else {
- None
- };
-
- let mut count = [0u8; size_of::<u64>()];
- input.read_exact(&mut count)?;
- let count = u64::from_be_bytes(count);
-
+ let mut pack = RespackReader::open(input)?;
let mut load_queue = Vec::new();
- let mut found_entry = false;
- for _ in 0..count {
- let mut res = [0u8; 32];
- let mut off = [0u8; size_of::<u64>()];
- let mut size = [0u8; size_of::<u64>()];
- input.read_exact(&mut res)?;
- input.read_exact(&mut off)?;
- input.read_exact(&mut size)?;
-
- found_entry |= Some(Resource(res, PhantomData)) == entry;
- if store.get_raw_size(Resource(res, PhantomData))?.is_none() {
- load_queue.push((res, u64::from_be_bytes(off), u64::from_be_bytes(size)))
+ for res in pack.index.keys() {
+ if store.get_raw_size(*res)?.is_none() {
+ load_queue.push(*res);
}
}
- if !found_entry && entry.is_some() {
- warn!("respack does not contain its entry resource")
- }
info!(
- "loading {} of {count} resources from pack",
+ "loading {} of {} resources from pack",
load_queue.len(),
+ pack.index.len()
);
-
- for (res, off, size) in load_queue {
- input.seek(SeekFrom::Start(off))?;
+ for res in load_queue {
let mut buf = Vec::new();
- input.by_ref().take(size).read_to_end(&mut buf)?;
+ pack.read(res)?.unwrap().read_to_end(&mut buf)?;
let key = store.set_raw(&buf)?;
- if key.0 != res {
+ if key != res {
warn!("respack containes mislabeled resources")
}
}
- Ok(entry)
+ Ok(pack.entry)
+}
+
+pub struct RespackReader<T> {
+ entry: Option<Resource<RespackEntry>>,
+ index: HashMap<Resource, (u64, u64)>,
+ inner: T,
+}
+impl<T: Read + Seek> RespackReader<T> {
+ pub fn open(mut inner: T) -> Result<Self> {
+ let mut magic = [0u8; MAGIC.len()];
+ inner.read_exact(&mut magic)?;
+ if magic != *MAGIC {
+ bail!("wrong magic bytes");
+ }
+ let mut entry = [0u8; 32];
+ inner.read_exact(&mut entry)?;
+ let entry = if entry != [0u8; 32] {
+ Some(Resource(entry, PhantomData))
+ } else {
+ None
+ };
+
+ let mut count = [0u8; size_of::<u64>()];
+ inner.read_exact(&mut count)?;
+ let count = u64::from_be_bytes(count);
+
+ let mut index = HashMap::new();
+ let mut found_entry = false;
+ for _ in 0..count {
+ let mut res = [0u8; 32];
+ let mut off = [0u8; size_of::<u64>()];
+ let mut size = [0u8; size_of::<u64>()];
+ inner.read_exact(&mut res)?;
+ inner.read_exact(&mut off)?;
+ inner.read_exact(&mut size)?;
+
+ found_entry |= Some(Resource(res, PhantomData)) == entry;
+ index.insert(
+ Resource(res, PhantomData),
+ (u64::from_be_bytes(off), u64::from_be_bytes(size)),
+ );
+ }
+ if !found_entry && entry.is_some() {
+ warn!("respack does not contain its entry resource")
+ }
+ info!("opened respack with {} resources", index.len());
+ Ok(Self {
+ entry,
+ index,
+ inner,
+ })
+ }
+ pub fn entry(&self) -> Option<Resource<RespackEntry>> {
+ self.entry.clone()
+ }
+ pub fn get_size(&self, key: Resource) -> Option<usize> {
+ self.index.get(&key).map(|(_off, size)| *size as usize)
+ }
+ pub fn iter(&self, mut cb: impl FnMut(Resource, usize)) {
+ for (r, (_, s)) in &self.index {
+ cb(*r, *s as usize)
+ }
+ }
+ pub fn read(&mut self, key: Resource) -> Result<Option<impl Read>> {
+ let Some((off, size)) = self.index.get(&key).copied() else {
+ return Ok(None);
+ };
+ self.inner.seek(SeekFrom::Start(off))?;
+ Ok(Some(self.inner.by_ref().take(size)))
+ }
}