Skip to content

Commit

Permalink
dump_resource
Browse files Browse the repository at this point in the history
  • Loading branch information
widberg committed Oct 26, 2023
1 parent d0b8178 commit 3a8e9ca
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 98 deletions.
14 changes: 10 additions & 4 deletions bff-cli/src/extract.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::fs::File;
use std::io;
use std::io::BufWriter;
use std::path::{Path, PathBuf};

use bff::bigfile::BigFile;
use bff::platforms::Platform;
use bff::BufReader;
use serde_json::to_writer_pretty;

use crate::error::BffCliResult;

Expand Down Expand Up @@ -57,14 +55,22 @@ pub fn read_bigfile(bigfile_path: &Path) -> BffCliResult<BigFile> {

pub fn extract(
bigfile_path: &Path,
_directory: &Path,
directory: &Path,
in_names: &Vec<PathBuf>,
out_names: &Option<PathBuf>,
) -> BffCliResult<()> {
read_names(bigfile_path, in_names)?;

let bigfile = read_bigfile(bigfile_path)?;
to_writer_pretty(io::stdout().lock(), &bigfile)?;

for resource in bigfile.objects.values() {
let name = resource.name;
let class_name = resource.class_name;
let path = directory.join(format!("{}.{}", name, class_name));
std::fs::create_dir_all(path.parent().unwrap())?;
let mut writer = BufWriter::new(File::create(path)?);
bigfile.dump_resource(resource, &mut writer)?;
}

write_names(out_names)?;

Expand Down
40 changes: 40 additions & 0 deletions bff-derive/src/bigfiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ impl Parse for BffBigFileMacroInput {
pub fn derive_bigfiles(input: BffBigFileMacroInput) -> TokenStream {
let read_bigfile = impl_read_bigfile(&input);
let write_bigfile = impl_write_bigfile(&input);
let dump_resource = impl_dump_resource(&input);

quote! {
impl BigFile {
#read_bigfile
#write_bigfile
#dump_resource
}
}
}
Expand Down Expand Up @@ -107,3 +109,41 @@ fn impl_write_bigfile(input: &BffBigFileMacroInput) -> proc_macro2::TokenStream
}
}
}

