Cleanup & add as_dyn to ReadStream

This commit is contained in:
Luke Street 2021-09-01 16:10:22 -04:00
parent dc5217dd04
commit 35388db458
8 changed files with 76 additions and 44 deletions

View File

@ -7,9 +7,9 @@ use std::{
use clap::{clap_app, AppSettings}; use clap::{clap_app, AppSettings};
use file_size; use file_size;
use nod::{ use nod::{
disc::{new_disc_base, PartReadStream}, disc::{new_disc_base, DiscBase, PartReadStream},
fst::NodeType, fst::NodeType,
io::{has_extension, new_disc_io}, io::{has_extension, new_disc_io, DiscIO},
Result, Result,
}; };

View File

@ -17,7 +17,9 @@ pub(crate) struct DiscGCN {
pub(crate) header: Header, pub(crate) header: Header,
} }
pub(crate) fn new_disc_gcn(header: Header) -> Result<DiscGCN> { Result::Ok(DiscGCN { header }) } impl DiscGCN {
pub(crate) fn new(header: Header) -> Result<DiscGCN> { Result::Ok(DiscGCN { header }) }
}
impl DiscBase for DiscGCN { impl DiscBase for DiscGCN {
fn get_header(&self) -> &Header { &self.header } fn get_header(&self) -> &Header { &self.header }
@ -92,6 +94,8 @@ impl<'a> Seek for GCPartReadStream<'a> {
impl<'a> ReadStream for GCPartReadStream<'a> { 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() }
fn as_dyn(&mut self) -> &mut dyn ReadStream { self }
} }
impl<'a> PartReadStream for GCPartReadStream<'a> { impl<'a> PartReadStream for GCPartReadStream<'a> {

View File

@ -5,7 +5,7 @@ use std::{fmt::Debug, io};
use binread::{prelude::*, BinReaderExt, NullString}; use binread::{prelude::*, BinReaderExt, NullString};
use crate::{ use crate::{
disc::{gcn::new_disc_gcn, wii::new_disc_wii}, disc::{gcn::DiscGCN, wii::DiscWii},
fst::{Node, NodeType}, fst::{Node, NodeType},
io::DiscIO, io::DiscIO,
streams::{ReadStream, SharedWindowedReadStream}, streams::{ReadStream, SharedWindowedReadStream},
@ -113,9 +113,9 @@ pub fn new_disc_base(disc_io: &mut dyn DiscIO) -> Result<Box<dyn DiscBase>> {
let mut stream = disc_io.begin_read_stream(0)?; let mut stream = disc_io.begin_read_stream(0)?;
let header: Header = stream.read_be()?; let header: Header = stream.read_be()?;
if header.wii_magic == 0x5D1C9EA3 { if header.wii_magic == 0x5D1C9EA3 {
Result::Ok(Box::from(new_disc_wii(stream.as_mut(), header)?)) Result::Ok(Box::from(DiscWii::new(stream.as_mut(), header)?))
} else if header.gcn_magic == 0xC2339F3D { } else if header.gcn_magic == 0xC2339F3D {
Result::Ok(Box::from(new_disc_gcn(header)?)) Result::Ok(Box::from(DiscGCN::new(header)?))
} else { } else {
Result::Err(Error::DiscFormat("Invalid GC/Wii magic".to_string())) Result::Err(Error::DiscFormat("Invalid GC/Wii magic".to_string()))
} }

View File

@ -192,11 +192,13 @@ pub(crate) struct DiscWii {
part_info: WiiPartInfo, part_info: WiiPartInfo,
} }
pub(crate) fn new_disc_wii(mut stream: &mut dyn ReadStream, header: Header) -> Result<DiscWii> { impl DiscWii {
pub(crate) fn new(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()?; disc.decrypt_partition_keys()?;
Result::Ok(disc) Result::Ok(disc)
} }
}
impl DiscWii { impl DiscWii {
pub(crate) fn decrypt_partition_keys(&mut self) -> Result<()> { pub(crate) fn decrypt_partition_keys(&mut self) -> Result<()> {
@ -401,6 +403,8 @@ impl<'a> ReadStream for WiiPartReadStream<'a> {
fn stable_stream_len(&mut self) -> io::Result<u64> { fn stable_stream_len(&mut self) -> io::Result<u64> {
io::Result::Ok(to_block_size(self.stream.stable_stream_len()?)) io::Result::Ok(to_block_size(self.stream.stable_stream_len()?))
} }
fn as_dyn(&mut self) -> &mut dyn ReadStream { self }
} }
#[derive(Clone, Debug, PartialEq, BinRead)] #[derive(Clone, Debug, PartialEq, BinRead)]

View File

@ -1,20 +1,20 @@
use std::fs::File; use std::{
use std::io::{Seek, SeekFrom}; fs::File,
use std::io; io,
use std::path::{Path, PathBuf}; io::{Seek, SeekFrom},
path::{Path, PathBuf},
};
use crate::io::DiscIO; use crate::{io::DiscIO, streams::ReadStream, Result};
use crate::Result;
use crate::streams::ReadStream;
pub(crate) struct DiscIOISO { pub(crate) struct DiscIOISO {
pub(crate) filename: PathBuf, pub(crate) filename: PathBuf,
} }
pub(crate) fn new_disc_io_iso(filename: &Path) -> Result<DiscIOISO> { impl DiscIOISO {
Result::Ok(DiscIOISO { pub(crate) fn new(filename: &Path) -> Result<DiscIOISO> {
filename: filename.to_owned(), Result::Ok(DiscIOISO { filename: filename.to_owned() })
}) }
} }
impl DiscIO for DiscIOISO { impl DiscIO for DiscIOISO {

View File

@ -3,7 +3,7 @@
use std::{fs, io, path::Path}; use std::{fs, io, path::Path};
use crate::{ use crate::{
io::{iso::new_disc_io_iso, nfs::new_disc_io_nfs}, io::{iso::DiscIOISO, nfs::DiscIONFS},
streams::ReadStream, streams::ReadStream,
Error, Result, Error, Result,
}; };
@ -21,18 +21,6 @@ pub trait DiscIO {
fn has_wii_crypto(&self) -> bool { true } fn has_wii_crypto(&self) -> bool { true }
} }
/// Helper function for checking a file extension.
#[inline(always)]
pub fn has_extension(filename: &Path, extension: &str) -> bool {
if let Some(ext) = filename.extension() {
// TODO use with Rust 1.53+
// ext.eq_ignore_ascii_case(extension)
ext.to_str().unwrap_or("").eq_ignore_ascii_case(extension)
} else {
false
}
}
/// Creates a new [`DiscIO`] instance. /// Creates a new [`DiscIO`] instance.
/// ///
/// # Examples /// # Examples
@ -66,10 +54,10 @@ pub fn new_disc_io(filename: &Path) -> Result<Box<dyn DiscIO>> {
))); )));
} }
if has_extension(path, "iso") { if has_extension(path, "iso") {
Result::Ok(Box::from(new_disc_io_iso(path)?)) Result::Ok(Box::from(DiscIOISO::new(path)?))
} else if has_extension(path, "nfs") { } else if has_extension(path, "nfs") {
if matches!(path.parent(), Some(parent) if parent.is_dir()) { if matches!(path.parent(), Some(parent) if parent.is_dir()) {
Result::Ok(Box::from(new_disc_io_nfs(path.parent().unwrap())?)) Result::Ok(Box::from(DiscIONFS::new(path.parent().unwrap())?))
} else { } else {
Result::Err(Error::DiscFormat("Failed to locate NFS parent directory".to_string())) Result::Err(Error::DiscFormat("Failed to locate NFS parent directory".to_string()))
} }
@ -77,3 +65,15 @@ pub fn new_disc_io(filename: &Path) -> Result<Box<dyn DiscIO>> {
Result::Err(Error::DiscFormat("Unknown file type".to_string())) Result::Err(Error::DiscFormat("Unknown file type".to_string()))
} }
} }
/// Helper function for checking a file extension.
#[inline(always)]
pub fn has_extension(filename: &Path, extension: &str) -> bool {
if let Some(ext) = filename.extension() {
// TODO use with Rust 1.53+
// ext.eq_ignore_ascii_case(extension)
ext.to_str().unwrap_or("").eq_ignore_ascii_case(extension)
} else {
false
}
}

View File

@ -83,12 +83,14 @@ pub(crate) struct DiscIONFS {
pub(crate) header: Option<NFSHeader>, pub(crate) header: Option<NFSHeader>,
} }
pub(crate) fn new_disc_io_nfs(directory: &Path) -> Result<DiscIONFS> { impl DiscIONFS {
pub(crate) fn new(directory: &Path) -> Result<DiscIONFS> {
let mut disc_io = let mut disc_io =
DiscIONFS { directory: directory.to_owned(), key: [0; 16], header: Option::None }; DiscIONFS { directory: directory.to_owned(), key: [0; 16], header: Option::None };
disc_io.validate_files()?; disc_io.validate_files()?;
Result::Ok(disc_io) Result::Ok(disc_io)
} }
}
pub(crate) struct NFSReadStream<'a> { pub(crate) struct NFSReadStream<'a> {
disc_io: &'a DiscIONFS, disc_io: &'a DiscIONFS,
@ -221,6 +223,8 @@ impl<'a> Seek for NFSReadStream<'a> {
impl<'a> ReadStream for NFSReadStream<'a> { 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!() }
fn as_dyn(&mut self) -> &mut dyn ReadStream { self }
} }
impl DiscIO for DiscIONFS { impl DiscIO for DiscIONFS {

View File

@ -40,11 +40,16 @@ pub trait ReadStream: Read + Seek {
/// Creates a windowed read sub-stream with offset and size. /// Creates a windowed read sub-stream with offset and size.
/// ///
/// Seeks underlying stream immediately. /// Seeks underlying stream immediately.
fn new_window(&mut self, offset: u64, size: u64) -> io::Result<SharedWindowedReadStream> fn new_window(&mut self, offset: u64, size: u64) -> io::Result<SharedWindowedReadStream> {
where Self: Sized {
self.seek(SeekFrom::Start(offset))?; self.seek(SeekFrom::Start(offset))?;
io::Result::Ok(SharedWindowedReadStream { base: self, begin: offset, end: offset + size }) io::Result::Ok(SharedWindowedReadStream {
base: self.as_dyn(),
begin: offset,
end: offset + size,
})
} }
fn as_dyn(&mut self) -> &mut dyn ReadStream;
} }
impl ReadStream for File { impl ReadStream for File {
@ -55,6 +60,8 @@ impl ReadStream for File {
self.seek(SeekFrom::Start(before))?; self.seek(SeekFrom::Start(before))?;
result result
} }
fn as_dyn(&mut self) -> &mut dyn ReadStream { self }
} }
trait WindowedReadStream: ReadStream { trait WindowedReadStream: ReadStream {
@ -84,6 +91,15 @@ pub struct SharedWindowedReadStream<'a> {
pub end: u64, pub end: u64,
} }
impl<'a> SharedWindowedReadStream<'a> {
pub fn set_window(&mut self, begin: u64, end: u64) -> io::Result<()> {
self.base.seek(SeekFrom::Start(begin))?;
self.begin = begin;
self.end = end;
io::Result::Ok(())
}
}
#[inline(always)] #[inline(always)]
fn windowed_read(stream: &mut dyn WindowedReadStream, buf: &mut [u8]) -> io::Result<usize> { fn windowed_read(stream: &mut dyn WindowedReadStream, buf: &mut [u8]) -> io::Result<usize> {
let pos = stream.stream_position()?; let pos = stream.stream_position()?;
@ -124,6 +140,8 @@ impl<'a> Seek for OwningWindowedReadStream<'a> {
impl<'a> ReadStream 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) }
fn as_dyn(&mut self) -> &mut dyn ReadStream { self }
} }
impl<'a> WindowedReadStream for OwningWindowedReadStream<'a> { impl<'a> WindowedReadStream for OwningWindowedReadStream<'a> {
@ -146,6 +164,8 @@ impl<'a> Seek for SharedWindowedReadStream<'a> {
impl<'a> ReadStream 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) }
fn as_dyn(&mut self) -> &mut dyn ReadStream { self }
} }
impl<'a> WindowedReadStream for SharedWindowedReadStream<'a> { impl<'a> WindowedReadStream for SharedWindowedReadStream<'a> {