mirror of https://github.com/encounter/nod-rs.git
Move region info from PartitionMeta to Disc
This commit is contained in:
parent
f4638369d1
commit
be4672471d
|
@ -441,7 +441,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nod"
|
name = "nod"
|
||||||
version = "1.4.2"
|
version = "1.4.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler",
|
"adler",
|
||||||
"aes",
|
"aes",
|
||||||
|
@ -464,7 +464,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nodtool"
|
name = "nodtool"
|
||||||
version = "1.4.2"
|
version = "1.4.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argp",
|
"argp",
|
||||||
"base16ct",
|
"base16ct",
|
||||||
|
|
|
@ -9,7 +9,7 @@ strip = "debuginfo"
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "1.4.2"
|
version = "1.4.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.74"
|
rust-version = "1.74"
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
|
|
|
@ -214,7 +214,6 @@ pub(crate) fn read_part_meta(
|
||||||
raw_apploader: raw_apploader.into_boxed_slice(),
|
raw_apploader: raw_apploader.into_boxed_slice(),
|
||||||
raw_fst,
|
raw_fst,
|
||||||
raw_dol: raw_dol.into_boxed_slice(),
|
raw_dol: raw_dol.into_boxed_slice(),
|
||||||
raw_region: None,
|
|
||||||
raw_ticket: None,
|
raw_ticket: None,
|
||||||
raw_tmd: None,
|
raw_tmd: None,
|
||||||
raw_cert_chain: None,
|
raw_cert_chain: None,
|
||||||
|
|
|
@ -365,8 +365,6 @@ pub struct PartitionMeta {
|
||||||
pub raw_fst: Box<[u8]>,
|
pub raw_fst: Box<[u8]>,
|
||||||
/// Main binary (main.dol)
|
/// Main binary (main.dol)
|
||||||
pub raw_dol: Box<[u8]>,
|
pub raw_dol: Box<[u8]>,
|
||||||
/// Disc region info (region.bin, Wii only)
|
|
||||||
pub raw_region: Option<Box<[u8; REGION_SIZE]>>,
|
|
||||||
/// Ticket (ticket.bin, Wii only)
|
/// Ticket (ticket.bin, Wii only)
|
||||||
pub raw_ticket: Option<Box<[u8]>>,
|
pub raw_ticket: Option<Box<[u8]>>,
|
||||||
/// TMD (tmd.bin, Wii only)
|
/// TMD (tmd.bin, Wii only)
|
||||||
|
|
|
@ -10,9 +10,10 @@ use super::{
|
||||||
hashes::{rebuild_hashes, HashTable},
|
hashes::{rebuild_hashes, HashTable},
|
||||||
wii::{PartitionWii, WiiPartEntry, WiiPartGroup, WiiPartitionHeader, WII_PART_GROUP_OFF},
|
wii::{PartitionWii, WiiPartEntry, WiiPartGroup, WiiPartitionHeader, WII_PART_GROUP_OFF},
|
||||||
DiscHeader, PartitionBase, PartitionHeader, PartitionKind, DL_DVD_SIZE, MINI_DVD_SIZE,
|
DiscHeader, PartitionBase, PartitionHeader, PartitionKind, DL_DVD_SIZE, MINI_DVD_SIZE,
|
||||||
SL_DVD_SIZE,
|
REGION_SIZE, SL_DVD_SIZE,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
disc::wii::REGION_OFFSET,
|
||||||
io::block::{Block, BlockIO, PartitionInfo},
|
io::block::{Block, BlockIO, PartitionInfo},
|
||||||
util::read::{read_box, read_from, read_vec},
|
util::read::{read_box, read_from, read_vec},
|
||||||
DiscMeta, Error, OpenOptions, Result, ResultContext, SECTOR_SIZE,
|
DiscMeta, Error, OpenOptions, Result, ResultContext, SECTOR_SIZE,
|
||||||
|
@ -36,6 +37,7 @@ pub struct DiscReader {
|
||||||
disc_header: Box<DiscHeader>,
|
disc_header: Box<DiscHeader>,
|
||||||
pub(crate) partitions: Vec<PartitionInfo>,
|
pub(crate) partitions: Vec<PartitionInfo>,
|
||||||
hash_tables: Vec<HashTable>,
|
hash_tables: Vec<HashTable>,
|
||||||
|
region: Option<[u8; REGION_SIZE]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for DiscReader {
|
impl Clone for DiscReader {
|
||||||
|
@ -52,6 +54,7 @@ impl Clone for DiscReader {
|
||||||
disc_header: self.disc_header.clone(),
|
disc_header: self.disc_header.clone(),
|
||||||
partitions: self.partitions.clone(),
|
partitions: self.partitions.clone(),
|
||||||
hash_tables: self.hash_tables.clone(),
|
hash_tables: self.hash_tables.clone(),
|
||||||
|
region: self.region,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,10 +79,13 @@ impl DiscReader {
|
||||||
disc_header: DiscHeader::new_box_zeroed()?,
|
disc_header: DiscHeader::new_box_zeroed()?,
|
||||||
partitions: vec![],
|
partitions: vec![],
|
||||||
hash_tables: vec![],
|
hash_tables: vec![],
|
||||||
|
region: None,
|
||||||
};
|
};
|
||||||
let disc_header: Box<DiscHeader> = read_box(&mut reader).context("Reading disc header")?;
|
let disc_header: Box<DiscHeader> = read_box(&mut reader).context("Reading disc header")?;
|
||||||
reader.disc_header = disc_header;
|
reader.disc_header = disc_header;
|
||||||
if reader.disc_header.is_wii() {
|
if reader.disc_header.is_wii() {
|
||||||
|
reader.seek(SeekFrom::Start(REGION_OFFSET)).context("Seeking to region info")?;
|
||||||
|
reader.region = Some(read_from(&mut reader).context("Reading region info")?);
|
||||||
reader.partitions = read_partition_info(&mut reader)?;
|
reader.partitions = read_partition_info(&mut reader)?;
|
||||||
// Rebuild hashes if the format requires it
|
// Rebuild hashes if the format requires it
|
||||||
if (options.rebuild_encryption || options.validate_hashes) && meta.needs_hash_recovery {
|
if (options.rebuild_encryption || options.validate_hashes) && meta.needs_hash_recovery {
|
||||||
|
@ -103,10 +109,16 @@ impl DiscReader {
|
||||||
self.io.meta().disc_size.unwrap_or_else(|| guess_disc_size(&self.partitions))
|
self.io.meta().disc_size.unwrap_or_else(|| guess_disc_size(&self.partitions))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn header(&self) -> &DiscHeader { &self.disc_header }
|
pub fn header(&self) -> &DiscHeader { &self.disc_header }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn region(&self) -> Option<&[u8; REGION_SIZE]> { self.region.as_ref() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn partitions(&self) -> &[PartitionInfo] { &self.partitions }
|
pub fn partitions(&self) -> &[PartitionInfo] { &self.partitions }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn meta(&self) -> DiscMeta { self.io.meta() }
|
pub fn meta(&self) -> DiscMeta { self.io.meta() }
|
||||||
|
|
||||||
/// Opens a new, decrypted partition read stream for the specified partition index.
|
/// Opens a new, decrypted partition read stream for the specified partition index.
|
||||||
|
|
|
@ -21,10 +21,7 @@ use crate::{
|
||||||
KeyBytes,
|
KeyBytes,
|
||||||
},
|
},
|
||||||
static_assert,
|
static_assert,
|
||||||
util::{
|
util::{div_rem, read::read_box_slice},
|
||||||
div_rem,
|
|
||||||
read::{read_box, read_box_slice},
|
|
||||||
},
|
|
||||||
Error, OpenOptions, Result, ResultContext,
|
Error, OpenOptions, Result, ResultContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -279,7 +276,6 @@ pub struct PartitionWii {
|
||||||
sector: u32,
|
sector: u32,
|
||||||
pos: u64,
|
pos: u64,
|
||||||
verify: bool,
|
verify: bool,
|
||||||
raw_region: Box<[u8; REGION_SIZE]>,
|
|
||||||
raw_tmd: Box<[u8]>,
|
raw_tmd: Box<[u8]>,
|
||||||
raw_cert_chain: Box<[u8]>,
|
raw_cert_chain: Box<[u8]>,
|
||||||
raw_h3_table: Box<[u8]>,
|
raw_h3_table: Box<[u8]>,
|
||||||
|
@ -297,7 +293,6 @@ impl Clone for PartitionWii {
|
||||||
sector: u32::MAX,
|
sector: u32::MAX,
|
||||||
pos: 0,
|
pos: 0,
|
||||||
verify: self.verify,
|
verify: self.verify,
|
||||||
raw_region: self.raw_region.clone(),
|
|
||||||
raw_tmd: self.raw_tmd.clone(),
|
raw_tmd: self.raw_tmd.clone(),
|
||||||
raw_cert_chain: self.raw_cert_chain.clone(),
|
raw_cert_chain: self.raw_cert_chain.clone(),
|
||||||
raw_h3_table: self.raw_h3_table.clone(),
|
raw_h3_table: self.raw_h3_table.clone(),
|
||||||
|
@ -315,10 +310,6 @@ impl PartitionWii {
|
||||||
let block_size = inner.block_size();
|
let block_size = inner.block_size();
|
||||||
let mut reader = PartitionGC::new(inner, disc_header)?;
|
let mut reader = PartitionGC::new(inner, disc_header)?;
|
||||||
|
|
||||||
// Read region
|
|
||||||
reader.seek(SeekFrom::Start(REGION_OFFSET)).context("Seeking to region offset")?;
|
|
||||||
let raw_region: Box<[u8; REGION_SIZE]> = read_box(&mut reader).context("Reading region")?;
|
|
||||||
|
|
||||||
// Read TMD, cert chain, and H3 table
|
// Read TMD, cert chain, and H3 table
|
||||||
let offset = partition.start_sector as u64 * SECTOR_SIZE as u64;
|
let offset = partition.start_sector as u64 * SECTOR_SIZE as u64;
|
||||||
reader
|
reader
|
||||||
|
@ -348,7 +339,6 @@ impl PartitionWii {
|
||||||
sector: u32::MAX,
|
sector: u32::MAX,
|
||||||
pos: 0,
|
pos: 0,
|
||||||
verify: options.validate_hashes,
|
verify: options.validate_hashes,
|
||||||
raw_region,
|
|
||||||
raw_tmd,
|
raw_tmd,
|
||||||
raw_cert_chain,
|
raw_cert_chain,
|
||||||
raw_h3_table,
|
raw_h3_table,
|
||||||
|
@ -498,7 +488,6 @@ impl PartitionBase for PartitionWii {
|
||||||
fn meta(&mut self) -> Result<Box<PartitionMeta>> {
|
fn meta(&mut self) -> Result<Box<PartitionMeta>> {
|
||||||
self.seek(SeekFrom::Start(0)).context("Seeking to partition header")?;
|
self.seek(SeekFrom::Start(0)).context("Seeking to partition header")?;
|
||||||
let mut meta = read_part_meta(self, true)?;
|
let mut meta = read_part_meta(self, true)?;
|
||||||
meta.raw_region = Some(self.raw_region.clone());
|
|
||||||
meta.raw_ticket = Some(Box::from(self.partition.header.ticket.as_bytes()));
|
meta.raw_ticket = Some(Box::from(self.partition.header.ticket.as_bytes()));
|
||||||
meta.raw_tmd = Some(self.raw_tmd.clone());
|
meta.raw_tmd = Some(self.raw_tmd.clone());
|
||||||
meta.raw_cert_chain = Some(self.raw_cert_chain.clone());
|
meta.raw_cert_chain = Some(self.raw_cert_chain.clone());
|
||||||
|
|
|
@ -66,7 +66,8 @@ use std::{
|
||||||
pub use disc::{
|
pub use disc::{
|
||||||
ApploaderHeader, DiscHeader, DolHeader, FileStream, Fst, Node, NodeKind, OwnedFileStream,
|
ApploaderHeader, DiscHeader, DolHeader, FileStream, Fst, Node, NodeKind, OwnedFileStream,
|
||||||
PartitionBase, PartitionHeader, PartitionKind, PartitionMeta, SignedHeader, Ticket,
|
PartitionBase, PartitionHeader, PartitionKind, PartitionMeta, SignedHeader, Ticket,
|
||||||
TicketLimit, TmdHeader, WindowedStream, BI2_SIZE, BOOT_SIZE, GCN_MAGIC, SECTOR_SIZE, WII_MAGIC,
|
TicketLimit, TmdHeader, WindowedStream, BI2_SIZE, BOOT_SIZE, GCN_MAGIC, REGION_SIZE,
|
||||||
|
SECTOR_SIZE, WII_MAGIC,
|
||||||
};
|
};
|
||||||
pub use io::{
|
pub use io::{
|
||||||
block::{DiscStream, PartitionInfo},
|
block::{DiscStream, PartitionInfo},
|
||||||
|
@ -209,6 +210,12 @@ impl Disc {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn header(&self) -> &DiscHeader { self.reader.header() }
|
pub fn header(&self) -> &DiscHeader { self.reader.header() }
|
||||||
|
|
||||||
|
/// The Wii disc's region information.
|
||||||
|
///
|
||||||
|
/// **GameCube**: This will return `None`.
|
||||||
|
#[inline]
|
||||||
|
pub fn region(&self) -> Option<&[u8; REGION_SIZE]> { self.reader.region() }
|
||||||
|
|
||||||
/// Returns extra metadata included in the disc file format, if any.
|
/// Returns extra metadata included in the disc file format, if any.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn meta(&self) -> DiscMeta { self.reader.meta() }
|
pub fn meta(&self) -> DiscMeta { self.reader.meta() }
|
||||||
|
|
|
@ -9,8 +9,7 @@ use std::{
|
||||||
use argp::FromArgs;
|
use argp::FromArgs;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nod::{
|
use nod::{
|
||||||
Disc, DiscHeader, Fst, Node, OpenOptions, PartitionBase, PartitionKind, PartitionMeta,
|
Disc, Fst, Node, OpenOptions, PartitionBase, PartitionKind, PartitionMeta, ResultContext,
|
||||||
ResultContext,
|
|
||||||
};
|
};
|
||||||
use size::{Base, Size};
|
use size::{Base, Size};
|
||||||
use zerocopy::IntoBytes;
|
use zerocopy::IntoBytes;
|
||||||
|
@ -65,38 +64,38 @@ pub fn run(args: Args) -> nod::Result<()> {
|
||||||
let mut out_dir = output_dir.clone();
|
let mut out_dir = output_dir.clone();
|
||||||
out_dir.push(info.kind.dir_name().as_ref());
|
out_dir.push(info.kind.dir_name().as_ref());
|
||||||
let mut partition = disc.open_partition(info.index)?;
|
let mut partition = disc.open_partition(info.index)?;
|
||||||
extract_partition(header, partition.as_mut(), &out_dir, is_wii, args.quiet)?;
|
extract_partition(&disc, partition.as_mut(), &out_dir, is_wii, args.quiet)?;
|
||||||
}
|
}
|
||||||
} else if partition.eq_ignore_ascii_case("data") {
|
} else if partition.eq_ignore_ascii_case("data") {
|
||||||
let mut partition = disc.open_partition_kind(PartitionKind::Data)?;
|
let mut partition = disc.open_partition_kind(PartitionKind::Data)?;
|
||||||
extract_partition(header, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
extract_partition(&disc, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
||||||
} else if partition.eq_ignore_ascii_case("update") {
|
} else if partition.eq_ignore_ascii_case("update") {
|
||||||
let mut partition = disc.open_partition_kind(PartitionKind::Update)?;
|
let mut partition = disc.open_partition_kind(PartitionKind::Update)?;
|
||||||
extract_partition(header, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
extract_partition(&disc, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
||||||
} else if partition.eq_ignore_ascii_case("channel") {
|
} else if partition.eq_ignore_ascii_case("channel") {
|
||||||
let mut partition = disc.open_partition_kind(PartitionKind::Channel)?;
|
let mut partition = disc.open_partition_kind(PartitionKind::Channel)?;
|
||||||
extract_partition(header, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
extract_partition(&disc, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
||||||
} else {
|
} else {
|
||||||
let idx = partition.parse::<usize>().map_err(|_| "Invalid partition index")?;
|
let idx = partition.parse::<usize>().map_err(|_| "Invalid partition index")?;
|
||||||
let mut partition = disc.open_partition(idx)?;
|
let mut partition = disc.open_partition(idx)?;
|
||||||
extract_partition(header, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
extract_partition(&disc, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut partition = disc.open_partition_kind(PartitionKind::Data)?;
|
let mut partition = disc.open_partition_kind(PartitionKind::Data)?;
|
||||||
extract_partition(header, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
extract_partition(&disc, partition.as_mut(), &output_dir, is_wii, args.quiet)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_partition(
|
fn extract_partition(
|
||||||
header: &DiscHeader,
|
disc: &Disc,
|
||||||
partition: &mut dyn PartitionBase,
|
partition: &mut dyn PartitionBase,
|
||||||
out_dir: &Path,
|
out_dir: &Path,
|
||||||
is_wii: bool,
|
is_wii: bool,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
) -> nod::Result<()> {
|
) -> nod::Result<()> {
|
||||||
let meta = partition.meta()?;
|
let meta = partition.meta()?;
|
||||||
extract_sys_files(header, meta.as_ref(), out_dir, quiet)?;
|
extract_sys_files(disc, meta.as_ref(), out_dir, quiet)?;
|
||||||
|
|
||||||
// Extract FST
|
// Extract FST
|
||||||
let files_dir = out_dir.join("files");
|
let files_dir = out_dir.join("files");
|
||||||
|
@ -132,7 +131,7 @@ fn extract_partition(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_sys_files(
|
fn extract_sys_files(
|
||||||
header: &DiscHeader,
|
disc: &Disc,
|
||||||
data: &PartitionMeta,
|
data: &PartitionMeta,
|
||||||
out_dir: &Path,
|
out_dir: &Path,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
|
@ -147,12 +146,13 @@ fn extract_sys_files(
|
||||||
extract_file(data.raw_dol.as_ref(), &sys_dir.join("main.dol"), quiet)?;
|
extract_file(data.raw_dol.as_ref(), &sys_dir.join("main.dol"), quiet)?;
|
||||||
|
|
||||||
// Wii files
|
// Wii files
|
||||||
if header.is_wii() {
|
let disc_header = disc.header();
|
||||||
|
if disc_header.is_wii() {
|
||||||
let disc_dir = out_dir.join("disc");
|
let disc_dir = out_dir.join("disc");
|
||||||
fs::create_dir_all(&disc_dir)
|
fs::create_dir_all(&disc_dir)
|
||||||
.with_context(|| format!("Creating directory {}", display(&disc_dir)))?;
|
.with_context(|| format!("Creating directory {}", display(&disc_dir)))?;
|
||||||
extract_file(&header.as_bytes()[..0x100], &disc_dir.join("header.bin"), quiet)?;
|
extract_file(&disc_header.as_bytes()[..0x100], &disc_dir.join("header.bin"), quiet)?;
|
||||||
if let Some(region) = data.raw_region.as_deref() {
|
if let Some(region) = disc.region() {
|
||||||
extract_file(region, &disc_dir.join("region.bin"), quiet)?;
|
extract_file(region, &disc_dir.join("region.bin"), quiet)?;
|
||||||
}
|
}
|
||||||
if let Some(ticket) = data.raw_ticket.as_deref() {
|
if let Some(ticket) = data.raw_ticket.as_deref() {
|
||||||
|
|
Loading…
Reference in New Issue