ttmp-rs/examples/extract.rs

345 lines
14 KiB
Rust

use std::collections::hash_map::DefaultHasher;
use std::fs::File;
use std::hash::{Hash, Hasher};
use std::io::ErrorKind;
use std::path::Path;
use ttmp::ttmp_extractor::TtmpExtractor;
pub fn main() {
let arg = std::env::args().skip(1).next().unwrap();
let file = File::open(&arg).unwrap();
let mut extractor = TtmpExtractor::new(file).unwrap();
extractor.extract_all(|file| {
if file.file.full_path.contains("../") {
return Err(std::io::Error::new(ErrorKind::Other, "tried to escape directory"));
}
let group = file.group.map(|s| {
let mut hasher = DefaultHasher::default();
s.hash(&mut hasher);
hasher.finish()
}).unwrap_or(0);
let option = file.option.map(|s| {
let mut hasher = DefaultHasher::default();
s.hash(&mut hasher);
hasher.finish()
}).unwrap_or(0);
let path = Path::new(".")
.join(format!("g{}", group))
.join(format!("o{}", option))
.join(&file.file.full_path);
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
println!("extracting {}", path.to_string_lossy());
Ok(Box::new(File::create(path)?))
}).unwrap();
}
// use std::fs::File;
// use std::io::{Cursor, Read, Seek, SeekFrom, Write};
// use std::path::Path;
//
// use flate2::read::DeflateDecoder;
// use sqpack::{DatBlockHeader, DatStdFileBlockInfos, FileKind, LodBlock, ModelBlock, SqPackFileInfoHeader};
// use sqpack::binrw::{BinRead, BinWriterExt, VecArgs};
// use sqpack::model::SqPackFileInfo;
//
// use ttmp::tracking_reader::TrackingReader;
//
// const MAX_LODS: usize = 3;
//
// pub fn main() {
// let arg = std::env::args().skip(1).next().unwrap();
// let file = File::open(&arg).unwrap();
// let (manifest, mut zip) = ttmp::from_reader(file).unwrap();
// let mut data_file = TrackingReader::new(zip.by_name("TTMPD.mpd").unwrap());
//
// let mut all_files = Vec::new();
//
// if let Some(pages) = &manifest.mod_pack_pages {
// for page in pages {
// for group in &page.mod_groups {
// for option in &group.option_list {
// for file in &option.mods_jsons {
// all_files.push(file);
// }
// }
// }
// }
// }
//
// if let Some(list) = &manifest.simple_mods_list {
// all_files.extend(list);
// }
//
// all_files.sort_unstable_by_key(|&file| file.mod_offset);
//
// let mut buf = [0; 4092];
// for file in all_files {
// data_file.read = 0;
// let path = &file.full_path;
// println!("extracting {}", path);
//
// if let Some(parent) = Path::new("./").join(Path::new(path)).parent() {
// std::fs::create_dir_all(parent).unwrap();
// }
//
// let expected = file.mod_size;
// let mut file = File::create(path).unwrap();
//
// let info: SqPackFileInfoHeader = read_struct(&mut data_file, &mut buf);
//
// match info.kind {
// FileKind::Empty => todo!(),
// FileKind::Standard => {
// let std_info: SqPackFileInfo = read_struct(&mut data_file, &mut buf);
// let blocks: Vec<DatStdFileBlockInfos> = (0..std_info.number_of_blocks)
// .map(|_| read_struct(&mut data_file, &mut buf))
// .collect();
//
// let skip_amt = info.size as usize
// - std::mem::size_of::<SqPackFileInfoHeader>()
// - std::mem::size_of::<SqPackFileInfo>()
// - std::mem::size_of::<DatStdFileBlockInfos>() * std_info.number_of_blocks as usize;
// skip(&mut data_file, &mut buf, skip_amt);
//
// for block in blocks {
// read_block_into(&mut data_file, &mut file, &mut buf, block.compressed_size as usize);
// }
// }
// FileKind::Model => {
// let model_info: ModelBlock = read_struct(&mut data_file, &mut buf);
// dbg!(&model_info);
//
// let block_counts = &model_info.block_num;
// let total_blocks = block_counts.stack
// + block_counts.runtime
// + block_counts.vertex_buffer.iter().sum::<u16>()
// + block_counts.edge_geometry_vertex_buffer.iter().sum::<u16>()
// + block_counts.index_buffer.iter().sum::<u16>();
// let block_sizes: Vec<u16> = read_vec(&mut data_file, total_blocks as usize);
//
// let skip_amt = info.size as usize
// - std::mem::size_of::<SqPackFileInfoHeader>()
// - std::mem::size_of::<ModelBlock>()
// - total_blocks as usize * std::mem::size_of::<u16>();
// skip(&mut data_file, &mut buf, skip_amt);
//
// file.seek(SeekFrom::Start(0x44)).unwrap();
//
// let stack_size = read_blocks_into(
// model_info.block_num.stack,
// model_info.block_index.stack,
// model_info.offset.stack,
// &block_sizes,
// &mut data_file,
// &mut file,
// &mut buf,
// );
//
// let runtime_size = read_blocks_into(
// model_info.block_num.runtime,
// model_info.block_index.runtime,
// model_info.offset.runtime,
// &block_sizes,
// &mut data_file,
// &mut file,
// &mut buf,
// );
//
// let mut vertex_data_offsets = [0u32; MAX_LODS];
// let mut vertex_buffer_sizes = [0u32; MAX_LODS];
//
// let mut index_data_offsets = [0u32; MAX_LODS];
// let mut index_buffer_sizes = [0u32; MAX_LODS];
//
// for lod_index in 0..MAX_LODS {
// // Vertex buffer
// let block_count = model_info.block_num.vertex_buffer[lod_index];
// if block_count != 0 {
// if lod_index == 0 || block_count > 0 {
// vertex_data_offsets[lod_index] = file.stream_position().unwrap().try_into().unwrap();
// }
//
// vertex_buffer_sizes[lod_index] = read_blocks_into(
// block_count,
// model_info.block_index.vertex_buffer[lod_index],
// // offset + model_info.offset.vertex_buffer[lod_index],
// model_info.offset.vertex_buffer[lod_index],
// &block_sizes,
// &mut data_file,
// &mut file,
// &mut buf,
// );
// }
//
// // Edge geometry vertex buffer
// let block_count = model_info.block_num.edge_geometry_vertex_buffer[lod_index];
// if block_count != 0 {
// read_blocks_into(
// block_count,
// model_info.block_index.edge_geometry_vertex_buffer[lod_index],
// // offset + model_info.offset.edge_geometry_vertex_buffer[lod_index],
// model_info.offset.edge_geometry_vertex_buffer[lod_index],
// &block_sizes,
// &mut data_file,
// &mut file,
// &mut buf,
// );
// }
//
// // Index buffer
// let block_count = model_info.block_num.index_buffer[lod_index];
// if block_count != 0 {
// if lod_index == 0 || block_count > 0 {
// index_data_offsets[lod_index] = file.stream_position().unwrap().try_into().unwrap();
// }
//
// index_buffer_sizes[lod_index] = read_blocks_into(
// block_count,
// model_info.block_index.index_buffer[lod_index],
// // offset + model_info.offset.index_buffer[lod_index],
// model_info.offset.index_buffer[lod_index],
// &block_sizes,
// &mut data_file,
// &mut file,
// &mut buf,
// );
// }
// }
//
// // Write out the header now we've collected the info for it.
// file.seek(SeekFrom::Start(0)).unwrap();
// file.write_le(&model_info.version).unwrap();
// file.write_le(&stack_size).unwrap();
// file.write_le(&runtime_size).unwrap();
// file.write_le(&model_info.vertex_declaration_num).unwrap();
// file.write_le(&model_info.material_num).unwrap();
// file.write_le(&vertex_data_offsets).unwrap();
// file.write_le(&index_data_offsets).unwrap();
// file.write_le(&vertex_buffer_sizes).unwrap();
// file.write_le(&index_buffer_sizes).unwrap();
// file.write_le(&model_info.num_lods).unwrap();
// file.write_le(&model_info.index_buffer_streaming_enabled).unwrap();
// file.write_le(&model_info.edge_geometry_enabled).unwrap();
// file.write_le(&0u8).unwrap();
// }
// FileKind::Texture => {
// let std_info: SqPackFileInfo = read_struct(&mut data_file, &mut buf);
// let blocks: Vec<LodBlock> = (0..std_info.number_of_blocks)
// .map(|_| read_struct(&mut data_file, &mut buf))
// .collect();
//
// let sub_block_count = blocks
// .iter()
// .fold(0, |acc, block| acc + block.block_count);
// let sub_block_sizes: Vec<u16> = read_vec(&mut data_file, sub_block_count as usize);
//
// let skip_amt = info.size as usize
// - std::mem::size_of::<SqPackFileInfoHeader>()
// - std::mem::size_of::<SqPackFileInfo>()
// - std::mem::size_of::<LodBlock>() * std_info.number_of_blocks as usize
// - std::mem::size_of::<u16>() * sub_block_sizes.len();
// skip(&mut data_file, &mut buf, skip_amt);
//
// let mip_map_size = blocks[0].compressed_offset;
// if mip_map_size > 0 {
// let mut reader = (&mut data_file).take(mip_map_size as u64);
// std::io::copy(&mut reader, &mut file).unwrap();
// }
//
// let mut sub_block = 0;
// for block in blocks {
// for _ in 0..block.block_count {
// read_block_into(&mut data_file, &mut file, &mut buf, sub_block_sizes[sub_block] as usize);
// sub_block += 1;
// }
// }
// }
// }
//
// if data_file.read < expected {
// let to_skip = expected - data_file.read;
// skip(&mut data_file, &mut buf, to_skip);
// }
// }
// }
//
// fn read_block_into<R: Read, W: Write>(reader: &mut R, writer: &mut W, buf: &mut [u8], size: usize) -> u64 {
// let header: DatBlockHeader = read_struct(reader, buf);
//
// let (read, actual) = if header.compressed_size == 32_000 {
// // uncompressed
// let mut reader = reader.take(header.uncompressed_size as u64);
// let read = std::io::copy(&mut reader, writer).unwrap();
// (read, read)
// } else {
// // compressed
// let reader = reader.take(header.compressed_size as u64);
// let mut decoder = DeflateDecoder::new(reader);
// let read = std::io::copy(&mut decoder, writer).unwrap();
// (header.compressed_size as u64, read)
// };
//
// if (header.size as usize + read as usize) < size as usize {
// let to_skip = size
// - header.size as usize
// - read as usize;
// skip(reader, buf, to_skip);
// }
//
// actual
// }
//
// fn read_blocks_into(
// block_count: u16,
// block_index: u16,
// _section_offset: u32,
// block_sizes: &[u16],
// reader: &mut impl Read,
// writer: &mut impl Write,
// buf: &mut [u8],
// ) -> u32 {
// let sizes = &block_sizes[block_index as usize..block_index as usize + block_count as usize];
//
// let mut total_read = 0u32;
// for &size in sizes {
// let bytes_read = read_block_into(reader, writer, buf, size as usize);
// total_read += bytes_read as u32;
// }
//
// total_read as u32
// }
//
// fn read_struct<S: BinRead, R: Read>(reader: &mut R, buf: &mut [u8]) -> S
// where S::Args: Default,
// {
// let size = std::mem::size_of::<S>();
// reader.read_exact(&mut buf[..size]).unwrap();
// S::read(&mut Cursor::new(&buf[..size])).unwrap()
// }
//
// fn skip<R: Read>(reader: &mut R, buf: &mut [u8], size: usize) {
// let mut left = size;
// while left > 0 {
// let to_read = std::cmp::min(left, buf.len());
// left -= reader.read(&mut buf[..to_read]).unwrap();
// }
// }
//
// fn read_vec<S: BinRead<Args=()>, R: Read>(reader: &mut R, amount: usize) -> Vec<S> {
// let mut buf = vec![0; amount * std::mem::size_of::<S>()];
// reader.read_exact(&mut buf).unwrap();
// <Vec<S>>::read_args(
// &mut Cursor::new(buf),
// VecArgs {
// count: amount,
// inner: (),
// },
// ).unwrap()
// }