mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-08 05:48:46 +08:00
Add support to read embbed control block (tested game: https://vndb.org/v19829 )
This commit is contained in:
@@ -33,6 +33,8 @@ pub mod psd;
|
||||
pub mod rc4;
|
||||
#[cfg(feature = "utils-serde-base64bytes")]
|
||||
pub mod serde_base64bytes;
|
||||
#[cfg(feature = "utils-simple-pack")]
|
||||
pub mod simple_pack;
|
||||
#[cfg(feature = "utils-str")]
|
||||
pub mod str;
|
||||
pub mod struct_pack;
|
||||
|
||||
100
src/utils/simple_pack.rs
Normal file
100
src/utils/simple_pack.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use crate::ext::io::*;
|
||||
use crate::types::*;
|
||||
use crate::utils::encoding::*;
|
||||
use anyhow::Result;
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
pub struct SimplePack<T: Read> {
|
||||
inner: T,
|
||||
total: u64,
|
||||
current: u64,
|
||||
}
|
||||
|
||||
impl<T: Read> SimplePack<T> {
|
||||
pub fn next<'a>(&'a mut self) -> Result<Option<SimplePackEntry<'a, T>>> {
|
||||
if self.current >= self.total {
|
||||
return Ok(None);
|
||||
}
|
||||
let name = self.read_cstring()?;
|
||||
let name = decode_to_string(Encoding::Utf8, name.as_bytes(), true)?;
|
||||
let entry_size = self.read_u64()?;
|
||||
Ok(Some(SimplePackEntry {
|
||||
pack: self,
|
||||
total: entry_size,
|
||||
current: 0,
|
||||
name,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read> Read for SimplePack<T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let remaining = self.total - self.current;
|
||||
if remaining == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let to_read = std::cmp::min(remaining, buf.len() as u64) as usize;
|
||||
let bytes_read = self.inner.read(&mut buf[..to_read])?;
|
||||
self.current += bytes_read as u64;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SimplePackEntry<'a, T: Read> {
|
||||
pub pack: &'a mut SimplePack<T>,
|
||||
total: u64,
|
||||
current: u64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl<'a, T: Read> Drop for SimplePackEntry<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
let to_skip = self.total - self.current;
|
||||
if to_skip > 0 {
|
||||
if let Err(e) = self.pack.skip(to_skip) {
|
||||
eprintln!("Failed to skip remaining bytes in SimplePackEntry: {}", e);
|
||||
crate::COUNTER.inc_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Read> Read for SimplePackEntry<'a, T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let remaining = self.total - self.current;
|
||||
if remaining == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let to_read = std::cmp::min(remaining, buf.len() as u64) as usize;
|
||||
let bytes_read = self.pack.read(&mut buf[..to_read])?;
|
||||
self.current += bytes_read as u64;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_simple_pack<'a, T: Read + Seek + 'a>(
|
||||
mut reader: T,
|
||||
) -> Result<SimplePack<Box<dyn Read + 'a>>> {
|
||||
reader.read_and_equal(b"SPCK")?;
|
||||
let flags = reader.read_u8()?;
|
||||
// not compressed
|
||||
if flags == 0 {
|
||||
let pos = reader.stream_position()?;
|
||||
let total = reader.stream_length()? - pos;
|
||||
Ok(SimplePack {
|
||||
inner: Box::new(reader),
|
||||
total,
|
||||
current: 0,
|
||||
})
|
||||
} else {
|
||||
let compressed_size = reader.read_u64()?;
|
||||
let uncompressed_size = reader.read_u64()?;
|
||||
let compressed = reader.take(compressed_size);
|
||||
let decompressed = zstd::stream::read::Decoder::new(compressed)?;
|
||||
Ok(SimplePack {
|
||||
inner: Box::new(decompressed),
|
||||
total: uncompressed_size,
|
||||
current: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user