aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/helper.rs76
-rw-r--r--src/main.rs93
-rw-r--r--src/unityfs.rs18
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!(),
}
}