aboutsummaryrefslogtreecommitdiff
path: root/src/unityfs/multi_reader.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-03-15 15:18:40 +0100
committermetamuffin <metamuffin@disroot.org>2025-03-15 15:18:40 +0100
commitd836e24357b81496c61f3cc9195ba36758523578 (patch)
tree0028aee5a453cc761dd39e92430a35c55147537f /src/unityfs/multi_reader.rs
parent07fc3656274117c211ca0d6a54926d390a4d9b68 (diff)
downloadunity-tools-d836e24357b81496c61f3cc9195ba36758523578.tar
unity-tools-d836e24357b81496c61f3cc9195ba36758523578.tar.bz2
unity-tools-d836e24357b81496c61f3cc9195ba36758523578.tar.zst
more abstraction around unityfs to read multiple files from a single reader
Diffstat (limited to 'src/unityfs/multi_reader.rs')
-rw-r--r--src/unityfs/multi_reader.rs50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/unityfs/multi_reader.rs b/src/unityfs/multi_reader.rs
new file mode 100644
index 0000000..3de6cd5
--- /dev/null
+++ b/src/unityfs/multi_reader.rs
@@ -0,0 +1,50 @@
+use std::{
+ io::{Read, Seek, SeekFrom},
+ sync::{Arc, Mutex},
+};
+
+use anyhow::Result;
+
+pub struct MultiReader<T> {
+ position: u64,
+ inner: Arc<Mutex<(u64, T)>>,
+}
+impl<T: Seek> MultiReader<T> {
+ pub fn new(mut inner: T) -> Result<Self> {
+ let position = inner.stream_position()?;
+ Ok(Self {
+ position,
+ inner: Arc::new(Mutex::new((position, inner))),
+ })
+ }
+}
+impl<T> Clone for MultiReader<T> {
+ fn clone(&self) -> Self {
+ Self {
+ position: self.position,
+ inner: self.inner.clone(),
+ }
+ }
+}
+impl<T: Read + Seek> Read for MultiReader<T> {
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ let mut g = self.inner.lock().unwrap();
+ if g.0 != self.position {
+ g.1.seek(SeekFrom::Start(self.position))?;
+ }
+ let size = g.1.read(buf)?;
+ g.0 += size as u64;
+ self.position += size as u64;
+ Ok(size)
+ }
+}
+impl<T: Seek> Seek for MultiReader<T> {
+ fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
+ self.position = match pos {
+ SeekFrom::Start(x) => x,
+ SeekFrom::Current(x) => self.position.saturating_add_signed(x),
+ SeekFrom::End(_) => unimplemented!(),
+ };
+ Ok(self.position)
+ }
+}