fn impl_dump_resource(input: &BffBigFileMacroInput) -> proc_macro2::TokenStream {
let arms = input
.forms
.iter()
.map(|form| {
let attrs = &form.attrs;
let pat = &form.pat;
let guard = match &form.guard {
Some((_, guard)) => quote! { #guard },
None => quote! {},
};
let body = &form.body;
quote! {
#(#attrs)*
#pat #guard => {
crate::names::names().lock().unwrap().name_type = <#body as BigFileIo>::name_type(version.clone(), platform);
Ok(<#body as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)
}
}
})
.collect::<Vec<_>>();

quote! {
pub fn dump_resource<W: std::io::Write + std::io::Seek>(&self, resource: &Resource, writer: &mut W) -> crate::BffResult<()> {
use crate::versions::Version::*;
use crate::platforms::Platform::*;
use crate::traits::BigFileIo;
let platform = self.manifest.platform;
let endian: crate::Endian = platform.into();
let version = &self.manifest.version;
match (version.clone(), platform) {
#(#arms)*
(version, platform) => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
}
}
}
}
3 changes: 3 additions & 0 deletions bff/src/bigfile/v1_06_63_02_pc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::io::{Read, Seek, SeekFrom, Write};
use binrw::{BinRead, BinResult, BinWrite, Endian};
use block::Block;
use header::*;
use object::Object;
use pool::Pool;

use crate::bigfile::manifest::*;
Expand Down Expand Up @@ -481,4 +482,6 @@ impl BigFileIo for BigFileV1_06_63_02PC {
fn name_type(_version: Version, _platform: Platform) -> NameType {
Asobo32
}

type ResourceType = Object;
}
63 changes: 21 additions & 42 deletions bff/src/bigfile/v1_06_63_02_pc/object.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::io::{Seek, SeekFrom, Write};
use std::io::{Seek, Write};

use binrw::{args, binread, parser, BinRead, BinResult, BinWrite, Endian};
use derive_more::{Deref, DerefMut};
use serde::Serialize;

use crate::lz::{lzrs_compress_data_with_header_writer_internal, lzrs_decompress_body_parser};
use crate::bigfile::resource::Resource;
use crate::bigfile::resource::ResourceData::SplitData;
use crate::lz::lzrs_decompress_body_parser;
use crate::names::Name;

#[parser(reader, endian)]
Expand Down Expand Up @@ -45,53 +47,30 @@ pub struct Object {
pub body: Vec<u8>,
}

impl BinWrite for Object {
type Args<'a> = ();

fn write_options<W: Write + Seek>(
&self,
impl Object {
pub fn dump_resource<W: Write + Seek>(
resource: &Resource,
writer: &mut W,
endian: Endian,
_args: Self::Args<'_>,
) -> BinResult<()> {
let start = writer.stream_position()?;
writer.seek(SeekFrom::Current(16))?;

self.class_name.write_options(writer, endian, ())?;
self.name.write_options(writer, endian, ())?;
self.link_header.write_options(writer, endian, ())?;
let link_header_size = self.link_header.len() as u32;
let body_size = if self.compress {
let body_start = writer.stream_position()?;
lzrs_compress_data_with_header_writer_internal(&self.body, writer, endian, ())?;
let body_end = writer.stream_position()?;
(body_end - body_start) as u32
} else {
self.body.write_options(writer, endian, ())?;
self.body.len() as u32
};

let end = writer.stream_position()?;

// Now that we know everything, back to the top to write the header
writer.seek(SeekFrom::Start(start))?;

let data_size = link_header_size + body_size;
let decompressed_size = self.body.len() as u32;
let compressed_size = if self.compress { body_size } else { 0 };

data_size.write_options(writer, endian, ())?;
link_header_size.write_options(writer, endian, ())?;
decompressed_size.write_options(writer, endian, ())?;
compressed_size.write_options(writer, endian, ())?;

writer.seek(SeekFrom::Start(end))?;

match &resource.data {
SplitData { link_header, body } => {
(link_header.len() as u32 + body.len() as u32).write_options(writer, endian, ())?;
(link_header.len() as u32).write_options(writer, endian, ())?;
(body.len() as u32).write_options(writer, endian, ())?;
0u32.write_options(writer, endian, ())?;
resource.class_name.write_options(writer, endian, ())?;
resource.name.write_options(writer, endian, ())?;
writer.write_all(link_header)?;
writer.write_all(body)?;
}
_ => unreachable!(),
}
Ok(())
}
}

#[derive(BinRead, Serialize, Debug, BinWrite, Deref, DerefMut)]
#[derive(BinRead, Serialize, Debug, Deref, DerefMut)]
pub struct PoolObject {
#[brw(align_after(2048))]
#[serde(flatten)]
Expand Down
2 changes: 1 addition & 1 deletion bff/src/bigfile/v1_06_63_02_pc/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ pub fn calculate_padded_pool_header_size(
calculated_padded(size, 2048)
}

#[derive(BinRead, Serialize, Debug, BinWrite)]
#[derive(BinRead, Serialize, Debug)]
pub struct Pool {
pub header: PoolHeader,
#[br(count = header.object_descriptions_indices.len())]
Expand Down
3 changes: 3 additions & 0 deletions bff/src/bigfile/v1_08_40_02_pc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::io::{Read, Seek, SeekFrom, Write};
use binrw::{BinRead, BinResult, BinWrite};
use block::Block;
use header::*;
use object::Object;

use crate::bigfile::manifest::*;
use crate::bigfile::resource::Resource;
Expand Down Expand Up @@ -250,4 +251,6 @@ impl BigFileIo for BigFileV1_08_40_02PC {
fn name_type(_version: Version, _platform: Platform) -> NameType {
Asobo32
}

type ResourceType = Object;
}
58 changes: 23 additions & 35 deletions bff/src/bigfile/v1_08_40_02_pc/object.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::io::{Seek, SeekFrom, Write};
use std::io::{Seek, Write};

use binrw::{binread, BinResult, BinWrite, Endian};
use serde::Serialize;

use crate::bigfile::resource::Resource;
use crate::bigfile::resource::ResourceData::{Data, SplitData};
use crate::bigfile::v1_06_63_02_pc::object::body_parser;
use crate::lz::lzrs_compress_data_with_header_writer_internal;
use crate::names::Name;

#[binread]
Expand All @@ -23,42 +24,29 @@ pub struct Object {
pub data: Vec<u8>,
}

impl BinWrite for Object {
type Args<'a> = ();

fn write_options<W: Write + Seek>(
&self,
impl Object {
pub fn dump_resource<W: Write + Seek>(
resource: &Resource,
writer: &mut W,
endian: Endian,
_args: Self::Args<'_>,
) -> BinResult<()> {
let start = writer.stream_position()?;
writer.seek(SeekFrom::Current(8))?;

self.class_name.write_options(writer, endian, ())?;
self.name.write_options(writer, endian, ())?;
let body_size = if self.compress {
let body_start = writer.stream_position()?;
lzrs_compress_data_with_header_writer_internal(&self.data, writer, endian, ())?;
let body_end = writer.stream_position()?;
(body_end - body_start) as u32
} else {
self.data.write_options(writer, endian, ())?;
self.data.len() as u32
};

let end = writer.stream_position()?;

// Now that we know everything, back to the top to write the header
writer.seek(SeekFrom::Start(start))?;

let decompressed_size = self.data.len() as u32;
let compressed_size = if self.compress { body_size } else { 0 };

decompressed_size.write_options(writer, endian, ())?;
compressed_size.write_options(writer, endian, ())?;

writer.seek(SeekFrom::Start(end))?;
match &resource.data {
Data(data) => {
(data.len() as u32).write_options(writer, endian, ())?;
0u32.write_options(writer, endian, ())?;
resource.class_name.write_options(writer, endian, ())?;
resource.name.write_options(writer, endian, ())?;
data.write_options(writer, endian, ())?;
}
SplitData { link_header, body } => {
((link_header.len() + body.len()) as u32).write_options(writer, endian, ())?;
0u32.write_options(writer, endian, ())?;
resource.class_name.write_options(writer, endian, ())?;
resource.name.write_options(writer, endian, ())?;
link_header.write_options(writer, endian, ())?;
body.write_options(writer, endian, ())?;
}
}

Ok(())
}
Expand Down
46 changes: 30 additions & 16 deletions bff/src/bigfile/v1_22_pc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,33 @@ pub struct Resource {
data: Vec<u8>,
}

impl Resource {
pub fn dump_resource<W: Write + Seek>(
resource: &crate::bigfile::resource::Resource,
writer: &mut W,
endian: Endian,
) -> BinResult<()> {
match &resource.data {
Data(data) => {
(data.len() as u32 + 12).write_options(writer, endian, ())?;
resource.class_name.write_options(writer, endian, ())?;
resource.name.write_options(writer, endian, ())?;
data.write_options(writer, endian, ())?;
}
SplitData { link_header, body } => {
let data_len = link_header.len() as u32 + body.len() as u32 + 12;
data_len.write_options(writer, endian, ())?;
resource.class_name.write_options(writer, endian, ())?;
resource.name.write_options(writer, endian, ())?;
link_header.write_options(writer, endian, ())?;
body.write_options(writer, endian, ())?;
}
}

Ok(())
}
}

impl From<Resource> for crate::bigfile::resource::Resource {
fn from(resource: Resource) -> crate::bigfile::resource::Resource {
crate::bigfile::resource::Resource {
Expand Down Expand Up @@ -181,22 +208,7 @@ impl<const HAS_VERSION_TRIPLE: bool, const KALISTO: bool> BigFileIo

for resource in block.objects.iter() {
let resource = bigfile.objects.get(&resource.name).unwrap();
match &resource.data {
Data(data) => {
(data.len() as u32 + 12).write_options(writer, endian, ())?;
resource.class_name.write_options(writer, endian, ())?;
resource.name.write_options(writer, endian, ())?;
data.write_options(writer, endian, ())?;
}
SplitData { link_header, body } => {
let data_len = link_header.len() as u32 + body.len() as u32 + 12;
data_len.write_options(writer, endian, ())?;
resource.class_name.write_options(writer, endian, ())?;
resource.name.write_options(writer, endian, ())?;
link_header.write_options(writer, endian, ())?;
body.write_options(writer, endian, ())?;
}
};
Resource::dump_resource(resource, writer, endian)?;
}

write_align_to(writer, 0x20000, 0xCD)?;
Expand Down Expand Up @@ -234,4 +246,6 @@ impl<const HAS_VERSION_TRIPLE: bool, const KALISTO: bool> BigFileIo
BlackSheep32
}
}

type ResourceType = Resource;
}
2 changes: 2 additions & 0 deletions bff/src/bigfile/v2_07_pc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,6 @@ impl<const MQFEL: bool> BigFileIo for BigFileV2_07PC<MQFEL> {
fn name_type(_version: Version, _platform: Platform) -> NameType {
BlackSheep32
}

type ResourceType = Resource;
}
2 changes: 2 additions & 0 deletions bff/src/traits/big_file_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ pub trait BigFileIo {
) -> BffResult<()>;

fn name_type(version: Version, platform: Platform) -> NameType;

type ResourceType;
}

0 comments on commit 3a8e9ca

Please sign in to comment.