Skip to content

Commit df81b04

Browse files
committed
packfs: support streaming file
1 parent 09f4d16 commit df81b04

File tree

4 files changed

+122
-23
lines changed

4 files changed

+122
-23
lines changed

yaobow/packfs/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![feature(io_error_more)]
22
#![feature(cursor_remaining)]
3+
#![cfg_attr(target_os = "vita", stdarch_arm_neon_intrinsics)]
34

45
pub mod cpk;
56
pub mod fmb;
@@ -8,6 +9,7 @@ pub mod memory_file;
89
pub mod pkg;
910
pub mod plain_fs;
1011
pub mod sfb;
12+
pub mod streaming_file;
1113
pub mod ypk;
1214
pub mod zpk;
1315
pub mod zpkg;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use std::{
2+
io::{Read, Seek},
3+
sync::{Arc, Mutex},
4+
};
5+
6+
use common::SeekRead;
7+
use mini_fs::UserFile;
8+
9+
pub struct StreamingFile {
10+
reader: Arc<Mutex<dyn SeekRead + Send + Sync>>,
11+
position: u64,
12+
start_position: u64,
13+
end_position: u64,
14+
}
15+
16+
impl StreamingFile {
17+
pub fn new(
18+
reader: Arc<Mutex<dyn SeekRead + Send + Sync>>,
19+
start_position: u64,
20+
end_position: u64,
21+
) -> StreamingFile {
22+
Self {
23+
reader,
24+
position: start_position,
25+
start_position,
26+
end_position,
27+
}
28+
}
29+
}
30+
31+
impl UserFile for StreamingFile {}
32+
33+
impl Read for StreamingFile {
34+
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
35+
if self.position >= self.end_position {
36+
return Ok(0);
37+
}
38+
39+
let mut reader = self.reader.lock().unwrap();
40+
reader.seek(std::io::SeekFrom::Start(self.position))?;
41+
let read = reader.read(buf)?;
42+
let read = read.min((self.end_position - self.position) as usize);
43+
self.position += read as u64;
44+
Ok(read)
45+
}
46+
}
47+
48+
impl Seek for StreamingFile {
49+
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
50+
let new_position = match pos {
51+
std::io::SeekFrom::Start(offset) => self.start_position + offset,
52+
std::io::SeekFrom::End(offset) => (self.end_position as i64 + offset) as u64,
53+
std::io::SeekFrom::Current(offset) => (self.position as i64 + offset) as u64,
54+
};
55+
56+
if new_position < self.start_position {
57+
return Err(std::io::Error::new(
58+
std::io::ErrorKind::InvalidInput,
59+
"Seek before start",
60+
));
61+
}
62+
63+
if new_position > self.end_position {
64+
return Err(std::io::Error::new(
65+
std::io::ErrorKind::InvalidInput,
66+
"Seek after end",
67+
));
68+
}
69+
70+
self.position = new_position;
71+
Ok(self.position - self.start_position)
72+
}
73+
}

yaobow/packfs/src/ypk/ypk_archive.rs

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,31 @@
11
use std::{
22
collections::HashMap,
3-
io::{Cursor, Write},
3+
io::{Cursor, Read, Write},
4+
ops::DerefMut,
5+
sync::{Arc, Mutex},
46
};
57

68
use binrw::{binrw, BinRead, BinWrite};
79
use common::{SeekRead, SeekWrite};
10+
use mini_fs::File;
811

9-
use crate::memory_file::MemoryFile;
12+
use crate::{memory_file::MemoryFile, streaming_file::StreamingFile};
1013

1114
pub struct YpkArchive {
12-
reader: Box<dyn SeekRead>,
15+
reader: Arc<Mutex<dyn SeekRead + Send + Sync>>,
1316
pub entries: Vec<YpkEntry>,
1417
entries_hash: HashMap<u64, Vec<usize>>,
1518
}
1619

