1
Fork 0
mirror of https://github.com/redstrate/Physis.git synced 2025-04-26 06:07:45 +00:00
physis/src/sqpack.rs

89 lines
3 KiB
Rust
Raw Normal View History

2022-07-19 19:29:41 -04:00
use crate::compression::no_header_decompress;
2022-12-17 08:23:19 -05:00
use crate::crc::Jamcrc;
2022-07-19 19:29:41 -04:00
use crate::dat::{BlockHeader, CompressionMode};
use binrw::BinRead;
2022-08-16 11:52:07 -04:00
use std::io::{Read, Seek, SeekFrom};
2022-07-19 19:29:41 -04:00
2022-12-17 08:23:19 -05:00
const CRC: Jamcrc = Jamcrc::new();
2022-07-19 19:29:41 -04:00
/// Calculates a hash for `index` files from a game path.
pub fn calculate_hash(path: &str) -> u64 {
let lowercase = path.to_lowercase();
let pos = lowercase.rfind('/').unwrap();
let (directory, filename) = lowercase.split_at(pos);
let directory_crc = CRC.checksum(directory.as_bytes());
let filename_crc = CRC.checksum(filename[1..filename.len()].as_bytes());
2022-07-19 19:29:41 -04:00
(directory_crc as u64) << 32 | (filename_crc as u64)
}
2022-08-16 11:52:07 -04:00
pub fn read_data_block<T: Read + Seek>(mut buf: T, starting_position: u64) -> Option<Vec<u8>> {
2022-07-19 19:29:41 -04:00
buf.seek(SeekFrom::Start(starting_position)).ok()?;
let block_header = BlockHeader::read(&mut buf).unwrap();
match block_header.compression {
2022-08-16 11:52:07 -04:00
CompressionMode::Compressed {
compressed_length,
decompressed_length,
} => {
2022-07-19 19:29:41 -04:00
let mut compressed_data: Vec<u8> = vec![0; compressed_length as usize];
buf.read_exact(&mut compressed_data).ok()?;
let mut decompressed_data: Vec<u8> = vec![0; decompressed_length as usize];
if !no_header_decompress(&mut compressed_data, &mut decompressed_data) {
return None;
}
Some(decompressed_data)
}
CompressionMode::Uncompressed { file_size } => {
let mut local_data: Vec<u8> = vec![0; file_size as usize];
buf.read_exact(&mut local_data).ok()?;
Some(local_data)
}
}
}
/// A fixed version of read_data_block accounting for differing compressed block sizes in ZiPatch files.
2022-08-16 11:52:07 -04:00
pub fn read_data_block_patch<T: Read + Seek>(mut buf: T) -> Option<Vec<u8>> {
2022-07-19 19:29:41 -04:00
let block_header = BlockHeader::read(&mut buf).unwrap();
match block_header.compression {
2022-08-16 11:52:07 -04:00
CompressionMode::Compressed {
compressed_length,
decompressed_length,
} => {
let compressed_length: usize =
((compressed_length as usize + 143) & 0xFFFFFF80) - (block_header.size as usize);
2022-07-19 19:29:41 -04:00
let mut compressed_data: Vec<u8> = vec![0; compressed_length as usize];
buf.read_exact(&mut compressed_data).ok()?;
let mut decompressed_data: Vec<u8> = vec![0; decompressed_length as usize];
if !no_header_decompress(&mut compressed_data, &mut decompressed_data) {
return None;
}
Some(decompressed_data)
}
CompressionMode::Uncompressed { file_size } => {
2022-08-16 11:52:07 -04:00
let new_file_size: usize = (file_size as usize + 143) & 0xFFFFFF80;
2022-07-19 19:29:41 -04:00
let mut local_data: Vec<u8> = vec![0; file_size as usize];
buf.read_exact(&mut local_data).ok()?;
2022-08-16 11:52:07 -04:00
buf.seek(SeekFrom::Current(
(new_file_size as usize - block_header.size as usize - file_size as usize) as i64,
))
.ok()?;
2022-07-19 19:29:41 -04:00
Some(local_data)
}
}
}