aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs111
1 files changed, 67 insertions, 44 deletions
diff --git a/src/main.rs b/src/main.rs
index eb131dd..5ba3e3a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,13 +2,15 @@ pub mod helper;
use anyhow::{Result, anyhow};
use helper::ReadExt;
+use log::{debug, info};
use std::{
env::args,
fs::File,
- io::{BufReader, Cursor, Read, Seek, SeekFrom},
+ io::{BufReader, Cursor, Read, Seek, SeekFrom, Write, copy},
};
fn main() -> anyhow::Result<()> {
+ env_logger::init_from_env("LOG");
let mut file = BufReader::new(File::open(args().nth(1).unwrap())?);
let signature = file.read_cstr()?;
@@ -16,79 +18,98 @@ fn main() -> anyhow::Result<()> {
let player_version = file.read_cstr()?;
let unity_version = file.read_cstr()?;
let size = file.read_u64_be()?;
- let meta_comp_size = file.read_u32_be()?;
- let meta_decomp_size = file.read_u32_be()?;
+ let blockindex_comp_size = file.read_u32_be()?;
+ let blockindex_decomp_size = file.read_u32_be()?;
let flags = file.read_u32_be()?;
let meta_comp_scheme = CompressionScheme::from_flag_num((flags & 0x3f) as u8)
.ok_or(anyhow!("unknown block compression"))?;
- let eof_meta = flags & 0x80 != 0;
+ let blockindex_eof = flags & 0x80 != 0;
+ let blockindex_has_directory = flags & 0x40 != 0;
+ let blockindex_need_padding = flags & 0x200 != 0;
- eprintln!("signature={signature:?}");
- eprintln!("file_version={file_version:?}");
- eprintln!("player_version={player_version:?}");
- eprintln!("unity_version={unity_version:?}");
- eprintln!("size={size:?}");
- eprintln!("meta_comp_size={meta_comp_size:?}");
- eprintln!("meta_decomp_size={meta_decomp_size:?}");
- eprintln!("flags={flags:?}");
- eprintln!("meta_comp_scheme={meta_comp_scheme:?}");
- eprintln!("eof_meta={eof_meta:?}");
+ info!("signature={signature:?}");
+ info!("file_version={file_version:?}");
+ info!("player_version={player_version:?}");
+ info!("unity_version={unity_version:?}");
+ debug!("size={size:?}");
+ debug!("meta_comp_size={blockindex_comp_size:?}");
+ debug!("meta_decomp_size={blockindex_decomp_size:?}");
+ debug!("flags={flags:?}");
+ debug!("meta_comp_scheme={meta_comp_scheme:?}");
+ debug!("blockindex_eof={blockindex_eof:?}");
+ debug!("blockindex_has_directory={blockindex_has_directory:?}");
+ debug!("blockindex_need_padding={blockindex_need_padding:?}");
- let restore_position = if eof_meta {
- let pos = file.stream_position()?;
- file.seek(SeekFrom::End(-(meta_comp_size as i64)))?;
- Some(pos)
- } else {
- None
- };
+ let mut blockindex = {
+ let restore_position = if blockindex_eof {
+ let pos = file.stream_position()?;
+ file.seek(SeekFrom::End(-(blockindex_comp_size as i64)))?;
+ Some(pos)
+ } else {
+ None
+ };
- let mut block = vec![0u8; meta_comp_size as usize];
- file.read_exact(&mut block)?;
+ let mut blockindex = vec![0u8; blockindex_comp_size as usize];
+ file.read_exact(&mut blockindex)?;
- if let Some(pos) = restore_position {
- file.seek(SeekFrom::Start(pos))?;
+ if let Some(pos) = restore_position {
+ file.seek(SeekFrom::Start(pos))?;
+ }
+ let blockindex =
+ meta_comp_scheme.decompress(blockindex, blockindex_decomp_size as usize)?;
+ Cursor::new(blockindex)
+ };
+ {
+ // align stream
+ let off = file.stream_position()? % 16;
+ if off != 0 {
+ file.seek_relative(16 - off as i64)?;
+ }
}
- let block = meta_comp_scheme.decompress(block, meta_decomp_size as usize)?;
- let mut block = Cursor::new(block);
-
- let guid = block.read_u128_be()?;
- eprintln!("guid={guid:032x}");
+ blockindex.read_u128_be()?;
- let num_blocks = block.read_u32_be()?;
- eprintln!("num_blocks={num_blocks:?}");
+ let num_blocks = blockindex.read_u32_be()?;
+ debug!("num_blocks={num_blocks:?}");
let mut blocks = Vec::new();
for _ in 0..num_blocks {
- let block_decomp_size = block.read_u32_be()?;
- let block_comp_size = block.read_u32_be()?;
- let block_flags = block.read_u16_be()?;
+ let block_decomp_size = blockindex.read_u32_be()?;
+ let block_comp_size = blockindex.read_u32_be()?;
+ let block_flags = blockindex.read_u16_be()?;
let block_comp_scheme = CompressionScheme::from_flag_num((block_flags & 0x3f) as u8)
.ok_or(anyhow!("unknown block compression"))?;
blocks.push((block_comp_size, block_decomp_size, block_comp_scheme))
}
- let num_nodes = block.read_u32_be()?;
- eprintln!("num_nodes={num_nodes:?}");
+ let num_nodes = blockindex.read_u32_be()?;
+ debug!("num_nodes={num_nodes:?}");
let mut nodes = Vec::new();
for _ in 0..num_nodes {
- let offset = block.read_u64_be()?;
- let size = block.read_u64_be()?;
- let status = block.read_u32_be()?;
- let name = block.read_cstr()?;
+ let offset = blockindex.read_u64_be()?;
+ let size = blockindex.read_u64_be()?;
+ let status = blockindex.read_u32_be()?;
+ let name = blockindex.read_cstr()?;
+ info!("found node {name:?} (offset={offset}, size={size}, status={status})");
nodes.push((offset, size, status, name))
}
- let mut all_blocks = Vec::new();
+ let mut storage = Vec::new();
for (comp_size, decomp_size, comp_scheme) in blocks {
let mut comp_buf = vec![0u8; comp_size as usize];
file.read_exact(&mut comp_buf)?;
let decomp_buf = comp_scheme.decompress(comp_buf, decomp_size as usize)?;
assert_eq!(decomp_size, decomp_buf.len() as u32);
- all_blocks.extend_from_slice(&decomp_buf);
+ storage.extend_from_slice(&decomp_buf);
}
+ let mut storage = Cursor::new(storage);
- eprintln!("{nodes:#?}");
+ for (offset, size, _status, name) in nodes {
+ storage.seek(SeekFrom::Start(offset))?;
+ info!("extracting {name:?}");
+ let mut file = File::create(format!("/tmp/{}", name))?;
+ copy(&mut (&mut storage).take(size), &mut file)?;
+ }
Ok(())
}
@@ -125,7 +146,9 @@ impl CompressionScheme {
// 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)?)
}
CompressionScheme::LZHAM => todo!(),
}