1720
impl YpkArchive {
18-
pub fn load(mut reader: Box<dyn SeekRead>) -> anyhow::Result<Self> {
19-
let header = YpkHeader::read(&mut reader)?;
21+
pub fn load(file: Arc<Mutex<dyn SeekRead + Send + Sync>>) -> anyhow::Result<Self> {
22+
let mut reader = file.lock().unwrap();
23+
let header = YpkHeader::read(&mut reader.deref_mut())?;
2024

2125
reader.seek(std::io::SeekFrom::Start(header.entry_offset))?;
2226
let mut entries = Vec::with_capacity(header.entry_count as usize);
2327
for _ in 0..header.entry_count {
24-
entries.push(YpkEntry::read(&mut reader)?);
28+
entries.push(YpkEntry::read(&mut reader.deref_mut())?);
2529
}
2630

2731
let mut entries_hash = HashMap::new();
@@ -32,31 +36,44 @@ impl YpkArchive {
3236
.push(i);
3337
}
3438

39+
drop(reader);
40+
3541
Ok(Self {
36-
reader,
42+
reader: file,
3743
entries,
3844
entries_hash,
3945
})
4046
}
4147

42-
pub fn open(&mut self, name: &str) -> std::io::Result<MemoryFile> {
43-
let (offset, actual_size) = {
48+
pub fn open(&mut self, name: &str) -> std::io::Result<File> {
49+
let (offset, actual_size, is_compressed) = {
4450
let entry = self.get_entry(name).ok_or_else(|| {
4551
std::io::Error::new(
4652
std::io::ErrorKind::NotFound,
4753
format!("Entry {:?} not found", name),
4854
)
4955
})?;
5056

51-
(entry.offset, entry.actual_size)
57+
(entry.offset, entry.actual_size, entry.is_compressed == 1)
5258
};
5359

54-
self.reader.seek(std::io::SeekFrom::Start(offset))?;
60+
/*let mut reader = self.reader.lock().unwrap();
61+
reader.seek(std::io::SeekFrom::Start(offset))?;
5562
let mut buf = vec![0; actual_size as usize];
56-
self.reader.read_exact(&mut buf)?;
57-
58-
let buf = zstd::stream::decode_all::<&[u8]>(buf.as_ref());
59-
Ok(MemoryFile::new(Cursor::new(buf.unwrap())))
63+
reader.read_exact(&mut buf)?;*/
64+
65+
let mut streaming =
66+
StreamingFile::new(self.reader.clone(), offset, offset + actual_size as u64);
67+
68+
if is_compressed {
69+
let buf = zstd::stream::decode_all(&mut streaming)?;
70+
return Ok(MemoryFile::new(Cursor::new(buf)).into());
71+
} else {
72+
/*let mut buf = Vec::new();
73+
streaming.read_to_end(&mut buf)?;
74+
return Ok(MemoryFile::new(Cursor::new(buf)).into());*/
75+
return Ok(streaming.into());
76+
}
6077
}
6178

6279
fn get_entry(&self, name: &str) -> Option<&YpkEntry> {
@@ -102,6 +119,7 @@ pub struct YpkEntry {
102119
name: Vec<u8>,
103120

104121
offset: u64,
122+
is_compressed: u32,
105123
original_size: u32,
106124
actual_size: u32,
107125
}
@@ -129,17 +147,22 @@ impl YpkWriter {
129147
let offset = self.writer.stream_position()?;
130148
let original_size = data.len() as u32;
131149

150+
let (is_compressed, data) = if name.ends_with(".bik") {
151+
(false, data.to_vec())
152+
} else {
153+
(true, zstd::stream::encode_all(data, 0)?)
154+
};
155+
132156
let name = normorlize_path(name);
133157
let name_for_hash = name.to_lowercase();
134158
let name = name.as_bytes();
135159

136-
let data = zstd::stream::encode_all(data, 0)?;
137-
138160
self.entries.push(YpkEntry {
139161
hash: xxhash_rust::xxh3::xxh3_64(name_for_hash.as_bytes()),
140162
name_len: name.len() as u32,
141163
name: name.to_vec(),
142164
offset,
165+
is_compressed: is_compressed as u32,
143166
original_size,
144167
actual_size: data.len() as u32,
145168
});

yaobow/packfs/src/ypk/ypk_fs.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
use crate::memory_file::MemoryFile;
2-
31
use mini_fs::{Entries, Store};
4-
use std::{cell::RefCell, path::Path};
2+
use std::{
3+
cell::RefCell,
4+
path::Path,
5+
sync::{Arc, Mutex},
6+
};
57

68
use super::YpkArchive;
79

@@ -12,14 +14,13 @@ pub struct YpkFs {
1214
impl YpkFs {
1315
pub fn new<P: AsRef<Path>>(ypk_path: P) -> anyhow::Result<YpkFs> {
1416
let file = std::fs::File::open(ypk_path.as_ref())?;
15-
let archive = RefCell::new(YpkArchive::load(Box::new(file))?);
16-
17+
let archive = RefCell::new(YpkArchive::load(Arc::new(Mutex::new(file)))?);
1718
Ok(YpkFs { archive })
1819
}
1920
}
2021

2122
impl Store for YpkFs {
22-
type File = MemoryFile;
23+
type File = mini_fs::File;
2324

2425
fn open_path(&self, path: &Path) -> std::io::Result<Self::File> {
2526
self.archive.borrow_mut().open(path.to_str().unwrap())

0 commit comments

Comments
 (0)