mirror of
https://github.com/widberg/bff
synced 2026-08-23 14:26:03 -04:00
Name macro
This commit is contained in:
parent
5a5eb49303
commit
b125d18a42
24 changed files with 885 additions and 764 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
|
@ -153,7 +153,6 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_context",
|
||||
"serde_json",
|
||||
"string-interner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1092,16 +1091,6 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "string-interner"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23de088478b31c349c9ba67816fa55d9355232d63c3afea8bf513e31f0f1d2c0"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
|
|
|
|||
|
|
@ -37,9 +37,8 @@ pub fn extract_cps(
|
|||
in_names: &Vec<PathBuf>,
|
||||
endian: &LzEndian,
|
||||
) -> BffCliResult<()> {
|
||||
let name_context = NameContext::default();
|
||||
let name_context = NameContext::new(NameType::BlackSheep32);
|
||||
let endian: Endian = (*endian).into();
|
||||
name_context.set_name_type(NameType::BlackSheep32);
|
||||
if in_names.is_empty() {
|
||||
read_default_cps_names(&name_context)?;
|
||||
} else {
|
||||
|
|
@ -90,9 +89,8 @@ pub fn create_cps(
|
|||
endian: &LzEndian,
|
||||
unencrypted: &bool,
|
||||
) -> BffCliResult<()> {
|
||||
let name_context = NameContext::default();
|
||||
let name_context = NameContext::new(NameType::BlackSheep32);
|
||||
let endian: Endian = (*endian).into();
|
||||
name_context.set_name_type(NameType::BlackSheep32);
|
||||
let mut cps = Cps::default();
|
||||
let directory_cwd = directory.join("System");
|
||||
read_files_into_cps_recursively(&mut cps, directory, &directory_cwd)?;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use bff::bigfile::BigFile;
|
|||
use bff::bigfile::platforms::Platform;
|
||||
use bff::bigfile::resource::{BffClass, Resource};
|
||||
use bff::bigfile::versions::Version;
|
||||
use bff::names::NameContext;
|
||||
use bff::names::{NameContext, NameType};
|
||||
use bff::traits::{Artifact, Import, TryIntoVersionPlatform};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use rayon::iter::{ParallelBridge, ParallelIterator};
|
||||
|
|
@ -15,6 +15,24 @@ use rayon::iter::{ParallelBridge, ParallelIterator};
|
|||
use crate::error::BffCliResult;
|
||||
use crate::extract::write_names;
|
||||
|
||||
fn validate_version_override_name_type(
|
||||
version_override: &Option<Version>,
|
||||
expected_name_type: NameType,
|
||||
) -> BffCliResult<()> {
|
||||
if let Some(version_override) = version_override {
|
||||
let override_name_type: NameType = version_override.try_into()?;
|
||||
if override_name_type != expected_name_type {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"`--version-override` implies NameType {:?}, but context requires {:?}",
|
||||
override_name_type, expected_name_type
|
||||
))
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create(
|
||||
directory: &Path,
|
||||
|
|
@ -25,10 +43,14 @@ pub fn create(
|
|||
version_to_write: &Option<Version>,
|
||||
tag: &Option<String>,
|
||||
) -> BffCliResult<()> {
|
||||
let name_context = NameContext::default();
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message("Reading manifest");
|
||||
let manifest_path = directory.join("manifest.json");
|
||||
let manifest_name_type = bff::names::json::probe_name_type_from_manifest_reader(
|
||||
BufReader::new(File::open(&manifest_path)?),
|
||||
)?;
|
||||
validate_version_override_name_type(version_override, manifest_name_type)?;
|
||||
let name_context = NameContext::new(manifest_name_type);
|
||||
let manifest_reader = BufReader::new(File::open(manifest_path)?);
|
||||
let manifest = bff::names::json::from_reader(manifest_reader, &name_context)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,30 @@ use bff::BufReader;
|
|||
use bff::bigfile::platforms::Platform;
|
||||
use bff::bigfile::resource::{BffClass, Resource};
|
||||
use bff::bigfile::versions::Version;
|
||||
use bff::names::NameContext;
|
||||
use bff::names::{NameContext, NameType};
|
||||
use bff::traits::{Artifact, Import, TryIntoVersionPlatform};
|
||||
|
||||
use crate::error::BffCliResult;
|
||||
use crate::extract::write_names;
|
||||
|
||||
fn validate_version_override_name_type(
|
||||
version_override: &Option<Version>,
|
||||
expected_name_type: NameType,
|
||||
) -> BffCliResult<()> {
|
||||
if let Some(version_override) = version_override {
|
||||
let override_name_type: NameType = version_override.try_into()?;
|
||||
if override_name_type != expected_name_type {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"`--version-override` implies NameType {:?}, but context requires {:?}",
|
||||
override_name_type, expected_name_type
|
||||
))
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_resource(
|
||||
directory: &Path,
|
||||
resource_path: &Path,
|
||||
|
|
@ -20,8 +38,12 @@ pub fn create_resource(
|
|||
platform_override: &Option<Platform>,
|
||||
version_override: &Option<Version>,
|
||||
) -> BffCliResult<()> {
|
||||
let name_context = NameContext::default();
|
||||
let resource_serialized_path = directory.join("resource.json");
|
||||
let name_type = bff::names::json::probe_name_type_from_bff_class_reader(BufReader::new(
|
||||
File::open(&resource_serialized_path)?,
|
||||
))?;
|
||||
validate_version_override_name_type(version_override, name_type)?;
|
||||
let name_context = NameContext::new(name_type);
|
||||
let resource_serialized_reader = BufReader::new(File::open(&resource_serialized_path)?);
|
||||
let mut bff_class: BffClass =
|
||||
bff::names::json::from_reader(resource_serialized_reader, &name_context)?;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use bff::bigfile::resource::Resource;
|
|||
use bff::names::NameContext;
|
||||
|
||||
use crate::error::BffCliResult;
|
||||
use crate::extract::{read_bigfile, read_bigfile_names};
|
||||
use crate::extract::{probe_bigfile_name_context, read_bigfile, read_bigfile_names};
|
||||
|
||||
struct ResolvedResource<'a> {
|
||||
link_name: Option<String>,
|
||||
|
|
@ -27,7 +27,7 @@ fn load_bigfile(
|
|||
bigfile_path: &Path,
|
||||
name_path: &Option<PathBuf>,
|
||||
) -> BffCliResult<(BigFile, NameContext)> {
|
||||
let name_context = NameContext::default();
|
||||
let name_context = probe_bigfile_name_context(bigfile_path, &None, &None)?;
|
||||
read_bigfile_names(bigfile_path, &name_context)?;
|
||||
if let Some(name_path) = name_path {
|
||||
read_name_file(name_path, &name_context)?;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,23 @@ pub fn read_bigfile(
|
|||
)?)
|
||||
}
|
||||
|
||||
pub fn probe_bigfile_name_context(
|
||||
bigfile_path: &Path,
|
||||
platform_override: &Option<Platform>,
|
||||
version_override: &Option<Version>,
|
||||
) -> BffCliResult<NameContext> {
|
||||
let platform = platform_override.unwrap_or_else(|| {
|
||||
bigfile_path
|
||||
.extension()
|
||||
.and_then(|e| e.try_into().ok())
|
||||
.unwrap_or(Platform::PC)
|
||||
});
|
||||
let f = File::open(bigfile_path)?;
|
||||
let mut reader = BufReader::new(f);
|
||||
let name_type = BigFile::probe_name_type_platform(&mut reader, platform, version_override)?;
|
||||
Ok(NameContext::new(name_type))
|
||||
}
|
||||
|
||||
const INVALID_PATH_CHARS: [u8; 41] = [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||
26, 27, 28, 29, 30, 31, 34, 42, 47, 58, 60, 62, 63, 92, 124,
|
||||
|
|
@ -192,7 +209,7 @@ pub fn extract(
|
|||
export_strategy: &ExportStrategy,
|
||||
rich_suffix: &String,
|
||||
) -> BffCliResult<()> {
|
||||
let name_context = NameContext::default();
|
||||
let name_context = probe_bigfile_name_context(bigfile_path, platform_override, version_override)?;
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message("Reading names");
|
||||
read_bigfile_names(bigfile_path, &name_context)?;
|
||||
|
|
|
|||
|
|
@ -7,12 +7,30 @@ use bff::bigfile::platforms::Platform;
|
|||
use bff::bigfile::resource::{BffClass, BffResource, BffResourceHeader};
|
||||
use bff::bigfile::versions::Version;
|
||||
use bff::class::Class;
|
||||
use bff::names::NameContext;
|
||||
use bff::names::{NameContext, NameType};
|
||||
use bff::traits::{Artifact, Export, TryIntoVersionPlatform};
|
||||
|
||||
use crate::error::BffCliResult;
|
||||
use crate::extract::read_in_names;
|
||||
|
||||
fn validate_version_override_name_type(
|
||||
version_override: &Option<Version>,
|
||||
expected_name_type: NameType,
|
||||
) -> BffCliResult<()> {
|
||||
if let Some(version_override) = version_override {
|
||||
let override_name_type: NameType = version_override.try_into()?;
|
||||
if override_name_type != expected_name_type {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"`--version-override` implies NameType {:?}, but context requires {:?}",
|
||||
override_name_type, expected_name_type
|
||||
))
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn extract_resource(
|
||||
resource_path: &Path,
|
||||
directory: &Path,
|
||||
|
|
@ -20,7 +38,10 @@ pub fn extract_resource(
|
|||
platform_override: &Option<Platform>,
|
||||
version_override: &Option<Version>,
|
||||
) -> BffCliResult<()> {
|
||||
let name_context = NameContext::default();
|
||||
let mut probe_reader = BufReader::new(File::open(resource_path)?);
|
||||
let name_type = BffResourceHeader::probe_name_type(&mut probe_reader)?;
|
||||
validate_version_override_name_type(version_override, name_type)?;
|
||||
let name_context = NameContext::new(name_type);
|
||||
read_in_names(in_names, &name_context)?;
|
||||
|
||||
let f = File::open(resource_path)?;
|
||||
|
|
|
|||
|
|
@ -2,18 +2,17 @@ use std::fs::File;
|
|||
use std::io::{self, BufWriter, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use bff::names::NameContext;
|
||||
use bff::petgraph::dot::{Config, Dot};
|
||||
|
||||
use crate::error::BffCliResult;
|
||||
use crate::extract::{read_bigfile, read_bigfile_names, read_in_names};
|
||||
use crate::extract::{probe_bigfile_name_context, read_bigfile, read_bigfile_names, read_in_names};
|
||||
|
||||
pub fn info(
|
||||
bigfile_path: &Path,
|
||||
in_names: &Vec<PathBuf>,
|
||||
out_reference_graph: &Option<PathBuf>,
|
||||
) -> BffCliResult<()> {
|
||||
let name_context = NameContext::default();
|
||||
let name_context = probe_bigfile_name_context(bigfile_path, &None, &None)?;
|
||||
read_bigfile_names(bigfile_path, &name_context)?;
|
||||
read_in_names(in_names, &name_context)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::path::PathBuf;
|
|||
|
||||
use bff::bigfile::platforms::Platform;
|
||||
use bff::bigfile::versions::Version;
|
||||
use bff::names::NameType;
|
||||
use clap::*;
|
||||
use crc::{CrcAlgorithm, CrcFormat, CrcMode};
|
||||
use crypt::CryptAlgorithm;
|
||||
|
|
@ -115,6 +116,8 @@ enum Commands {
|
|||
},
|
||||
Names {
|
||||
bigfile: Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
name_type: Option<NameType>,
|
||||
#[clap(value_enum)]
|
||||
#[arg(short, long)]
|
||||
wordlist: Option<Wordlist>,
|
||||
|
|
@ -342,11 +345,19 @@ fn main() -> BffCliResult<()> {
|
|||
} => diff::diff(old_bigfile, new_bigfile, old_names, new_names),
|
||||
Commands::Names {
|
||||
bigfile,
|
||||
name_type,
|
||||
wordlist,
|
||||
in_names,
|
||||
out_names,
|
||||
use_reference_graph,
|
||||
} => names::names(bigfile, wordlist, in_names, out_names, use_reference_graph),
|
||||
} => names::names(
|
||||
bigfile,
|
||||
name_type,
|
||||
wordlist,
|
||||
in_names,
|
||||
out_names,
|
||||
use_reference_graph,
|
||||
),
|
||||
Commands::Crc {
|
||||
string,
|
||||
starting,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use bff::names::{NameContext, WORDLIST_ANIMALS, WORDLIST_BIP39, get_forced_hash_string};
|
||||
use bff::names::{NameContext, NameType, WORDLIST_ANIMALS, WORDLIST_BIP39, get_forced_hash_string};
|
||||
use bff::petgraph;
|
||||
use bff::petgraph::visit::{VisitMap, Visitable};
|
||||
use clap::ValueEnum;
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
|
||||
use crate::error::BffCliResult;
|
||||
use crate::extract::{read_bigfile, read_bigfile_names, read_in_names, write_names};
|
||||
use crate::extract::{probe_bigfile_name_context, read_bigfile, read_bigfile_names, read_in_names, write_names};
|
||||
|
||||
#[derive(ValueEnum, Clone, Copy)]
|
||||
pub enum Wordlist {
|
||||
|
|
@ -19,20 +19,27 @@ pub enum Wordlist {
|
|||
|
||||
pub fn names(
|
||||
bigfile_path: &Option<PathBuf>,
|
||||
name_type: &Option<NameType>,
|
||||
wordlist: &Option<Wordlist>,
|
||||
in_names: &Vec<PathBuf>,
|
||||
out_names: &Option<PathBuf>,
|
||||
use_reference_graph: &bool,
|
||||
) -> BffCliResult<()> {
|
||||
let name_context = NameContext::default();
|
||||
let name_context = if let Some(bigfile_path) = bigfile_path {
|
||||
probe_bigfile_name_context(bigfile_path, &None, &None)?
|
||||
} else {
|
||||
NameContext::new(name_type.ok_or_else(|| {
|
||||
std::io::Error::other(
|
||||
"`--name-type` is required when `--bigfile` is not provided",
|
||||
)
|
||||
})?)
|
||||
};
|
||||
if let Some(bigfile_path) = bigfile_path {
|
||||
read_bigfile_names(bigfile_path, &name_context)?;
|
||||
}
|
||||
read_in_names(in_names, &name_context)?;
|
||||
|
||||
if let Some(bigfile_path) = bigfile_path {
|
||||
read_bigfile_names(bigfile_path, &name_context)?;
|
||||
|
||||
let bigfile = read_bigfile(bigfile_path, &None, &None, &name_context)?;
|
||||
|
||||
if let Some(wordlist) = wordlist {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::io::{BufReader, Seek};
|
||||
use std::path::Path;
|
||||
|
||||
use bff::bigfile::BigFile;
|
||||
|
|
@ -12,17 +12,24 @@ use bff::traits::TryYourBest;
|
|||
use crate::error::BffCliResult;
|
||||
|
||||
pub fn try_your_best(path: &Path) -> BffCliResult<()> {
|
||||
let name_context = NameContext::default();
|
||||
let f = File::open(path)?;
|
||||
let mut reader = BufReader::new(f);
|
||||
|
||||
if let Ok(bff_resource) = BffResource::read(&mut reader, &name_context) {
|
||||
let report = <Class as TryYourBest<&Resource>>::report(
|
||||
&bff_resource.resource,
|
||||
bff_resource.header.platform,
|
||||
);
|
||||
println!("{}", report);
|
||||
} else {
|
||||
if let Ok(name_type) = bff::bigfile::resource::BffResourceHeader::probe_name_type(&mut reader) {
|
||||
reader.rewind()?;
|
||||
let name_context = NameContext::new(name_type);
|
||||
if let Ok(bff_resource) = BffResource::read(&mut reader, &name_context) {
|
||||
let report = <Class as TryYourBest<&Resource>>::report(
|
||||
&bff_resource.resource,
|
||||
bff_resource.header.platform,
|
||||
);
|
||||
println!("{}", report);
|
||||
return Ok(());
|
||||
}
|
||||
reader.rewind()?;
|
||||
}
|
||||
|
||||
{
|
||||
let platform = path
|
||||
.extension()
|
||||
.and_then(|e| e.try_into().ok())
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ schemars = { version = "0.8.21", features = ["indexmap2"] }
|
|||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_context = "0.1.0"
|
||||
serde_json = "1.0"
|
||||
string-interner = "0.19.0"
|
||||
|
||||
[dev-dependencies]
|
||||
datatest = "0.8.0"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::io::{Read, Seek, Write};
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
|
||||
use binrw::{BinRead, BinWrite, binrw};
|
||||
use schemars::JsonSchema;
|
||||
|
|
@ -8,7 +8,7 @@ use super::platforms::Platform;
|
|||
use super::versions::Version;
|
||||
use crate::BffResult;
|
||||
use crate::class::Class;
|
||||
use crate::names::{Name, NameContext};
|
||||
use crate::names::{Name, NameContext, NameType};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum ResourceData {
|
||||
|
|
@ -49,6 +49,17 @@ pub struct BffResourceHeader {
|
|||
}
|
||||
|
||||
impl BffResourceHeader {
|
||||
pub fn name_type(&self) -> BffResult<NameType> {
|
||||
(&self.version).try_into()
|
||||
}
|
||||
|
||||
pub fn probe_name_type<R: Read + Seek>(reader: &mut R) -> BffResult<NameType> {
|
||||
let start = reader.stream_position()?;
|
||||
let header = Self::read(reader)?;
|
||||
reader.seek(SeekFrom::Start(start))?;
|
||||
header.name_type()
|
||||
}
|
||||
|
||||
fn data_padded_size_on_disk(&self) -> u16 {
|
||||
let non_data_size = 4 + 2;
|
||||
let total_unpadded_size =
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use binrw::{BinRead, BinResult, BinWrite, Endian, args, binread, parser};
|
|||
|
||||
use crate::bigfile::resource::ResourceData::SplitData;
|
||||
use crate::lz::{lz4_decompress_body_parser, zlib_decompress_body_parser};
|
||||
use crate::names::{Name, NameAsobo64};
|
||||
use crate::names::Name;
|
||||
|
||||
#[parser(reader, endian)]
|
||||
fn body_parser(
|
||||
|
|
@ -77,7 +77,7 @@ impl Resource {
|
|||
resource.name.write_options(writer, endian, ())?;
|
||||
resource
|
||||
.link_name
|
||||
.unwrap_or(NameAsobo64::default().into())
|
||||
.unwrap_or_default()
|
||||
.write_options(writer, endian, ())?;
|
||||
(link_header.len() as u32 + body.len() as u32).write_options(writer, endian, ())?;
|
||||
(link_header.len() as u32).write_options(writer, endian, ())?;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use binrw::{BinRead, BinResult, BinWrite, Endian, args, binread, parser};
|
|||
|
||||
use crate::bigfile::resource::ResourceData::SplitData;
|
||||
use crate::lz::lz4_decompress_body_parser;
|
||||
use crate::names::{Name, NameAsobo64};
|
||||
use crate::names::Name;
|
||||
|
||||
#[parser(reader, endian)]
|
||||
pub fn body_parser(decompressed_size: u32, compressed_size: u32) -> BinResult<Vec<u8>> {
|
||||
|
|
@ -64,7 +64,7 @@ impl Resource {
|
|||
resource.name.write_options(writer, endian, ())?;
|
||||
resource
|
||||
.link_name
|
||||
.unwrap_or(NameAsobo64::default().into())
|
||||
.unwrap_or_default()
|
||||
.write_options(writer, endian, ())?;
|
||||
(link_header.len() as u32 + body.len() as u32).write_options(writer, endian, ())?;
|
||||
(link_header.len() as u32).write_options(writer, endian, ())?;
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@ use scanf::sscanf;
|
|||
use schemars::schema::Schema;
|
||||
use schemars::{JsonSchema, SchemaGenerator};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_context::context_scope;
|
||||
|
||||
use crate::helpers::PascalString;
|
||||
use crate::names::{DeserializeNamesContext, SerializeNamesContext};
|
||||
|
||||
#[derive(Debug, Display, Clone, Eq, PartialEq, BinRead, BinWrite)]
|
||||
pub enum Version {
|
||||
|
|
@ -137,13 +135,6 @@ impl From<&str> for Version {
|
|||
|
||||
impl Serialize for Version {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
if let Ok(name_type) = self.try_into() {
|
||||
context_scope(|cx| {
|
||||
if let Ok(names_context) = cx.get::<SerializeNamesContext>() {
|
||||
names_context.set_name_type(name_type);
|
||||
}
|
||||
});
|
||||
}
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
|
@ -151,15 +142,7 @@ impl Serialize for Version {
|
|||
impl<'de> Deserialize<'de> for Version {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
let string = String::deserialize(deserializer)?;
|
||||
let version: Self = string.as_str().into();
|
||||
if let Ok(name_type) = (&version).try_into() {
|
||||
context_scope(|cx| {
|
||||
if let Ok(names_context) = cx.get::<DeserializeNamesContext>() {
|
||||
names_context.set_name_type(name_type);
|
||||
}
|
||||
});
|
||||
}
|
||||
Ok(version)
|
||||
Ok(string.as_str().into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,24 @@
|
|||
macro_rules! bigfiles {
|
||||
($($pattern:pat => $bigfile:ident),* $(,)?) => {
|
||||
impl BigFile {
|
||||
pub fn probe_name_type_platform<R: std::io::Read + std::io::Seek>(
|
||||
reader: &mut R,
|
||||
_platform: crate::bigfile::platforms::Platform,
|
||||
version_override: &Option<crate::bigfile::versions::Version>,
|
||||
) -> crate::BffResult<crate::names::NameType> {
|
||||
use binrw::BinRead;
|
||||
|
||||
let start = reader.stream_position()?;
|
||||
let version: crate::bigfile::versions::Version =
|
||||
crate::helpers::FixedStringNull::<256>::read_be(reader)?
|
||||
.as_str()
|
||||
.into();
|
||||
reader.seek(std::io::SeekFrom::Start(start))?;
|
||||
|
||||
let version = version_override.clone().unwrap_or(version);
|
||||
(&version).try_into()
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub fn read_platform<R: std::io::Read + std::io::Seek>(
|
||||
reader: &mut R,
|
||||
|
|
@ -19,13 +37,20 @@ macro_rules! bigfiles {
|
|||
.as_str()
|
||||
.into();
|
||||
let version = version_override.clone().unwrap_or(version);
|
||||
name_context.scope(|| match (&version, platform) {
|
||||
match (&version, platform) {
|
||||
$($pattern => {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
<$bigfile as BigFileIo>::read(reader, version, platform)
|
||||
if name_context.name_type() != <$bigfile as BigFileIo>::NAME_TYPE {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"NameContext type mismatch: expected {:?}, got {:?}",
|
||||
<$bigfile as BigFileIo>::NAME_TYPE,
|
||||
name_context.name_type()
|
||||
))
|
||||
.into());
|
||||
}
|
||||
name_context.scope(|| <$bigfile as BigFileIo>::read(reader, version, platform))
|
||||
})*
|
||||
_ => Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
|
|
@ -53,15 +78,22 @@ macro_rules! bigfiles {
|
|||
version.to_string()
|
||||
};
|
||||
crate::helpers::FixedStringNull::<256>::write_be(&version_string.into(), writer)?;
|
||||
name_context.scope(|| match (version.clone(), platform) {
|
||||
match (version.clone(), platform) {
|
||||
$($pattern => {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
<$bigfile as BigFileIo>::write(self, writer, tag)
|
||||
if name_context.name_type() != <$bigfile as BigFileIo>::NAME_TYPE {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"NameContext type mismatch: expected {:?}, got {:?}",
|
||||
<$bigfile as BigFileIo>::NAME_TYPE,
|
||||
name_context.name_type()
|
||||
))
|
||||
.into());
|
||||
}
|
||||
name_context.scope(|| <$bigfile as BigFileIo>::write(self, writer, tag))
|
||||
})*
|
||||
(version, platform) => {
|
||||
Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
|
|
@ -78,15 +110,24 @@ macro_rules! bigfiles {
|
|||
let platform = self.manifest.platform;
|
||||
let endian: crate::Endian = platform.into();
|
||||
let version = &self.manifest.version;
|
||||
name_context.scope(|| match (version.clone(), platform) {
|
||||
match (version.clone(), platform) {
|
||||
$($pattern => {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)
|
||||
if name_context.name_type() != <$bigfile as BigFileIo>::NAME_TYPE {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"NameContext type mismatch: expected {:?}, got {:?}",
|
||||
<$bigfile as BigFileIo>::NAME_TYPE,
|
||||
name_context.name_type()
|
||||
))
|
||||
.into());
|
||||
}
|
||||
name_context.scope(|| {
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)
|
||||
})
|
||||
})*
|
||||
(version, platform) => {
|
||||
Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump_bff_resource<W: std::io::Write + std::io::Seek>(
|
||||
|
|
@ -119,15 +160,24 @@ macro_rules! bigfiles {
|
|||
let platform = self.manifest.platform;
|
||||
let endian: crate::Endian = platform.into();
|
||||
let version = &self.manifest.version;
|
||||
name_context.scope(|| match (version.clone(), platform) {
|
||||
match (version.clone(), platform) {
|
||||
$($pattern => {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
|
||||
if name_context.name_type() != <$bigfile as BigFileIo>::NAME_TYPE {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"NameContext type mismatch: expected {:?}, got {:?}",
|
||||
<$bigfile as BigFileIo>::NAME_TYPE,
|
||||
name_context.name_type()
|
||||
))
|
||||
.into());
|
||||
}
|
||||
name_context.scope(|| {
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
|
||||
})
|
||||
})*
|
||||
(version, platform) => {
|
||||
Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
|
|
@ -143,15 +193,24 @@ macro_rules! bigfiles {
|
|||
let crate::bigfile::resource::BffResourceHeader { platform, version } =
|
||||
<crate::bigfile::resource::BffResourceHeader as binrw::BinRead>::read(reader)?;
|
||||
let endian: crate::Endian = platform.into();
|
||||
name_context.scope(|| match (version.clone(), platform) {
|
||||
match (version.clone(), platform) {
|
||||
$($pattern => {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
|
||||
if name_context.name_type() != <$bigfile as BigFileIo>::NAME_TYPE {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"NameContext type mismatch: expected {:?}, got {:?}",
|
||||
<$bigfile as BigFileIo>::NAME_TYPE,
|
||||
name_context.name_type()
|
||||
))
|
||||
.into());
|
||||
}
|
||||
name_context.scope(|| {
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
|
||||
})
|
||||
})*
|
||||
(version, platform) => {
|
||||
Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,15 +229,24 @@ macro_rules! bigfiles {
|
|||
|
||||
let endian: crate::Endian = platform.into();
|
||||
let resource = self;
|
||||
name_context.scope(|| match (version.clone(), platform) {
|
||||
match (version.clone(), platform) {
|
||||
$($pattern => {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)
|
||||
if name_context.name_type() != <$bigfile as BigFileIo>::NAME_TYPE {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"NameContext type mismatch: expected {:?}, got {:?}",
|
||||
<$bigfile as BigFileIo>::NAME_TYPE,
|
||||
name_context.name_type()
|
||||
))
|
||||
.into());
|
||||
}
|
||||
name_context.scope(|| {
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)
|
||||
})
|
||||
})*
|
||||
(version, platform) => {
|
||||
Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
|
|
@ -202,15 +270,24 @@ macro_rules! bigfiles {
|
|||
writer,
|
||||
)?;
|
||||
let resource = self;
|
||||
name_context.scope(|| match (version.clone(), platform) {
|
||||
match (version.clone(), platform) {
|
||||
$($pattern => {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)
|
||||
if name_context.name_type() != <$bigfile as BigFileIo>::NAME_TYPE {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"NameContext type mismatch: expected {:?}, got {:?}",
|
||||
<$bigfile as BigFileIo>::NAME_TYPE,
|
||||
name_context.name_type()
|
||||
))
|
||||
.into());
|
||||
}
|
||||
name_context.scope(|| {
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::dump_resource(resource, writer, endian)?)
|
||||
})
|
||||
})*
|
||||
(version, platform) => {
|
||||
Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
|
|
@ -225,15 +302,24 @@ macro_rules! bigfiles {
|
|||
use crate::traits::BigFileIo;
|
||||
|
||||
let endian: crate::Endian = platform.into();
|
||||
name_context.scope(|| match (version.clone(), platform) {
|
||||
match (version.clone(), platform) {
|
||||
$($pattern => {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
|
||||
if name_context.name_type() != <$bigfile as BigFileIo>::NAME_TYPE {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"NameContext type mismatch: expected {:?}, got {:?}",
|
||||
<$bigfile as BigFileIo>::NAME_TYPE,
|
||||
name_context.name_type()
|
||||
))
|
||||
.into());
|
||||
}
|
||||
name_context.scope(|| {
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
|
||||
})
|
||||
})*
|
||||
(version, platform) => {
|
||||
Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
|
|
@ -248,15 +334,24 @@ macro_rules! bigfiles {
|
|||
let crate::bigfile::resource::BffResourceHeader { platform, version } =
|
||||
<crate::bigfile::resource::BffResourceHeader as binrw::BinRead>::read(reader)?;
|
||||
let endian: crate::Endian = platform.into();
|
||||
name_context.scope(|| match (version.clone(), platform) {
|
||||
match (version.clone(), platform) {
|
||||
$($pattern => {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
|
||||
if name_context.name_type() != <$bigfile as BigFileIo>::NAME_TYPE {
|
||||
return Err(std::io::Error::other(format!(
|
||||
"NameContext type mismatch: expected {:?}, got {:?}",
|
||||
<$bigfile as BigFileIo>::NAME_TYPE,
|
||||
name_context.name_type()
|
||||
))
|
||||
.into());
|
||||
}
|
||||
name_context.scope(|| {
|
||||
Ok(<$bigfile as BigFileIo>::ResourceType::read_resource(reader, endian)?)
|
||||
})
|
||||
})*
|
||||
(version, platform) => {
|
||||
Err(crate::error::UnimplementedVersionPlatformError::new(version, platform).into())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,13 +372,12 @@ macro_rules! bigfiles {
|
|||
) {
|
||||
use crate::traits::BigFileIo;
|
||||
|
||||
let name_context = crate::names::NameContext::default();
|
||||
report.total += 1;
|
||||
// TODO: Probably need a way to do this without specifying a version.
|
||||
$(
|
||||
reader.seek(std::io::SeekFrom::Start(256)).unwrap();
|
||||
report.$bigfile += {
|
||||
name_context.set_name_type(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
let name_context = crate::names::NameContext::new(<$bigfile as BigFileIo>::NAME_TYPE);
|
||||
<bool as Into<usize>>::into(name_context.scope(|| {
|
||||
<$bigfile as BigFileIo>::read(
|
||||
reader,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ macro_rules! classes {
|
|||
)*
|
||||
|
||||
$crate::macros::classes::classes!(@emit_class_enums $($class)*);
|
||||
$crate::macros::classes::classes!(@emit_try_from_name $($class)*);
|
||||
$crate::macros::classes::classes!(@emit_class_name_maps $($class)*);
|
||||
$crate::macros::classes::classes!(@emit_try_from_resource $($class)*);
|
||||
$crate::macros::classes::classes!(@emit_try_into_resource $($class)*);
|
||||
$crate::macros::classes::classes!(@emit_class_try_your_best_report $($class)*);
|
||||
|
|
@ -37,23 +37,76 @@ macro_rules! classes {
|
|||
$($class($crate::macros::classes::classes!(@class_ty $class)),)*
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
#[derive(serde::Serialize, Debug, Clone, Copy, Eq, PartialEq, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub enum ClassType {
|
||||
$($class,)*
|
||||
}
|
||||
};
|
||||
|
||||
(@emit_try_from_name $($class:ident)*) => {
|
||||
impl TryFrom<crate::names::Name> for (ClassType, crate::names::NameStyle, crate::names::NameType) {
|
||||
(@emit_class_name_maps $($class:ident)*) => {
|
||||
impl ClassType {
|
||||
pub fn from_name_and_type(
|
||||
name: crate::names::Name,
|
||||
name_type: crate::names::NameType,
|
||||
) -> Option<Self> {
|
||||
use std::collections::HashMap;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
fn build(
|
||||
name_type: crate::names::NameType,
|
||||
) -> HashMap<crate::names::Name, ClassType> {
|
||||
let mut map = HashMap::new();
|
||||
$(
|
||||
let styled = crate::names::apply_name_style(
|
||||
stringify!($class),
|
||||
crate::names::name_type_style(name_type),
|
||||
);
|
||||
map.insert(
|
||||
crate::names::hash_string_for_type(name_type, styled),
|
||||
ClassType::$class,
|
||||
);
|
||||
)*
|
||||
map
|
||||
}
|
||||
|
||||
static ASOBO32: OnceLock<HashMap<crate::names::Name, ClassType>> = OnceLock::new();
|
||||
static ASOBO_ALTERNATE32: OnceLock<HashMap<crate::names::Name, ClassType>> = OnceLock::new();
|
||||
static KALISTO32: OnceLock<HashMap<crate::names::Name, ClassType>> = OnceLock::new();
|
||||
static BLACKSHEEP32: OnceLock<HashMap<crate::names::Name, ClassType>> = OnceLock::new();
|
||||
static ASOBO64: OnceLock<HashMap<crate::names::Name, ClassType>> = OnceLock::new();
|
||||
static UBISOFT64: OnceLock<HashMap<crate::names::Name, ClassType>> = OnceLock::new();
|
||||
|
||||
let map = match name_type {
|
||||
crate::names::NameType::Asobo32 => {
|
||||
ASOBO32.get_or_init(|| build(crate::names::NameType::Asobo32))
|
||||
}
|
||||
crate::names::NameType::AsoboAlternate32 => ASOBO_ALTERNATE32
|
||||
.get_or_init(|| build(crate::names::NameType::AsoboAlternate32)),
|
||||
crate::names::NameType::Kalisto32 => {
|
||||
KALISTO32.get_or_init(|| build(crate::names::NameType::Kalisto32))
|
||||
}
|
||||
crate::names::NameType::BlackSheep32 => {
|
||||
BLACKSHEEP32.get_or_init(|| build(crate::names::NameType::BlackSheep32))
|
||||
}
|
||||
crate::names::NameType::Asobo64 => {
|
||||
ASOBO64.get_or_init(|| build(crate::names::NameType::Asobo64))
|
||||
}
|
||||
crate::names::NameType::Ubisoft64 => {
|
||||
UBISOFT64.get_or_init(|| build(crate::names::NameType::Ubisoft64))
|
||||
}
|
||||
};
|
||||
|
||||
map.get(&name).copied()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(crate::names::Name, crate::names::NameType)> for ClassType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(name: crate::names::Name) -> Result<(ClassType, crate::names::NameStyle, crate::names::NameType), ()> {
|
||||
$(
|
||||
if let Some((style, name_type)) = $crate::macros::classes::classes!(@class_name_style_type $class name) {
|
||||
return Ok((ClassType::$class, style, name_type));
|
||||
}
|
||||
)*
|
||||
Err(())
|
||||
fn try_from(
|
||||
(name, name_type): (crate::names::Name, crate::names::NameType),
|
||||
) -> Result<ClassType, ()> {
|
||||
ClassType::from_name_and_type(name, name_type).ok_or(())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -63,11 +116,14 @@ macro_rules! classes {
|
|||
type Error = crate::error::Error;
|
||||
|
||||
fn try_from_version_platform(resource: &crate::bigfile::resource::Resource, version: crate::bigfile::versions::Version, platform: crate::bigfile::platforms::Platform) -> crate::BffResult<Class> {
|
||||
$(
|
||||
if $crate::macros::classes::classes!(@class_name_style_type $class resource.class_name).is_some() {
|
||||
return Ok(<&crate::bigfile::resource::Resource as crate::traits::TryIntoVersionPlatform<$crate::macros::classes::classes!(@class_ty $class)>>::try_into_version_platform(resource, version, platform)?.into());
|
||||
}
|
||||
)*
|
||||
let name_type = (&version).try_into()?;
|
||||
if let Some(class_type) = ClassType::from_name_and_type(resource.class_name, name_type) {
|
||||
return match class_type {
|
||||
$(
|
||||
ClassType::$class => Ok(<&crate::bigfile::resource::Resource as crate::traits::TryIntoVersionPlatform<$crate::macros::classes::classes!(@class_ty $class)>>::try_into_version_platform(resource, version, platform)?.into()),
|
||||
)*
|
||||
};
|
||||
}
|
||||
Err(crate::error::UnimplementedClassError::new(resource.name, resource.class_name, version, platform).into())
|
||||
}
|
||||
}
|
||||
|
|
@ -101,12 +157,19 @@ macro_rules! classes {
|
|||
type Report = ClassTryYourBestReport;
|
||||
fn update_report(resource: &crate::bigfile::resource::Resource, platform: crate::bigfile::platforms::Platform, report: &mut Self::Report) {
|
||||
report.total += 1;
|
||||
$(
|
||||
if $crate::macros::classes::classes!(@class_name_style_type $class resource.class_name).is_some() {
|
||||
<$crate::macros::classes::classes!(@class_ty $class) as crate::traits::TryYourBest<&crate::bigfile::resource::Resource>>::update_report(resource, platform, &mut report.$class);
|
||||
return;
|
||||
}
|
||||
)*
|
||||
let Some(name_type) = crate::names::active_name_type() else {
|
||||
return;
|
||||
};
|
||||
let Some(class_type) = ClassType::from_name_and_type(resource.class_name, name_type) else {
|
||||
return;
|
||||
};
|
||||
match class_type {
|
||||
$(
|
||||
ClassType::$class => {
|
||||
<$crate::macros::classes::classes!(@class_ty $class) as crate::traits::TryYourBest<&crate::bigfile::resource::Resource>>::update_report(resource, platform, &mut report.$class);
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -127,8 +190,8 @@ macro_rules! classes {
|
|||
};
|
||||
|
||||
(@emit_class_names_fn $($class:ident)*) => {
|
||||
pub fn class_names() -> &'static[&'static str] {
|
||||
&[$(<$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<&'static str>>::NAME,<$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<&'static str>>::NAME_LEGACY,)*]
|
||||
pub fn class_base_names() -> &'static[&'static str] {
|
||||
&[ $(stringify!($class),)* ]
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -158,28 +221,9 @@ macro_rules! classes {
|
|||
}
|
||||
};
|
||||
|
||||
(@class_name_style_type $class:ident $name:expr) => {{
|
||||
match $name {
|
||||
crate::names::Name::Asobo32(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameAsobo32>>::NAME => Some((crate::names::NameStyle::Z, crate::names::NameType::Asobo32)),
|
||||
crate::names::Name::Asobo32(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameAsobo32>>::NAME_LEGACY => Some((crate::names::NameStyle::Caps, crate::names::NameType::Asobo32)),
|
||||
crate::names::Name::AsoboAlternate32(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameAsoboAlternate32>>::NAME => Some((crate::names::NameStyle::Z, crate::names::NameType::AsoboAlternate32)),
|
||||
crate::names::Name::AsoboAlternate32(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameAsoboAlternate32>>::NAME_LEGACY => Some((crate::names::NameStyle::Caps, crate::names::NameType::AsoboAlternate32)),
|
||||
crate::names::Name::Kalisto32(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameKalisto32>>::NAME => Some((crate::names::NameStyle::Z, crate::names::NameType::Kalisto32)),
|
||||
crate::names::Name::Kalisto32(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameKalisto32>>::NAME_LEGACY => Some((crate::names::NameStyle::Caps, crate::names::NameType::Kalisto32)),
|
||||
crate::names::Name::BlackSheep32(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameBlackSheep32>>::NAME => Some((crate::names::NameStyle::Z, crate::names::NameType::BlackSheep32)),
|
||||
crate::names::Name::BlackSheep32(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameBlackSheep32>>::NAME_LEGACY => Some((crate::names::NameStyle::Caps, crate::names::NameType::BlackSheep32)),
|
||||
crate::names::Name::Asobo64(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameAsobo64>>::NAME => Some((crate::names::NameStyle::Z, crate::names::NameType::Asobo64)),
|
||||
crate::names::Name::Asobo64(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameAsobo64>>::NAME_LEGACY => Some((crate::names::NameStyle::Caps, crate::names::NameType::Asobo64)),
|
||||
crate::names::Name::Ubisoft64(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameUbisoft64>>::NAME => Some((crate::names::NameStyle::Z, crate::names::NameType::Ubisoft64)),
|
||||
crate::names::Name::Ubisoft64(n) if n == <$crate::macros::classes::classes!(@class_ty $class) as crate::traits::NamedClass<crate::names::NameUbisoft64>>::NAME_LEGACY => Some((crate::names::NameStyle::Caps, crate::names::NameType::Ubisoft64)),
|
||||
_ => None,
|
||||
}
|
||||
}};
|
||||
|
||||
(@module $class:ident) => {
|
||||
pastey::paste! {
|
||||
pub mod [<#$class:snake>] {
|
||||
$crate::macros::classes::classes!(@named_class $class);
|
||||
$crate::macros::classes::classes!(@declare_class_kind_impl $class {});
|
||||
}
|
||||
}
|
||||
|
|
@ -196,51 +240,11 @@ macro_rules! classes {
|
|||
pub mod $variant_mod;
|
||||
use self::$variant_mod::$variant;
|
||||
)*
|
||||
$crate::macros::classes::classes!(@named_class $class);
|
||||
$crate::macros::classes::classes!(@declare_class_kind_impl $class { $($pattern => $variant),* });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(@named_class $class:ident) => {
|
||||
pastey::paste! {
|
||||
impl crate::traits::NamedClass<crate::names::NameAsobo32> for $class {
|
||||
const NAME: crate::names::NameAsobo32 = crate::names::NameAsobo32::new(crate::crc::asobo32(stringify!([<$class _Z>]).as_bytes()));
|
||||
const NAME_LEGACY: crate::names::NameAsobo32 = crate::names::NameAsobo32::new(crate::crc::asobo32(stringify!([<$class:upper>]).as_bytes()));
|
||||
}
|
||||
|
||||
impl crate::traits::NamedClass<crate::names::NameAsoboAlternate32> for $class {
|
||||
const NAME: crate::names::NameAsoboAlternate32 = crate::names::NameAsoboAlternate32::new(crate::crc::asobo_alternate32(stringify!([<$class _Z>]).as_bytes()));
|
||||
const NAME_LEGACY: crate::names::NameAsoboAlternate32 = crate::names::NameAsoboAlternate32::new(crate::crc::asobo_alternate32(stringify!([<$class:upper>]).as_bytes()));
|
||||
}
|
||||
|
||||
impl crate::traits::NamedClass<crate::names::NameKalisto32> for $class {
|
||||
const NAME: crate::names::NameKalisto32 = crate::names::NameKalisto32::new(crate::crc::kalisto32(stringify!([<$class _Z>]).as_bytes()));
|
||||
const NAME_LEGACY: crate::names::NameKalisto32 = crate::names::NameKalisto32::new(crate::crc::kalisto32(stringify!([<$class:upper>]).as_bytes()));
|
||||
}
|
||||
|
||||
impl crate::traits::NamedClass<crate::names::NameBlackSheep32> for $class {
|
||||
const NAME: crate::names::NameBlackSheep32 = crate::names::NameBlackSheep32::new(crate::crc::blacksheep32(stringify!([<$class _Z>]).as_bytes()));
|
||||
const NAME_LEGACY: crate::names::NameBlackSheep32 = crate::names::NameBlackSheep32::new(crate::crc::blacksheep32(stringify!([<$class:upper>]).as_bytes()));
|
||||
}
|
||||
|
||||
impl crate::traits::NamedClass<crate::names::NameAsobo64> for $class {
|
||||
const NAME: crate::names::NameAsobo64 = crate::names::NameAsobo64::new(crate::crc::asobo64(stringify!([<$class _Z>]).as_bytes()));
|
||||
const NAME_LEGACY: crate::names::NameAsobo64 = crate::names::NameAsobo64::new(crate::crc::asobo64(stringify!([<$class:upper>]).as_bytes()));
|
||||
}
|
||||
|
||||
impl crate::traits::NamedClass<crate::names::NameUbisoft64> for $class {
|
||||
const NAME: crate::names::NameUbisoft64 = crate::names::NameUbisoft64::new(crate::crc::ubisoft64(stringify!([<$class _Z>]).as_bytes()));
|
||||
const NAME_LEGACY: crate::names::NameUbisoft64 = crate::names::NameUbisoft64::new(crate::crc::ubisoft64(stringify!([<$class:upper>]).as_bytes()));
|
||||
}
|
||||
|
||||
impl crate::traits::NamedClass<&'static str> for $class {
|
||||
const NAME: &'static str = stringify!([<$class _Z>]);
|
||||
const NAME_LEGACY: &'static str = stringify!([<$class:upper>]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(@declare_class_kind_impl $class:ident {}) => {
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, derive_more::From, derive_more::IsVariant, bff_derive::ReferencedNames)]
|
||||
pub enum $class {}
|
||||
|
|
@ -258,7 +262,7 @@ macro_rules! classes {
|
|||
) -> crate::BffResult<$class> {
|
||||
Err(
|
||||
// TODO: Pick the right name based on the algorithm and suffix for the current BigFile
|
||||
crate::error::UnimplementedClassError::new(resource.name, <Self as crate::traits::NamedClass<crate::names::NameAsobo32>>::NAME.into(), version, platform).into(),
|
||||
crate::error::UnimplementedClassError::new(resource.name, resource.class_name, version, platform).into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -360,7 +364,7 @@ macro_rules! classes {
|
|||
})*
|
||||
_ => Err(
|
||||
// TODO: Pick the right name based on the algorithm and suffix for the current BigFile
|
||||
crate::error::UnimplementedClassError::new(resource.name, <Self as crate::traits::NamedClass<crate::names::NameAsobo32>>::NAME.into(), version, platform).into(),
|
||||
crate::error::UnimplementedClassError::new(resource.name, resource.class_name, version, platform).into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,99 @@ macro_rules! names {
|
|||
name_style_transform(style)(string.as_ref())
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, derive_more::Display, derive_more::FromStr)]
|
||||
pub enum NameType {
|
||||
$($name,)*
|
||||
}
|
||||
|
||||
pub const fn name_type_style(name_type: NameType) -> NameStyle {
|
||||
match name_type {
|
||||
$(NameType::$name => NameStyle::$name_style,)*
|
||||
}
|
||||
}
|
||||
|
||||
impl NameType {
|
||||
pub const fn target_bits(self) -> usize {
|
||||
match self {
|
||||
$(
|
||||
NameType::$name => core::mem::size_of::<<$name_hash_function as crate::traits::NameHashFunction>::Target>() * 8,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn is_32_bit(self) -> bool {
|
||||
self.target_bits() == 32
|
||||
}
|
||||
|
||||
pub fn hash_bytes(self, bytes: &[u8]) -> crate::names::Name {
|
||||
match self {
|
||||
$(NameType::$name => hash_bytes_for_hash::<$name_hash_function>(bytes),)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_forced_hash_name<S: AsRef<str>>(self, string: S) -> Option<(crate::names::Name, String)> {
|
||||
match self {
|
||||
$(NameType::$name => parse_forced_hash_name_for_hash::<$name_hash_function, S>(string),)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_from_i32(self, value: i32) -> crate::names::Name {
|
||||
match self {
|
||||
$(NameType::$name => name_from_i32_for_hash::<$name_hash_function>(value),)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value_from_name(self, name: crate::names::Name) -> i64 {
|
||||
match self {
|
||||
$(NameType::$name => name_value_for_hash::<$name_hash_function>(name),)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_name<R: std::io::Read + std::io::Seek>(
|
||||
self,
|
||||
reader: &mut R,
|
||||
endian: binrw::Endian,
|
||||
) -> binrw::BinResult<crate::names::Name> {
|
||||
match self {
|
||||
$(NameType::$name => read_name_for_hash::<$name_hash_function, R>(reader, endian),)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_name<W: std::io::Write + std::io::Seek>(
|
||||
self,
|
||||
writer: &mut W,
|
||||
endian: binrw::Endian,
|
||||
name: crate::names::Name,
|
||||
) -> binrw::BinResult<()> {
|
||||
match self {
|
||||
$(NameType::$name => write_name_for_hash::<$name_hash_function, W>(writer, endian, name),)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize_name_value<S: serde::Serializer>(
|
||||
self,
|
||||
name: crate::names::Name,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
match self {
|
||||
$(NameType::$name => serialize_name_value_for_hash::<$name_hash_function, S>(name, serializer),)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_name<'de, D, F>(
|
||||
self,
|
||||
deserializer: D,
|
||||
add_name: F,
|
||||
) -> Result<crate::names::Name, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
F: FnMut(&str),
|
||||
{
|
||||
match self {
|
||||
$(NameType::$name => deserialize_name_for_hash::<$name_hash_function, D, F>(deserializer, self, add_name),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,6 @@
|
|||
mod big_file_io;
|
||||
mod export;
|
||||
mod name_hash_function;
|
||||
mod named_class;
|
||||
mod referenced_names;
|
||||
mod try_version_platform;
|
||||
mod try_your_best;
|
||||
|
|
@ -9,7 +8,6 @@ mod try_your_best;
|
|||
pub use big_file_io::*;
|
||||
pub use export::*;
|
||||
pub use name_hash_function::*;
|
||||
pub use named_class::*;
|
||||
pub use referenced_names::*;
|
||||
pub use try_version_platform::*;
|
||||
pub use try_your_best::*;
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
pub trait NamedClass<N> {
|
||||
const NAME: N;
|
||||
const NAME_LEGACY: N;
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ use std::fs::{self, File};
|
|||
use std::io::Cursor;
|
||||
|
||||
use bff::bigfile::BigFile;
|
||||
use bff::bigfile::platforms::Platform;
|
||||
use bff::bigfile::resource::{BffClass, BffResourceHeader, Resource};
|
||||
use bff::class::Class;
|
||||
use bff::names::NameContext;
|
||||
|
|
@ -23,6 +24,14 @@ fn assert_no_missing_class_names(bigfile: &BigFile, name_context: &NameContext)
|
|||
}
|
||||
}
|
||||
|
||||
fn probe_name_context<R: std::io::Read + std::io::Seek>(
|
||||
reader: &mut R,
|
||||
platform: Platform,
|
||||
) -> NameContext {
|
||||
let name_type = BigFile::probe_name_type_platform(reader, platform, &None).unwrap();
|
||||
NameContext::new(name_type)
|
||||
}
|
||||
|
||||
#[datatest::data("tests/datasets/bigfile_read.yaml")]
|
||||
#[test]
|
||||
fn read(bigfile_path_str: String) {
|
||||
|
|
@ -30,7 +39,7 @@ fn read(bigfile_path_str: String) {
|
|||
let platform = bigfile_path.extension().unwrap().try_into().unwrap();
|
||||
let f = File::open(bigfile_path).unwrap();
|
||||
let mut reader = BufReader::new(f);
|
||||
let name_context = NameContext::default();
|
||||
let name_context = probe_name_context(&mut reader, platform);
|
||||
let bigfile = BigFile::read_platform(&mut reader, platform, &None, &name_context).unwrap();
|
||||
assert_no_missing_class_names(&bigfile, &name_context);
|
||||
}
|
||||
|
|
@ -42,7 +51,7 @@ fn roundtrip_resources(bigfile_path_str: String) {
|
|||
let platform = bigfile_path.extension().unwrap().try_into().unwrap();
|
||||
let f = File::open(bigfile_path).unwrap();
|
||||
let mut reader = BufReader::new(f);
|
||||
let name_context = NameContext::default();
|
||||
let name_context = probe_name_context(&mut reader, platform);
|
||||
let bigfile = BigFile::read_platform(&mut reader, platform, &None, &name_context).unwrap();
|
||||
let version = bigfile.manifest.version.clone();
|
||||
|
||||
|
|
@ -84,7 +93,7 @@ fn roundtrip(bigfile_path_str: String) {
|
|||
let platform = bigfile_path.extension().unwrap().try_into().unwrap();
|
||||
let data = fs::read(bigfile_path).unwrap();
|
||||
let mut reader = Cursor::new(&data);
|
||||
let name_context = NameContext::default();
|
||||
let name_context = probe_name_context(&mut reader, platform);
|
||||
let bigfile = BigFile::read_platform(&mut reader, platform, &None, &name_context).unwrap();
|
||||
assert_no_missing_class_names(&bigfile, &name_context);
|
||||
|
||||
|
|
@ -103,7 +112,7 @@ fn read_write_read(bigfile_path_str: String) {
|
|||
let platform = bigfile_path.extension().unwrap().try_into().unwrap();
|
||||
let f = File::open(bigfile_path).unwrap();
|
||||
let mut reader = BufReader::new(f);
|
||||
let name_context = NameContext::default();
|
||||
let name_context = probe_name_context(&mut reader, platform);
|
||||
let bigfile = BigFile::read_platform(&mut reader, platform, &None, &name_context).unwrap();
|
||||
assert_no_missing_class_names(&bigfile, &name_context);
|
||||
|
||||
|
|
@ -112,7 +121,7 @@ fn read_write_read(bigfile_path_str: String) {
|
|||
.write(&mut writer, None, &None, &None, None, &name_context)
|
||||
.unwrap();
|
||||
let mut reader = Cursor::new(writer.into_inner());
|
||||
let name_context = NameContext::default();
|
||||
let name_context = probe_name_context(&mut reader, platform);
|
||||
let bigfile2 = BigFile::read_platform(&mut reader, platform, &None, &name_context).unwrap();
|
||||
assert!(bigfile == bigfile2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ fn read_write_read(cps_path_str: String) {
|
|||
let cps_path = resolve_repo_data_path(&cps_path_str);
|
||||
let f = File::open(cps_path).unwrap();
|
||||
let mut reader = BufReader::new(f);
|
||||
let name_context = NameContext::default();
|
||||
name_context.set_name_type(NameType::BlackSheep32);
|
||||
let name_context = NameContext::new(NameType::BlackSheep32);
|
||||
read_default_cps_names(&name_context).unwrap();
|
||||
let cps = Cps::read(&mut reader, Endian::Little, &name_context).unwrap();
|
||||
let mut writer = Cursor::new(Vec::new());
|
||||
|
|
@ -23,8 +22,7 @@ fn read_write_read(cps_path_str: String) {
|
|||
.unwrap();
|
||||
|
||||
let mut reader = Cursor::new(writer.into_inner());
|
||||
let name_context = NameContext::default();
|
||||
name_context.set_name_type(NameType::BlackSheep32);
|
||||
let name_context = NameContext::new(NameType::BlackSheep32);
|
||||
read_default_cps_names(&name_context).unwrap();
|
||||
let cps2 = Cps::read(&mut reader, Endian::Little, &name_context).unwrap();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue