Reformat with rustfmt

This commit is contained in:
Luke Street 2021-08-25 11:22:17 -04:00
parent 9df1aa4149
commit aaf9d37306
11 changed files with 252 additions and 216 deletions

8
rustfmt.toml Normal file
View File

@ -0,0 +1,8 @@
fn_single_line = true
group_imports = "StdExternalCrate"
imports_granularity = "Crate"
overflow_delimited_expr = true
reorder_impl_items = true
use_field_init_shorthand = true
use_small_heuristics = "Max"
where_single_line = true

View File

@ -1,14 +1,17 @@
use std::{env, fs, io};
use std::io::BufWriter;
use std::path::{Path, PathBuf};
use std::{
env, fs, io,
io::BufWriter,
path::{Path, PathBuf},
};
use clap::{AppSettings, clap_app};
use clap::{clap_app, AppSettings};
use file_size;
use nod::disc::{new_disc_base, PartReadStream};
use nod::fst::NodeType;
use nod::io::{has_extension, new_disc_io};
use nod::Result;
use nod::{
disc::{new_disc_base, PartReadStream},
fst::NodeType,
io::{has_extension, new_disc_io},
Result,
};
fn main() -> Result<()> {
let matches = clap_app!(nodtool =>
@ -36,7 +39,8 @@ Phillip Stephens (Antidote)")
(@arg DIR: "Output directory (optional)")
(@arg quiet: -q "Quiet output")
)
).get_matches();
)
.get_matches();
if let Some(matches) = matches.subcommand_matches("extract") {
let file: PathBuf = PathBuf::from(matches.value_of("FILE").unwrap());
let output_dir: PathBuf;
@ -61,12 +65,20 @@ Phillip Stephens (Antidote)")
Result::Ok(())
}
fn extract_node(node: &NodeType, partition: &mut dyn PartReadStream, base_path: &Path) -> io::Result<()> {
fn extract_node(
node: &NodeType,
partition: &mut dyn PartReadStream,
base_path: &Path,
) -> io::Result<()> {
match node {
NodeType::File(v) => {
let mut file_path = base_path.to_owned();
file_path.push(v.name.as_ref());
println!("Extracting {} (size: {})", file_path.to_string_lossy(), file_size::fit_4(v.length as u64));
println!(
"Extracting {} (size: {})",
file_path.to_string_lossy(),
file_size::fit_4(v.length as u64)
);
let file = fs::File::create(file_path)?;
let mut buf_writer = BufWriter::with_capacity(partition.ideal_buffer_size(), file);
io::copy(&mut partition.begin_file_stream(v)?, &mut buf_writer)?;

View File

@ -1,29 +1,31 @@
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::{
io,
io::{Read, Seek, SeekFrom},
};
use binread::prelude::*;
use crate::{div_rem, Result};
use crate::disc::{BI2Header, BUFFER_SIZE, DiscBase, DiscIO, Header, PartHeader, PartReadStream};
use crate::fst::{find_node, Node, node_parser, NodeKind, NodeType};
use crate::streams::{ReadStream, SharedWindowedReadStream};
use crate::{
disc::{BI2Header, DiscBase, DiscIO, Header, PartHeader, PartReadStream, BUFFER_SIZE},
div_rem,
fst::{find_node, node_parser, Node, NodeKind, NodeType},
streams::{ReadStream, SharedWindowedReadStream},
Result,
};
pub(crate) struct DiscGCN {
pub(crate) header: Header,
}
pub(crate) fn new_disc_gcn(header: Header) -> Result<DiscGCN> {
Result::Ok(DiscGCN {
header
})
}
pub(crate) fn new_disc_gcn(header: Header) -> Result<DiscGCN> { Result::Ok(DiscGCN { header }) }
impl DiscBase for DiscGCN {
fn get_header(&self) -> &Header {
&self.header
}
fn get_header(&self) -> &Header { &self.header }
fn get_data_partition<'a>(&self, disc_io: &'a mut dyn DiscIO) -> Result<Box<dyn PartReadStream + 'a>> {
fn get_data_partition<'a>(
&self,
disc_io: &'a mut dyn DiscIO,
) -> Result<Box<dyn PartReadStream + 'a>> {
Result::Ok(Box::from(GCPartReadStream {
stream: disc_io.begin_read_stream(0)?,
offset: 0,
@ -40,7 +42,6 @@ struct GCPartReadStream<'a> {
buf: [u8; BUFFER_SIZE],
}
impl<'a> Read for GCPartReadStream<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let (mut block, mut block_offset) = div_rem(self.offset as usize, BUFFER_SIZE);
@ -86,15 +87,11 @@ impl<'a> Seek for GCPartReadStream<'a> {
io::Result::Ok(self.offset)
}
fn stream_position(&mut self) -> io::Result<u64> {
io::Result::Ok(self.offset)
}
fn stream_position(&mut self) -> io::Result<u64> { io::Result::Ok(self.offset) }
}
impl<'a> ReadStream for GCPartReadStream<'a> {
fn stable_stream_len(&mut self) -> io::Result<u64> {
self.stream.stable_stream_len()
}
fn stable_stream_len(&mut self) -> io::Result<u64> { self.stream.stable_stream_len() }
}
impl<'a> PartReadStream for GCPartReadStream<'a> {
@ -108,9 +105,7 @@ impl<'a> PartReadStream for GCPartReadStream<'a> {
Result::Ok(Box::from(self.read_be::<GCPartition>()?))
}
fn ideal_buffer_size(&self) -> usize {
BUFFER_SIZE
}
fn ideal_buffer_size(&self) -> usize { BUFFER_SIZE }
}
#[derive(Clone, Debug, PartialEq, BinRead)]
@ -123,11 +118,7 @@ pub(crate) struct GCPartition {
}
impl PartHeader for GCPartition {
fn root_node(&self) -> &NodeType {
&self.root_node
}
fn root_node(&self) -> &NodeType { &self.root_node }
fn find_node(&self, path: &str) -> Option<&NodeType> {
find_node(&self.root_node, path)
}
fn find_node(&self, path: &str) -> Option<&NodeType> { find_node(&self.root_node, path) }
}

View File

@ -1,15 +1,16 @@
//! Disc type related logic (GameCube, Wii)
use std::fmt::Debug;
use std::io;
use std::{fmt::Debug, io};
use binread::{BinReaderExt, NullString, prelude::*};
use binread::{prelude::*, BinReaderExt, NullString};
use crate::{Error, Result};
use crate::disc::{gcn::new_disc_gcn, wii::new_disc_wii};
use crate::fst::{Node, NodeType};
use crate::io::DiscIO;
use crate::streams::{ReadStream, SharedWindowedReadStream};
use crate::{
disc::{gcn::new_disc_gcn, wii::new_disc_wii},
fst::{Node, NodeType},
io::DiscIO,
streams::{ReadStream, SharedWindowedReadStream},
Error, Result,
};
pub(crate) mod gcn;
pub(crate) mod wii;
@ -89,7 +90,10 @@ pub trait DiscBase {
/// let disc_base = new_disc_base(disc_io.as_mut())?;
/// let mut partition = disc_base.get_data_partition(disc_io.as_mut())?;
/// ```
fn get_data_partition<'a>(&self, disc_io: &'a mut dyn DiscIO) -> Result<Box<dyn PartReadStream + 'a>>;
fn get_data_partition<'a>(
&self,
disc_io: &'a mut dyn DiscIO,
) -> Result<Box<dyn PartReadStream + 'a>>;
}
/// Creates a new [`DiscBase`] instance.

View File

@ -1,19 +1,27 @@
use std::{io, io::{Read, Seek, SeekFrom}};
use std::{
io,
io::{Read, Seek, SeekFrom},
};
use aes::{Aes128, NewBlockCipher, Block};
use aes::{Aes128, Block, NewBlockCipher};
use binread::prelude::*;
use block_modes::{block_padding::NoPadding, BlockMode, Cbc};
use sha1::{digest, Digest, Sha1};
use crate::disc::{BI2Header, BUFFER_SIZE, DiscBase, DiscIO, Header, PartHeader, PartReadStream};
use crate::{Error, div_rem, Result, array_ref};
use crate::fst::{find_node, Node, NodeKind, NodeType, node_parser};
use crate::streams::{OwningWindowedReadStream, ReadStream, SharedWindowedReadStream, wrap_windowed};
use crate::{
array_ref,
disc::{BI2Header, DiscBase, DiscIO, Header, PartHeader, PartReadStream, BUFFER_SIZE},
div_rem,
fst::{find_node, node_parser, Node, NodeKind, NodeType},
streams::{wrap_windowed, OwningWindowedReadStream, ReadStream, SharedWindowedReadStream},
Error, Result,
};
type Aes128Cbc = Cbc<Aes128, NoPadding>;
const BLOCK_SIZE: usize = 0x7c00;
const BUFFER_OFFSET: usize = BUFFER_SIZE - BLOCK_SIZE;
#[rustfmt::skip]
const COMMON_KEYS: [[u8; 16]; 2] = [
/* Normal */
[0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7],
@ -185,10 +193,7 @@ pub(crate) struct DiscWii {
}
pub(crate) fn new_disc_wii(mut stream: &mut dyn ReadStream, header: Header) -> Result<DiscWii> {
let mut disc = DiscWii {
header,
part_info: stream.read_be()?,
};
let mut disc = DiscWii { header, part_info: stream.read_be()? };
disc.decrypt_partition_keys()?;
Result::Ok(disc)
}
@ -202,29 +207,38 @@ impl DiscWii {
Aes128Cbc::new(
Aes128::new(&COMMON_KEYS[ticket.common_key_idx as usize].into()),
&iv.into(),
).decrypt(&mut ticket.enc_key)?;
)
.decrypt(&mut ticket.enc_key)?;
}
Result::Ok(())
}
}
impl DiscBase for DiscWii {
fn get_header(&self) -> &Header {
&self.header
}
fn get_header(&self) -> &Header { &self.header }
fn get_data_partition<'a>(&self, disc_io: &'a mut dyn DiscIO) -> Result<Box<dyn PartReadStream + 'a>> {
let part = self.part_info.parts.iter().find(|v| v.part_type == WiiPartType::Data)
fn get_data_partition<'a>(
&self,
disc_io: &'a mut dyn DiscIO,
) -> Result<Box<dyn PartReadStream + 'a>> {
let part = self
.part_info
.parts
.iter()
.find(|v| v.part_type == WiiPartType::Data)
.ok_or(Error::DiscFormat("Failed to locate data partition".to_string()))?;
let data_off = part.part_header.data_off;
let result = Box::new(WiiPartReadStream {
stream: wrap_windowed(
disc_io.begin_read_stream(data_off)?,
data_off, part.part_header.data_size,
data_off,
part.part_header.data_size,
)?,
crypto: if disc_io.has_wii_crypto() {
Aes128::new(&part.part_header.ticket.enc_key.into()).into()
} else { Option::None },
} else {
Option::None
},
offset: 0,
cur_block: u64::MAX,
buf: [0; 0x8000],
@ -254,9 +268,7 @@ impl<'a> PartReadStream for WiiPartReadStream<'a> {
Result::Ok(Box::from(self.read_be::<WiiPartition>()?))
}
fn ideal_buffer_size(&self) -> usize {
BLOCK_SIZE
}
fn ideal_buffer_size(&self) -> usize { BLOCK_SIZE }
}
#[inline(always)]
@ -277,7 +289,9 @@ fn decrypt_block(part: &mut WiiPartReadStream, cluster: usize) -> io::Result<()>
.decrypt(&mut part.buf[BUFFER_OFFSET..])
.expect("Failed to decrypt block");
}
if part.validate_hashes && part.crypto.is_some() /* FIXME NFS validation? */ {
if part.validate_hashes && part.crypto.is_some()
/* FIXME NFS validation? */
{
let (mut group, sub_group) = div_rem(cluster, 8);
group %= 8;
// H0 hashes
@ -287,7 +301,12 @@ fn decrypt_block(part: &mut WiiPartReadStream, cluster: usize) -> io::Result<()>
let expected = as_digest(array_ref![part.buf, i * 20, 20]);
let output = hash.finalize();
if output != expected {
panic!("Invalid hash! (block {:?}) {:?}\n\texpected {:?}", i, output.as_slice(), expected);
panic!(
"Invalid hash! (block {:?}) {:?}\n\texpected {:?}",
i,
output.as_slice(),
expected
);
}
}
// H1 hash
@ -297,7 +316,12 @@ fn decrypt_block(part: &mut WiiPartReadStream, cluster: usize) -> io::Result<()>
let expected = as_digest(array_ref![part.buf, 0x280 + sub_group * 20, 20]);
let output = hash.finalize();
if output != expected {
panic!("Invalid hash! (subgroup {:?}) {:?}\n\texpected {:?}", sub_group, output.as_slice(), expected);
panic!(
"Invalid hash! (subgroup {:?}) {:?}\n\texpected {:?}",
sub_group,
output.as_slice(),
expected
);
}
}
// H2 hash
@ -307,7 +331,12 @@ fn decrypt_block(part: &mut WiiPartReadStream, cluster: usize) -> io::Result<()>
let expected = as_digest(array_ref![part.buf, 0x340 + group * 20, 20]);
let output = hash.finalize();
if output != expected {
panic!("Invalid hash! (group {:?}) {:?}\n\texpected {:?}", group, output.as_slice(), expected);
panic!(
"Invalid hash! (group {:?}) {:?}\n\texpected {:?}",
group,
output.as_slice(),
expected
);
}
}
}
@ -331,9 +360,9 @@ impl<'a> Read for WiiPartReadStream<'a> {
cache_size = BLOCK_SIZE - block_offset;
}
buf[read..read + cache_size]
.copy_from_slice(&self.buf[BUFFER_OFFSET + block_offset..
BUFFER_OFFSET + block_offset + cache_size]);
buf[read..read + cache_size].copy_from_slice(
&self.buf[BUFFER_OFFSET + block_offset..BUFFER_OFFSET + block_offset + cache_size],
);
read += cache_size;
rem -= cache_size;
block_offset = 0;
@ -365,9 +394,7 @@ impl<'a> Seek for WiiPartReadStream<'a> {
io::Result::Ok(self.offset)
}
fn stream_position(&mut self) -> io::Result<u64> {
io::Result::Ok(self.offset)
}
fn stream_position(&mut self) -> io::Result<u64> { io::Result::Ok(self.offset) }
}
impl<'a> ReadStream for WiiPartReadStream<'a> {
@ -386,11 +413,7 @@ pub(crate) struct WiiPartition {
}
impl PartHeader for WiiPartition {
fn root_node(&self) -> &NodeType {
&self.root_node
}
fn root_node(&self) -> &NodeType { &self.root_node }
fn find_node(&self, path: &str) -> Option<&NodeType> {
find_node(&self.root_node, path)
}
fn find_node(&self, path: &str) -> Option<&NodeType> { find_node(&self.root_node, path) }
}

View File

@ -2,7 +2,7 @@
use std::io::{Read, Seek, SeekFrom};
use binread::{derive_binread, NullString, prelude::*, ReadOptions};
use binread::{derive_binread, prelude::*, NullString, ReadOptions};
use encoding_rs::SHIFT_JIS;
/// File system node kind.
@ -64,7 +64,13 @@ fn read_node<R: Read + Seek>(reader: &mut R, ro: &ReadOptions, i: &mut u32) -> B
})
}
fn read_node_name<R: Read + Seek>(reader: &mut R, ro: &ReadOptions, base: u64, node: &mut NodeType, root: bool) -> BinResult<()> {
fn read_node_name<R: Read + Seek>(
reader: &mut R,
ro: &ReadOptions,
base: u64,
node: &mut NodeType,
root: bool,
) -> BinResult<()> {
let mut decode_name = |v: &mut Node| -> BinResult<()> {
if !root {
let offset = base + v.name_offset as u64;
@ -82,7 +88,9 @@ fn read_node_name<R: Read + Seek>(reader: &mut R, ro: &ReadOptions, base: u64, n
BinResult::Ok(())
};
match node {
NodeType::File(v) => { decode_name(v)?; }
NodeType::File(v) => {
decode_name(v)?;
}
NodeType::Directory(v, c) => {
decode_name(v)?;
for x in c {
@ -93,7 +101,11 @@ fn read_node_name<R: Read + Seek>(reader: &mut R, ro: &ReadOptions, base: u64, n
BinResult::Ok(())
}
pub(crate) fn node_parser<R: Read + Seek>(reader: &mut R, ro: &ReadOptions, _: ()) -> BinResult<NodeType> {
pub(crate) fn node_parser<R: Read + Seek>(
reader: &mut R,
ro: &ReadOptions,
_: (),
) -> BinResult<NodeType> {
let mut node = read_node(reader, ro, &mut 0)?;
let base = reader.stream_position()?;
read_node_name(reader, ro, base, &mut node, true)?;
@ -103,7 +115,9 @@ pub(crate) fn node_parser<R: Read + Seek>(reader: &mut R, ro: &ReadOptions, _: (
fn matches_name(node: &NodeType, name: &str) -> bool {
match node {
NodeType::File(v) => v.name.as_ref().eq_ignore_ascii_case(name),
NodeType::Directory(v, _) => v.name.is_empty() /* root */ || v.name.as_ref().eq_ignore_ascii_case(name),
NodeType::Directory(v, _) => {
v.name.is_empty() /* root */ || v.name.as_ref().eq_ignore_ascii_case(name)
}
}
}
@ -114,11 +128,7 @@ pub(crate) fn find_node<'a>(mut node: &'a NodeType, path: &str) -> Option<&'a No
if matches_name(node, current.unwrap()) {
match node {
NodeType::File(_) => {
return if split.next().is_none() {
Option::Some(node)
} else {
Option::None
};
return if split.next().is_none() { Option::Some(node) } else { Option::None };
}
NodeType::Directory(v, c) => {
// Find child

View File

@ -1,11 +1,11 @@
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::io;
use std::path::{PathBuf, Path};
use std::path::{Path, PathBuf};
use crate::io::DiscIO;
use crate::streams::ReadStream;
use crate::Result;
use crate::streams::ReadStream;
pub(crate) struct DiscIOISO {
pub(crate) filename: PathBuf,

View File

@ -1,11 +1,12 @@
//! Disc file format related logic (ISO, NFS, etc)
use std::{fs, io};
use std::path::Path;
use std::{fs, io, path::Path};
use crate::{Error, Result};
use crate::io::{iso::new_disc_io_iso, nfs::new_disc_io_nfs};
use crate::streams::ReadStream;
use crate::{
io::{iso::new_disc_io_iso, nfs::new_disc_io_nfs},
streams::ReadStream,
Error, Result,
};
pub(crate) mod iso;
pub(crate) mod nfs;
@ -27,7 +28,9 @@ pub fn has_extension(filename: &Path, extension: &str) -> bool {
// TODO use with Rust 1.53+
// ext.eq_ignore_ascii_case(extension)
ext.to_str().unwrap_or("").eq_ignore_ascii_case(extension)
} else { false }
} else {
false
}
}
/// Creates a new [`DiscIO`] instance.
@ -57,9 +60,10 @@ pub fn new_disc_io(filename: &Path) -> Result<Box<dyn DiscIO>> {
));
}
if !meta.unwrap().is_file() {
return Result::Err(Error::DiscFormat(
format!("Input is not a file: {}", filename.to_string_lossy())
));
return Result::Err(Error::DiscFormat(format!(
"Input is not a file: {}",
filename.to_string_lossy()
)));
}
if has_extension(path, "iso") {
Result::Ok(Box::from(new_disc_io_iso(path)?))

View File

@ -1,13 +1,15 @@
use std::{fs::File, io, io::{Read, Seek, SeekFrom}, path::{Path, PathBuf}};
use std::{
fs::File,
io,
io::{Read, Seek, SeekFrom},
path::{Path, PathBuf},
};
use aes::{Aes128, NewBlockCipher};
use binread::{derive_binread, prelude::*};
use block_modes::{block_padding::NoPadding, BlockMode, Cbc};
use crate::disc::{BUFFER_SIZE};
use crate::io::DiscIO;
use crate::{Error,Result};
use crate::streams::ReadStream;
use crate::{disc::BUFFER_SIZE, io::DiscIO, streams::ReadStream, Error, Result};
type Aes128Cbc = Cbc<Aes128, NoPadding>;
@ -39,18 +41,18 @@ pub(crate) struct FBO {
pub(crate) offset: u32,
}
pub(crate) fn fbo_max() -> FBO {
FBO {
file: u32::MAX,
block: u32::MAX,
l_block: u32::MAX,
offset: u32::MAX,
impl Default for FBO {
fn default() -> Self {
FBO { file: u32::MAX, block: u32::MAX, l_block: u32::MAX, offset: u32::MAX }
}
}
impl NFSHeader {
pub(crate) fn calculate_num_files(&self) -> u32 {
let total_block_count = self.lba_ranges.iter().take(self.lba_range_count as usize)
let total_block_count = self
.lba_ranges
.iter()
.take(self.lba_range_count as usize)
.fold(0u32, |acc, range| acc + range.num_blocks);
(((total_block_count as u64) * 0x8000u64 + (0x200u64 + 0xF9FFFFFu64)) / 0xFA00000u64) as u32
}
@ -68,14 +70,9 @@ impl NFSHeader {
physical_block += range.num_blocks;
}
if block == u32::MAX {
fbo_max()
FBO::default()
} else {
FBO {
file: block / 8000,
block: block % 8000,
l_block: block_div,
offset: block_off,
}
FBO { file: block / 8000, block: block % 8000, l_block: block_div, offset: block_off }
}
}
}
@ -87,11 +84,8 @@ pub(crate) struct DiscIONFS {
}
pub(crate) fn new_disc_io_nfs(directory: &Path) -> Result<DiscIONFS> {
let mut disc_io = DiscIONFS {
directory: directory.to_owned(),
key: [0; 16],
header: Option::None,
};
let mut disc_io =
DiscIONFS { directory: directory.to_owned(), key: [0; 16], header: Option::None };
disc_io.validate_files()?;
Result::Ok(disc_io)
}
@ -124,9 +118,10 @@ impl<'a> NFSReadStream<'a> {
fn set_cur_block(&mut self, cur_block: u32) -> io::Result<()> {
self.cur_block = cur_block;
self.file.as_ref().unwrap().seek(
SeekFrom::Start(self.cur_block as u64 * BUFFER_SIZE as u64 + 0x200u64)
)?;
self.file
.as_ref()
.unwrap()
.seek(SeekFrom::Start(self.cur_block as u64 * BUFFER_SIZE as u64 + 0x200u64))?;
io::Result::Ok(())
}
@ -164,6 +159,7 @@ impl<'a> NFSReadStream<'a> {
}
// Decrypt
#[rustfmt::skip]
let iv: [u8; 16] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
(phys_addr.l_block & 0xFF) as u8,
@ -171,8 +167,7 @@ impl<'a> NFSReadStream<'a> {
((phys_addr.l_block >> 16) & 0xFF) as u8,
((phys_addr.l_block >> 24) & 0xFF) as u8,
];
Aes128Cbc::new(self.crypto.clone(), &iv.into())
.decrypt(&mut self.buf)?;
Aes128Cbc::new(self.crypto.clone(), &iv.into()).decrypt(&mut self.buf)?;
Result::Ok(())
}
@ -188,7 +183,8 @@ impl<'a> Read for NFSReadStream<'a> {
let mut read: usize = 0;
while rem > 0 {
let mut read_size = rem;
let block_offset: usize = if self.phys_addr.offset == u32::MAX { 0 } else { self.phys_addr.offset as usize };
let block_offset: usize =
if self.phys_addr.offset == u32::MAX { 0 } else { self.phys_addr.offset as usize };
if read_size + block_offset > BUFFER_SIZE {
read_size = BUFFER_SIZE - block_offset
}
@ -197,11 +193,10 @@ impl<'a> Read for NFSReadStream<'a> {
read += read_size;
rem -= read_size;
self.offset += read_size as u64;
self.set_logical_addr(self.offset)
.map_err(|v| match v {
Error::Io(_, v) => v,
_ => io::Error::from(io::ErrorKind::Other)
})?;
self.set_logical_addr(self.offset).map_err(|v| match v {
Error::Io(_, v) => v,
_ => io::Error::from(io::ErrorKind::Other),
})?;
}
io::Result::Ok(read)
}
@ -214,23 +209,18 @@ impl<'a> Seek for NFSReadStream<'a> {
SeekFrom::End(v) => (self.stable_stream_len()? as i64 + v) as u64,
SeekFrom::Current(v) => (self.offset as i64 + v) as u64,
};
self.set_logical_addr(self.offset)
.map_err(|v| match v {
Error::Io(_, v) => v,
_ => io::Error::from(io::ErrorKind::Other)
})?;
self.set_logical_addr(self.offset).map_err(|v| match v {
Error::Io(_, v) => v,
_ => io::Error::from(io::ErrorKind::Other),
})?;
io::Result::Ok(self.offset)
}
fn stream_position(&mut self) -> io::Result<u64> {
io::Result::Ok(self.offset)
}
fn stream_position(&mut self) -> io::Result<u64> { io::Result::Ok(self.offset) }
}
impl<'a> ReadStream for NFSReadStream<'a> {
fn stable_stream_len(&mut self) -> io::Result<u64> {
todo!()
}
fn stable_stream_len(&mut self) -> io::Result<u64> { todo!() }
}
impl DiscIO for DiscIONFS {
@ -239,7 +229,7 @@ impl DiscIO for DiscIONFS {
disc_io: self,
file: Option::None,
crypto: Aes128::new(&self.key.into()),
phys_addr: fbo_max(),
phys_addr: FBO::default(),
offset,
cur_file: u32::MAX,
cur_block: u32::MAX,
@ -282,9 +272,13 @@ impl DiscIONFS {
)));
}
File::open(key_path.as_path())
.map_err(|v| Error::Io(format!("Failed to open {}", key_path.to_string_lossy()), v))?
.map_err(|v| {
Error::Io(format!("Failed to open {}", key_path.to_string_lossy()), v)
})?
.read(&mut self.key)
.map_err(|v| Error::Io(format!("Failed to read {}", key_path.to_string_lossy()), v))?;
.map_err(|v| {
Error::Io(format!("Failed to read {}", key_path.to_string_lossy()), v)
})?;
}
{
// Load header from first file

View File

@ -26,8 +26,8 @@
//! println!(s);
//! }
//! ```
pub mod fst;
pub mod disc;
pub mod fst;
pub mod io;
pub mod streams;
@ -42,25 +42,22 @@ pub enum Error {
pub type Result<T> = std::result::Result<T, Error>;
impl From<std::io::Error> for Error {
fn from(v: std::io::Error) -> Self {
Error::Io("I/O error".to_string(), v)
}
fn from(v: std::io::Error) -> Self { Error::Io("I/O error".to_string(), v) }
}
impl From<binread::Error> for Error {
fn from(v: binread::Error) -> Self {
Error::BinaryFormat(v)
}
fn from(v: binread::Error) -> Self { Error::BinaryFormat(v) }
}
impl From<block_modes::BlockModeError> for Error {
fn from(v: block_modes::BlockModeError) -> Self {
Error::Encryption(v)
}
fn from(v: block_modes::BlockModeError) -> Self { Error::Encryption(v) }
}
#[inline(always)]
pub(crate) fn div_rem<T: std::ops::Div<Output=T> + std::ops::Rem<Output=T> + Copy>(x: T, y: T) -> (T, T) {
pub(crate) fn div_rem<T: std::ops::Div<Output = T> + std::ops::Rem<Output = T> + Copy>(
x: T,
y: T,
) -> (T, T) {
let quot = x / y;
let rem = x % y;
(quot, rem)

View File

@ -1,9 +1,13 @@
//! Common stream types
use std::{fs::File, io, io::{Read, Seek, SeekFrom}};
use std::ops::DerefMut;
use std::{
fs::File,
io,
io::{Read, Seek, SeekFrom},
ops::DerefMut,
};
/// Creates a fixed-size array from a slice.
/// Creates a fixed-size array reference from a slice.
#[macro_export]
macro_rules! array_ref {
($slice:expr, $offset:expr, $size:expr) => {{
@ -12,7 +16,19 @@ macro_rules! array_ref {
unsafe { &*(slice.as_ptr() as *const [_; $size]) }
}
to_array(&$slice[$offset..$offset + $size])
}}
}};
}
/// Creates a mutable fixed-size array reference from a slice.
#[macro_export]
macro_rules! array_ref_mut {
($slice:expr, $offset:expr, $size:expr) => {{
#[inline]
fn to_array<T>(slice: &mut [T]) -> &mut [T; $size] {
unsafe { &mut *(slice.as_ptr() as *mut [_; $size]) }
}
to_array(&mut $slice[$offset..$offset + $size])
}};
}
pub trait ReadStream: Read + Seek {
@ -24,13 +40,10 @@ pub trait ReadStream: Read + Seek {
/// Creates a windowed read sub-stream with offset and size.
///
/// Seeks underlying stream immediately.
fn new_window(&mut self, offset: u64, size: u64) -> io::Result<SharedWindowedReadStream> where Self: Sized {
fn new_window(&mut self, offset: u64, size: u64) -> io::Result<SharedWindowedReadStream>
where Self: Sized {
self.seek(SeekFrom::Start(offset))?;
io::Result::Ok(SharedWindowedReadStream {
base: self,
begin: offset,
end: offset + size,
})
io::Result::Ok(SharedWindowedReadStream { base: self, begin: offset, end: offset + size })
}
}
@ -56,13 +69,13 @@ pub struct OwningWindowedReadStream<'a> {
}
/// Takes ownership of & wraps a read stream into a windowed read stream.
pub fn wrap_windowed<'a>(mut base: Box<dyn ReadStream + 'a>, offset: u64, size: u64) -> io::Result<OwningWindowedReadStream<'a>> {
pub fn wrap_windowed<'a>(
mut base: Box<dyn ReadStream + 'a>,
offset: u64,
size: u64,
) -> io::Result<OwningWindowedReadStream<'a>> {
base.seek(SeekFrom::Start(offset))?;
io::Result::Ok(OwningWindowedReadStream {
base,
begin: offset,
end: offset + size,
})
io::Result::Ok(OwningWindowedReadStream { base, begin: offset, end: offset + size })
}
pub struct SharedWindowedReadStream<'a> {
@ -98,15 +111,11 @@ fn windowed_seek(stream: &mut dyn WindowedReadStream, pos: SeekFrom) -> io::Resu
}
impl<'a> Read for OwningWindowedReadStream<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
windowed_read(self, buf)
}
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { windowed_read(self, buf) }
}
impl<'a> Seek for OwningWindowedReadStream<'a> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
windowed_seek(self, pos)
}
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { windowed_seek(self, pos) }
fn stream_position(&mut self) -> io::Result<u64> {
Result::Ok(self.base.stream_position()? - self.begin)
@ -114,31 +123,21 @@ impl<'a> Seek for OwningWindowedReadStream<'a> {
}
impl<'a> ReadStream for OwningWindowedReadStream<'a> {
fn stable_stream_len(&mut self) -> io::Result<u64> {
Result::Ok(self.end - self.begin)
}
fn stable_stream_len(&mut self) -> io::Result<u64> { Result::Ok(self.end - self.begin) }
}
impl<'a> WindowedReadStream for OwningWindowedReadStream<'a> {
fn base_stream(&mut self) -> &mut dyn ReadStream {
self.base.deref_mut()
}
fn base_stream(&mut self) -> &mut dyn ReadStream { self.base.deref_mut() }
fn window(&self) -> (u64, u64) {
(self.begin, self.end)
}
fn window(&self) -> (u64, u64) { (self.begin, self.end) }
}
impl<'a> Read for SharedWindowedReadStream<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
windowed_read(self, buf)
}
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { windowed_read(self, buf) }
}
impl<'a> Seek for SharedWindowedReadStream<'a> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
windowed_seek(self, pos)
}
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { windowed_seek(self, pos) }
fn stream_position(&mut self) -> io::Result<u64> {
Result::Ok(self.base.stream_position()? - self.begin)
@ -146,17 +145,11 @@ impl<'a> Seek for SharedWindowedReadStream<'a> {
}
impl<'a> ReadStream for SharedWindowedReadStream<'a> {
fn stable_stream_len(&mut self) -> io::Result<u64> {
Result::Ok(self.end - self.begin)
}
fn stable_stream_len(&mut self) -> io::Result<u64> { Result::Ok(self.end - self.begin) }
}
impl<'a> WindowedReadStream for SharedWindowedReadStream<'a> {
fn base_stream(&mut self) -> &mut dyn ReadStream {
self.base
}
fn base_stream(&mut self) -> &mut dyn ReadStream { self.base }
fn window(&self) -> (u64, u64) {
(self.begin, self.end)
}
fn window(&self) -> (u64, u64) { (self.begin, self.end) }
}