mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-07 05:18:44 +08:00
111 lines
3.0 KiB
Rust
111 lines
3.0 KiB
Rust
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> SimplePackEntry<'a, T> {
|
|
pub fn total_size(&self) -> u64 {
|
|
self.total
|
|
}
|
|
|
|
pub fn is_eof(&self) -> bool {
|
|
self.current >= self.total
|
|
}
|
|
}
|
|
|
|
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,
|
|
})
|
|
}
|
|
}
|