diff options
author | metamuffin <metamuffin@disroot.org> | 2025-02-10 12:15:55 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-02-10 12:15:55 +0100 |
commit | d786df60b89e52c5e4a605f95c677f4bce4c6ec3 (patch) | |
tree | 3d39b967c91c964de458fdf28297c8fb52d1688c | |
parent | bc5c636a61411d8c29e64223a7d04263f2e68669 (diff) | |
download | unity-tools-d786df60b89e52c5e4a605f95c677f4bce4c6ec3.tar unity-tools-d786df60b89e52c5e4a605f95c677f4bce4c6ec3.tar.bz2 unity-tools-d786df60b89e52c5e4a605f95c677f4bce4c6ec3.tar.zst |
start work on serialized files
-rw-r--r-- | src/helper.rs | 76 | ||||
-rw-r--r-- | src/main.rs | 93 | ||||
-rw-r--r-- | src/unityfs.rs | 18 |
3 files changed, 171 insertions, 16 deletions
diff --git a/src/helper.rs b/src/helper.rs index 79c2872..c2b9a92 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -1,28 +1,104 @@ use std::io::{Read, Result}; +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Endianness { + Big, + Little, +} + pub trait ReadExt { + fn read_u8(&mut self) -> Result<u8>; fn read_u16_be(&mut self) -> Result<u16>; + fn read_i16(&mut self, e: Endianness) -> Result<i16>; + fn read_i16_be(&mut self) -> Result<i16>; + fn read_i16_le(&mut self) -> Result<i16>; + fn read_i32(&mut self, e: Endianness) -> Result<i32>; + fn read_i32_be(&mut self) -> Result<i32>; + fn read_i32_le(&mut self) -> Result<i32>; + fn read_u32(&mut self, e: Endianness) -> Result<u32>; fn read_u32_be(&mut self) -> Result<u32>; + fn read_u32_le(&mut self) -> Result<u32>; + fn read_u64(&mut self, e: Endianness) -> Result<u64>; fn read_u64_be(&mut self) -> Result<u64>; + fn read_u64_le(&mut self) -> Result<u64>; fn read_u128_be(&mut self) -> Result<u128>; fn read_cstr(&mut self) -> Result<String>; } impl<T: Read> ReadExt for T { + fn read_u8(&mut self) -> Result<u8> { + let mut buf = [0; 2]; + self.read_exact(&mut buf)?; + Ok(buf[0]) + } fn read_u16_be(&mut self) -> Result<u16> { let mut buf = [0; 2]; self.read_exact(&mut buf)?; Ok(u16::from_be_bytes(buf)) } + fn read_i16(&mut self, e: Endianness) -> Result<i16> { + match e { + Endianness::Big => self.read_i16_be(), + Endianness::Little => self.read_i16_le(), + } + } + fn read_i16_be(&mut self) -> Result<i16> { + let mut buf = [0; 2]; + self.read_exact(&mut buf)?; + Ok(i16::from_be_bytes(buf)) + } + fn read_i16_le(&mut self) -> Result<i16> { + let mut buf = [0; 2]; + self.read_exact(&mut buf)?; + Ok(i16::from_le_bytes(buf)) + } + fn read_i32(&mut self, e: Endianness) -> Result<i32> { + match e { + Endianness::Big => self.read_i32_be(), + Endianness::Little => self.read_i32_le(), + } + } + fn read_i32_be(&mut self) -> Result<i32> { + let mut buf = [0; 4]; + self.read_exact(&mut buf)?; + Ok(i32::from_be_bytes(buf)) + } + fn read_i32_le(&mut self) -> Result<i32> { + let mut buf = [0; 4]; + self.read_exact(&mut buf)?; + Ok(i32::from_le_bytes(buf)) + } + fn read_u32(&mut self, e: Endianness) -> Result<u32> { + match e { + Endianness::Big => self.read_u32_be(), + Endianness::Little => self.read_u32_le(), + } + } fn read_u32_be(&mut self) -> Result<u32> { let mut buf = [0; 4]; self.read_exact(&mut buf)?; Ok(u32::from_be_bytes(buf)) } + fn read_u32_le(&mut self) -> Result<u32> { + let mut buf = [0; 4]; + self.read_exact(&mut buf)?; + Ok(u32::from_le_bytes(buf)) + } + fn read_u64(&mut self, e: Endianness) -> Result<u64> { + match e { + Endianness::Big => self.read_u64_be(), + Endianness::Little => self.read_u64_le(), + } + } fn read_u64_be(&mut self) -> Result<u64> { let mut buf = [0; 8]; self.read_exact(&mut buf)?; Ok(u64::from_be_bytes(buf)) } + fn read_u64_le(&mut self) -> Result<u64> { + let mut buf = [0; 8]; + self.read_exact(&mut buf)?; + Ok(u64::from_le_bytes(buf)) + } fn read_u128_be(&mut self) -> Result<u128> { let mut buf = [0; 16]; self.read_exact(&mut buf)?; diff --git a/src/main.rs b/src/main.rs index a23bdcd..c1dcfd2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,13 @@ +use log::debug; use std::{ env::args, fs::File, - io::{BufReader, copy}, + io::{BufReader, Read}, +}; +use unity_tools::{ + helper::{Endianness, ReadExt}, + unityfs::UnityFS, }; -use unity_tools::unityfs::UnityFS; fn main() -> anyhow::Result<()> { env_logger::init_from_env("LOG"); @@ -11,9 +15,88 @@ fn main() -> anyhow::Result<()> { let mut fs = UnityFS::open(file)?; for node in fs.nodes().to_vec() { - let mut reader = fs.read(&node)?; - let mut writer = File::create(format!("/tmp/{}", node.name))?; - copy(&mut reader, &mut writer)?; + if node.name.ends_with(".resource") || node.name.ends_with("resS") { + continue; + } + let mut cab = fs.read(&node)?; + // let mut writer = File::create(format!("/tmp/{}", node.name))?; + // copy(&mut cab, &mut writer)?; + // continue; + + let mut metadata_size = cab.read_u32_be()?; + let mut file_size = cab.read_u32_be()? as u64; + let format = cab.read_u32_be()?; + let mut data_offset = cab.read_u32_be()? as u64; + + debug!("format={format}"); + + assert!(format >= 9); + let e = match cab.read_u32_be()? { + 0 => Endianness::Little, + _ => Endianness::Big, + }; + debug!("endianess={e:?}"); + + if format >= 22 { + metadata_size = cab.read_u32(e)?; + file_size = cab.read_u64(e)?; + data_offset = cab.read_u64(e)?; + cab.read_u64(e)?; + } + debug!("metadata_size={metadata_size}"); + debug!("file_size={file_size}"); + debug!("data_offset={data_offset}"); + + let generator_version = cab.read_cstr()?; + let target_platform = cab.read_u32_le()?; + debug!("generator_version={generator_version:?}"); + debug!("target_platform={target_platform}"); + + let has_type_trees = cab.read_u8()? != 0; + let num_types = cab.read_u32(e)?; + + for _ in 0..num_types { + let mut class_id = cab.read_i32(e)?; + let stripped_type = cab.read_u8()? != 0; + let script_id = cab.read_i16(e)?; + if class_id == 114 { + if script_id >= 0 { + class_id = -2 - script_id as i32; + } else { + class_id = -1; + } + } + eprintln!("class_id={class_id}"); + eprintln!("stripped_type={stripped_type}"); + eprintln!("script_id={script_id}"); + + let hash = if class_id < 0 { + (cab.read_u128_be()?, cab.read_u128_be()?) + } else { + (cab.read_u128_be()?, 0) + }; + eprintln!("{hash:032x?}"); + + if has_type_trees { + let num_nodes = cab.read_u32(e)?; + eprintln!("tree:num_nodes={num_nodes}"); + let size = cab.read_u32(e)?; + assert!(format >= 19); + for _ in 0..num_nodes { + cab.read_u32(e)?; + } + let mut data = vec![0u8; size as usize]; + cab.read_exact(&mut data)?; + } + + if format > 21 { + cab.read_u32_be()?; + } + } + + // let num_objects = cab.read_u32_le()?; + // debug!("num_objects={num_objects}"); + // for _ in 0..num_objects {} } Ok(()) diff --git a/src/unityfs.rs b/src/unityfs.rs index 0d5668c..d106ce6 100644 --- a/src/unityfs.rs +++ b/src/unityfs.rs @@ -1,10 +1,7 @@ use crate::helper::ReadExt; use anyhow::{Result, anyhow, bail}; use log::{debug, info, trace}; -use std::{ - fs::File, - io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Take, Write}, -}; +use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Take}; pub struct UnityFS<T> { nodes: Vec<NodeInfo>, @@ -165,7 +162,6 @@ impl<T: Read> BlocksReader<T> { trace!("loading block {}", self.nblock_index); let block = &self.blocks[self.nblock_index]; let mut comp_buf = vec![0; block.comp_size as usize]; - File::create("/tmp/a")?.write_all(&comp_buf)?; self.inner.read_exact(&mut comp_buf)?; let decomp_buf = block .comp_scheme @@ -264,14 +260,14 @@ impl CompressionScheme { r.read_to_end(&mut buf)?; Ok(buf) } - // CompressionScheme::LZ4HC | CompressionScheme::LZ4 => { - // Ok(lz4_flex::block::decompress(&block, decomp_size).context("lz4 decomp")?) - // } CompressionScheme::LZ4HC | CompressionScheme::LZ4 => { - File::create("/tmp/a")?.write_all(&block)?; - Ok(lz4::block::decompress(&block, Some(decomp_size as i32))?) - // Ok(lz4::block::decompress(&block, None)?) + Ok(lz4_flex::block::decompress(&block, decomp_size)?) } + // CompressionScheme::LZ4HC | CompressionScheme::LZ4 => { + // File::create("/tmp/a")?.write_all(&block)?; + // Ok(lz4::block::decompress(&block, Some(decomp_size as i32))?) + // Ok(lz4::block::decompress(&block, None)?) + // } CompressionScheme::LZHAM => todo!(), } } |