mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-06-07 07:03:32 +00:00
Add header_type
and custom_type
to extract config
Extract configuration is now emitted in the output config, so tooling can load and perform their own tasks on extracted assets without having to parse YAML. `header_type`: - `symbol` (default): Emit a full symbol declaration. - `raw`: Emit raw array data (for wrapping in your own declaration) - `none`: Don't emit a header at all. (For custom processing) `custom_type`/`custom_data`: Passed through to the output config as-is for custom tasks.
This commit is contained in:
parent
f984bc3fb2
commit
146c4d2f8c
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -348,7 +348,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "decomp-toolkit"
|
name = "decomp-toolkit"
|
||||||
version = "1.1.4"
|
version = "1.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ar",
|
"ar",
|
||||||
|
@ -3,7 +3,7 @@ name = "decomp-toolkit"
|
|||||||
description = "Yet another GameCube/Wii decompilation toolkit."
|
description = "Yet another GameCube/Wii decompilation toolkit."
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
version = "1.1.4"
|
version = "1.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
repository = "https://github.com/encounter/decomp-toolkit"
|
repository = "https://github.com/encounter/decomp-toolkit"
|
||||||
|
@ -5,6 +5,7 @@ use std::{
|
|||||||
fs::DirBuilder,
|
fs::DirBuilder,
|
||||||
io::{Cursor, Seek, Write},
|
io::{Cursor, Seek, Write},
|
||||||
mem::take,
|
mem::take,
|
||||||
|
str::FromStr,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
util::{
|
util::{
|
||||||
asm::write_asm,
|
asm::write_asm,
|
||||||
bin2c::bin2c,
|
bin2c::{bin2c, HeaderKind},
|
||||||
comment::MWComment,
|
comment::MWComment,
|
||||||
config::{
|
config::{
|
||||||
apply_splits_file, apply_symbols_file, is_auto_symbol, signed_hex_serde,
|
apply_splits_file, apply_symbols_file, is_auto_symbol, signed_hex_serde,
|
||||||
@ -303,6 +304,20 @@ pub struct ExtractConfig {
|
|||||||
/// Path is relative to `out_dir/include`.
|
/// Path is relative to `out_dir/include`.
|
||||||
#[serde(with = "unix_path_serde_option", default, skip_serializing_if = "Option::is_none")]
|
#[serde(with = "unix_path_serde_option", default, skip_serializing_if = "Option::is_none")]
|
||||||
pub header: Option<Utf8UnixPathBuf>,
|
pub header: Option<Utf8UnixPathBuf>,
|
||||||
|
/// The type for the extracted symbol in the header file. By default, the header will emit
|
||||||
|
/// a full symbol declaration (a.k.a. `symbol`), but this can be set to `raw` to emit the raw
|
||||||
|
/// data as a byte array. `none` avoids emitting a header entirely, in which case the `header`
|
||||||
|
/// field can be used by external asset processing.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub header_type: Option<String>,
|
||||||
|
/// A user-defined type for use with external asset processing. This value is simply passed
|
||||||
|
/// through to the `custom_type` field in the output config.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub custom_type: Option<String>,
|
||||||
|
/// User-defined data for use with external asset processing. This value is simply passed
|
||||||
|
/// through to the `custom_data` field in the output config.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub custom_data: Option<serde_json::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A relocation that should be blocked.
|
/// A relocation that should be blocked.
|
||||||
@ -364,6 +379,19 @@ pub struct OutputModule {
|
|||||||
pub ldscript: Utf8UnixPathBuf,
|
pub ldscript: Utf8UnixPathBuf,
|
||||||
pub entry: Option<String>,
|
pub entry: Option<String>,
|
||||||
pub units: Vec<OutputUnit>,
|
pub units: Vec<OutputUnit>,
|
||||||
|
pub extract: Vec<OutputExtract>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
|
pub struct OutputExtract {
|
||||||
|
pub symbol: String,
|
||||||
|
#[serde(with = "unix_path_serde_option")]
|
||||||
|
pub binary: Option<Utf8UnixPathBuf>,
|
||||||
|
#[serde(with = "unix_path_serde_option")]
|
||||||
|
pub header: Option<Utf8UnixPathBuf>,
|
||||||
|
pub header_type: String,
|
||||||
|
pub custom_type: Option<String>,
|
||||||
|
pub custom_data: Option<serde_json::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, Hash)]
|
||||||
@ -938,6 +966,7 @@ fn split_write_obj(
|
|||||||
ldscript: out_dir.join("ldscript.lcf").with_unix_encoding(),
|
ldscript: out_dir.join("ldscript.lcf").with_unix_encoding(),
|
||||||
units: Vec::with_capacity(split_objs.len()),
|
units: Vec::with_capacity(split_objs.len()),
|
||||||
entry,
|
entry,
|
||||||
|
extract: Vec::with_capacity(module.config.extract.len()),
|
||||||
};
|
};
|
||||||
for (unit, split_obj) in module.obj.link_order.iter().zip(&split_objs) {
|
for (unit, split_obj) in module.obj.link_order.iter().zip(&split_objs) {
|
||||||
let out_obj = write_elf(split_obj, config.export_all)?;
|
let out_obj = write_elf(split_obj, config.export_all)?;
|
||||||
@ -975,8 +1004,17 @@ fn split_write_obj(
|
|||||||
write_if_changed(&out_path, data)?;
|
write_if_changed(&out_path, data)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let header_kind = match extract.header_type.as_deref() {
|
||||||
|
Some(value) => match HeaderKind::from_str(value) {
|
||||||
|
Ok(kind) => kind,
|
||||||
|
Err(()) => bail!("Invalid header type '{}'", value),
|
||||||
|
},
|
||||||
|
_ => HeaderKind::Symbol,
|
||||||
|
};
|
||||||
|
|
||||||
|
if header_kind != HeaderKind::None {
|
||||||
if let Some(header) = &extract.header {
|
if let Some(header) = &extract.header {
|
||||||
let header_string = bin2c(symbol, section, data);
|
let header_string = bin2c(symbol, section, data, header_kind);
|
||||||
let out_path = base_dir.join("include").join(header.with_encoding());
|
let out_path = base_dir.join("include").join(header.with_encoding());
|
||||||
if let Some(parent) = out_path.parent() {
|
if let Some(parent) = out_path.parent() {
|
||||||
DirBuilder::new().recursive(true).create(parent)?;
|
DirBuilder::new().recursive(true).create(parent)?;
|
||||||
@ -985,6 +1023,17 @@ fn split_write_obj(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy to output config
|
||||||
|
out_config.extract.push(OutputExtract {
|
||||||
|
symbol: symbol.name.clone(),
|
||||||
|
binary: extract.binary.clone(),
|
||||||
|
header: extract.header.clone(),
|
||||||
|
header_type: header_kind.to_string(),
|
||||||
|
custom_type: extract.custom_type.clone(),
|
||||||
|
custom_data: extract.custom_data.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Generate ldscript.lcf
|
// Generate ldscript.lcf
|
||||||
let ldscript_template = if let Some(template_path) = &module.config.ldscript_template {
|
let ldscript_template = if let Some(template_path) = &module.config.ldscript_template {
|
||||||
let template_path = template_path.with_encoding();
|
let template_path = template_path.with_encoding();
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::{fmt, str::FromStr};
|
||||||
|
|
||||||
use crate::obj::{ObjSection, ObjSectionKind, ObjSymbol};
|
use crate::obj::{ObjSection, ObjSectionKind, ObjSymbol};
|
||||||
|
|
||||||
const PROLOGUE: &str = r#"
|
const PROLOGUE: &str = r#"
|
||||||
@ -13,8 +15,50 @@ const PROLOGUE: &str = r#"
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
/// The output header type.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum HeaderKind {
|
||||||
|
/// Do not generate a header. (Used for custom processing)
|
||||||
|
None,
|
||||||
|
/// A full symbol definition.
|
||||||
|
Symbol,
|
||||||
|
/// Raw array data.
|
||||||
|
Raw,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for HeaderKind {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"none" => Ok(Self::None),
|
||||||
|
"symbol" => Ok(Self::Symbol),
|
||||||
|
"raw" => Ok(Self::Raw),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for HeaderKind {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::None => write!(f, "none"),
|
||||||
|
Self::Symbol => write!(f, "symbol"),
|
||||||
|
Self::Raw => write!(f, "raw"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts a binary blob into a C array.
|
/// Converts a binary blob into a C array.
|
||||||
pub fn bin2c(symbol: &ObjSymbol, section: &ObjSection, data: &[u8]) -> String {
|
pub fn bin2c(symbol: &ObjSymbol, section: &ObjSection, data: &[u8], kind: HeaderKind) -> String {
|
||||||
|
match kind {
|
||||||
|
HeaderKind::None => String::new(),
|
||||||
|
HeaderKind::Symbol => bin2c_symbol(symbol, section, data),
|
||||||
|
HeaderKind::Raw => bin2c_raw(data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bin2c_symbol(symbol: &ObjSymbol, section: &ObjSection, data: &[u8]) -> String {
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
output.push_str(PROLOGUE);
|
output.push_str(PROLOGUE);
|
||||||
output.push_str(&format!(
|
output.push_str(&format!(
|
||||||
@ -41,3 +85,19 @@ pub fn bin2c(symbol: &ObjSymbol, section: &ObjSection, data: &[u8]) -> String {
|
|||||||
output.push_str("\n};\n");
|
output.push_str("\n};\n");
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bin2c_raw(data: &[u8]) -> String {
|
||||||
|
let mut output = String::new();
|
||||||
|
for (i, byte) in data.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
if i % 16 == 0 {
|
||||||
|
output.push('\n');
|
||||||
|
} else {
|
||||||
|
output.push(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.push_str(&format!("0x{:02X},", byte));
|
||||||
|
}
|
||||||
|
output.push('\n');
|
||||||
|
output
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user