mirror of
https://github.com/Theaninova/mhlib.git
synced 2025-12-12 12:36:17 +00:00
add archive tests
This commit is contained in:
@@ -31,7 +31,7 @@ Support of games primarily depends on who developed them - Games with structural
|
|||||||
* [x] Moorhuhn Schatzjäger 2
|
* [x] Moorhuhn Schatzjäger 2
|
||||||
* [x] Moorhuhn Schatzjäger 3
|
* [x] Moorhuhn Schatzjäger 3
|
||||||
* [ ] Moorhuhn Invasion
|
* [ ] Moorhuhn Invasion
|
||||||
* `.sar` Starforce 3D Engine (Visual Imagination Software "VIS" GbR)
|
* `.sar` Starforce 3D Engine (Visual Imagination Software "VIS" GbR): LightWave 3D + Open Dynamics Engine + CEGUI
|
||||||
* [ ] Moorhuhn Kart 3
|
* [ ] Moorhuhn Kart 3
|
||||||
* [ ] Moorhuhn Director's Cut
|
* [ ] Moorhuhn Director's Cut
|
||||||
* [ ] Moorhuhn Kart Thunder
|
* [ ] Moorhuhn Kart Thunder
|
||||||
|
|||||||
14
rust/Cargo.lock
generated
14
rust/Cargo.lock
generated
@@ -346,6 +346,13 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mhex"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"starforcelib",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
@@ -583,6 +590,13 @@ dependencies = [
|
|||||||
"serde-xml-rs",
|
"serde-xml-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "starforcelib"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"binrw",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "1.0.109"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = ["renderwarelib", "springylib"]
|
members = ["renderwarelib", "springylib", "starforcelib", "mhex"]
|
||||||
|
|||||||
9
rust/lightwave/Cargo.toml
Normal file
9
rust/lightwave/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "lightwave"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
binrw = "0.11.1"
|
||||||
14
rust/lightwave/src/lib.rs
Normal file
14
rust/lightwave/src/lib.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
pub fn add(left: usize, right: usize) -> usize {
|
||||||
|
left + right
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let result = add(2, 2);
|
||||||
|
assert_eq!(result, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
rust/mhex/Cargo.toml
Normal file
9
rust/mhex/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "mhex"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
starforcelib = {path = "../starforcelib"}
|
||||||
6
rust/mhex/src/main.rs
Normal file
6
rust/mhex/src/main.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
use starforcelib::sarc::SarcArchive;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let path = "E:\\Games\\Moorhuhn Kart 3\\data.sar";
|
||||||
|
SarcArchive::extract_all(path).unwrap();
|
||||||
|
}
|
||||||
1
rust/starforcelib/.gitignore
vendored
Normal file
1
rust/starforcelib/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
target/
|
||||||
7
rust/starforcelib/Cargo.toml
Normal file
7
rust/starforcelib/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "starforcelib"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
binrw = "0.11.1"
|
||||||
1
rust/starforcelib/src/lib.rs
Normal file
1
rust/starforcelib/src/lib.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod sarc;
|
||||||
121
rust/starforcelib/src/sarc.rs
Normal file
121
rust/starforcelib/src/sarc.rs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
use binrw::prelude::*;
|
||||||
|
use binrw::{BinRead, PosValue};
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
use std::fs;
|
||||||
|
use std::fs::{File, OpenOptions};
|
||||||
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[binrw]
|
||||||
|
#[brw(little, magic = b"SARC")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SarcArchive {
|
||||||
|
pub version: u32,
|
||||||
|
#[br(temp)]
|
||||||
|
#[bw(calc = files.len() as u32)]
|
||||||
|
pub count: u32,
|
||||||
|
#[br(count = count)]
|
||||||
|
pub files: Vec<FilePointer>,
|
||||||
|
#[bw(ignore)]
|
||||||
|
pub position: PosValue<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[binrw]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FilePointer {
|
||||||
|
#[br(temp)]
|
||||||
|
#[bw(calc = path.len() as u8)]
|
||||||
|
pub path_len: u8,
|
||||||
|
#[br(count = path_len, map = |v| String::from_utf8(v).unwrap(), pad_after = 1)]
|
||||||
|
#[bw(map = |s| s.as_bytes())]
|
||||||
|
pub path: String,
|
||||||
|
pub position: u32,
|
||||||
|
pub size: u32,
|
||||||
|
#[br(assert(size == size_2), temp)]
|
||||||
|
#[bw(calc = *size)]
|
||||||
|
pub size_2: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for SarcArchive {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(f, "v{}", self.version)?;
|
||||||
|
for file in self.files.iter() {
|
||||||
|
writeln!(f, "{}", file)?;
|
||||||
|
}
|
||||||
|
writeln!(f, "=> {:#x}", self.position.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for FilePointer {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} => {:#x}..+{:#x}",
|
||||||
|
self.path, self.position, self.size
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SarcArchive {
|
||||||
|
pub fn read_file(path: &str) -> std::io::Result<SarcArchive> {
|
||||||
|
let mut file = File::open(path)?;
|
||||||
|
SarcArchive::read(&mut file)
|
||||||
|
.map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<R>(file: &mut R) -> BinResult<SarcArchive>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
BinRead::read(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract<R>(&self, file: &mut R, path: &str) -> std::io::Result<Vec<u8>>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
self.files
|
||||||
|
.iter()
|
||||||
|
.find(|it| it.path.as_str() == path)
|
||||||
|
.ok_or(std::io::Error::new(std::io::ErrorKind::NotFound, path))
|
||||||
|
.and_then(|ptr| ptr.extract(file, self.position.pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_all(path: &str) -> std::io::Result<()> {
|
||||||
|
let info = SarcArchive::read_file(path)?;
|
||||||
|
let mut file = File::open(path)?;
|
||||||
|
let dir = Path::new(path);
|
||||||
|
|
||||||
|
for ptr in info.files {
|
||||||
|
let out_path = dir.with_file_name(format!("extract\\{}", ptr.path.replace(':', "")));
|
||||||
|
|
||||||
|
println!("Extracting: {}", ptr.path);
|
||||||
|
println!(" ↳ {}", out_path.to_str().unwrap());
|
||||||
|
|
||||||
|
fs::create_dir_all(out_path.with_file_name(""))?;
|
||||||
|
|
||||||
|
let mut data = ptr
|
||||||
|
.extract(&mut file, info.position.pos)
|
||||||
|
.map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
|
||||||
|
let mut output = OpenOptions::new()
|
||||||
|
.create_new(true)
|
||||||
|
.write(true)
|
||||||
|
.open(out_path)?;
|
||||||
|
output.write_all(data.as_mut_slice())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FilePointer {
|
||||||
|
fn extract<R>(&self, file: &mut R, offset: u64) -> std::io::Result<Vec<u8>>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
file.seek(SeekFrom::Start(self.position as u64 + offset))?;
|
||||||
|
let mut data = vec![0u8; self.size as usize];
|
||||||
|
file.read_exact(data.as_mut_slice())?;
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user