Various minor API adjustments

This commit is contained in:
Luke Street 2024-10-03 20:18:44 -06:00
parent 8abe674cb9
commit 5f537f0e7b
11 changed files with 31 additions and 27 deletions

4
Cargo.lock generated
View File

@ -447,7 +447,7 @@ dependencies = [
[[package]]
name = "nod"
version = "1.3.0"
version = "1.4.0"
dependencies = [
"adler",
"aes",
@ -470,7 +470,7 @@ dependencies = [
[[package]]
name = "nodtool"
version = "1.3.0"
version = "1.4.0"
dependencies = [
"argp",
"base16ct",

View File

@ -9,7 +9,7 @@ strip = "debuginfo"
codegen-units = 1
[workspace.package]
version = "1.3.0"
version = "1.4.0"
edition = "2021"
rust-version = "1.74"
authors = ["Luke Street <luke@street.dev>"]

View File

@ -19,7 +19,7 @@ pub enum NodeKind {
}
/// An individual file system node.
#[derive(Clone, Debug, PartialEq, FromBytes, FromZeroes, AsBytes)]
#[derive(Copy, Clone, Debug, PartialEq, FromBytes, FromZeroes, AsBytes)]
#[repr(C, align(4))]
pub struct Node {
kind: u8,
@ -108,7 +108,7 @@ impl<'a> Fst<'a> {
/// Get the name of a node.
#[allow(clippy::missing_inline_in_public_items)]
pub fn get_name(&self, node: &Node) -> Result<Cow<'a, str>, String> {
pub fn get_name(&self, node: Node) -> Result<Cow<'a, str>, String> {
let name_buf = self.string_table.get(node.name_offset() as usize..).ok_or_else(|| {
format!(
"FST: name offset {} out of bounds (string table size: {})",
@ -128,12 +128,12 @@ impl<'a> Fst<'a> {
/// Finds a particular file or directory by path.
#[allow(clippy::missing_inline_in_public_items)]
pub fn find(&self, path: &str) -> Option<(usize, &'a Node)> {
pub fn find(&self, path: &str) -> Option<(usize, Node)> {
let mut split = path.trim_matches('/').split('/');
let mut current = split.next()?;
let mut idx = 1;
let mut stop_at = None;
while let Some(node) = self.nodes.get(idx) {
while let Some(node) = self.nodes.get(idx).copied() {
if self.get_name(node).as_ref().map_or(false, |name| name.eq_ignore_ascii_case(current))
{
if let Some(next) = split.next() {
@ -168,11 +168,11 @@ pub struct FstIter<'a> {
}
impl<'a> Iterator for FstIter<'a> {
type Item = (usize, &'a Node, Result<Cow<'a, str>, String>);
type Item = (usize, Node, Result<Cow<'a, str>, String>);
fn next(&mut self) -> Option<Self::Item> {
let idx = self.idx;
let node = self.fst.nodes.get(idx)?;
let node = self.fst.nodes.get(idx).copied()?;
let name = self.fst.get_name(node);
self.idx += 1;
Some((idx, node, name))

View File

@ -124,7 +124,7 @@ impl PartitionBase for PartitionGC {
read_part_meta(self, false)
}
fn open_file(&mut self, node: &Node) -> io::Result<FileStream> {
fn open_file(&mut self, node: Node) -> io::Result<FileStream> {
if !node.is_file() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
@ -134,7 +134,7 @@ impl PartitionBase for PartitionGC {
FileStream::new(self, node.offset(false), node.length())
}
fn into_open_file(self: Box<Self>, node: &Node) -> io::Result<OwnedFileStream> {
fn into_open_file(self: Box<Self>, node: Node) -> io::Result<OwnedFileStream> {
if !node.is_file() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,

View File

@ -313,7 +313,7 @@ pub trait PartitionBase: DynClone + BufRead + Seek + Send + Sync {
/// Ok(())
/// }
/// ```
fn open_file(&mut self, node: &Node) -> io::Result<FileStream>;
fn open_file(&mut self, node: Node) -> io::Result<FileStream>;
/// Consumes the partition instance and returns a windowed stream.
///
@ -342,7 +342,7 @@ pub trait PartitionBase: DynClone + BufRead + Seek + Send + Sync {
/// Ok(())
/// }
/// ```
fn into_open_file(self: Box<Self>, node: &Node) -> io::Result<OwnedFileStream>;
fn into_open_file(self: Box<Self>, node: Node) -> io::Result<OwnedFileStream>;
}
dyn_clone::clone_trait_object!(PartitionBase);

View File

@ -35,6 +35,11 @@ where T: BufRead + Seek
base.seek(SeekFrom::Start(offset))?;
Ok(Self { base, pos: offset, begin: offset, end: offset + size })
}
/// Returns the length of the window.
#[inline]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> u64 { self.end - self.begin }
}
impl<T> Read for WindowedStream<T>

View File

@ -489,7 +489,7 @@ impl PartitionBase for PartitionWii {
Ok(meta)
}
fn open_file(&mut self, node: &Node) -> io::Result<FileStream> {
fn open_file(&mut self, node: Node) -> io::Result<FileStream> {
if !node.is_file() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
@ -499,7 +499,7 @@ impl PartitionBase for PartitionWii {
FileStream::new(self, node.offset(true), node.length())
}
fn into_open_file(self: Box<Self>, node: &Node) -> io::Result<OwnedFileStream> {
fn into_open_file(self: Box<Self>, node: Node) -> io::Result<OwnedFileStream> {
if !node.is_file() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,

View File

@ -94,7 +94,7 @@ dyn_clone::clone_trait_object!(BlockIO);
/// Creates a new [`BlockIO`] instance from a stream.
pub fn new(mut stream: Box<dyn DiscStream>) -> Result<Box<dyn BlockIO>> {
let io: Box<dyn BlockIO> = match detect(stream.as_mut())? {
let io: Box<dyn BlockIO> = match detect(stream.as_mut()).context("Detecting file type")? {
Some(Format::Iso) => crate::io::iso::DiscIOISO::new(stream)?,
Some(Format::Ciso) => crate::io::ciso::DiscIOCISO::new(stream)?,
Some(Format::Gcz) => {
@ -103,10 +103,8 @@ pub fn new(mut stream: Box<dyn DiscStream>) -> Result<Box<dyn BlockIO>> {
crate::io::gcz::DiscIOGCZ::new(stream)?
}
#[cfg(not(feature = "compress-zlib"))]
{
return Err(Error::DiscFormat("GCZ support is disabled".to_string()));
}
}
Some(Format::Nfs) => {
return Err(Error::DiscFormat("NFS requires a filesystem path".to_string()))
}
@ -134,7 +132,7 @@ pub fn open(filename: &Path) -> Result<Box<dyn BlockIO>> {
return Err(Error::DiscFormat(format!("Input is not a file: {}", filename.display())));
}
let mut stream = Box::new(SplitFileReader::new(filename)?);
let io: Box<dyn BlockIO> = match detect(stream.as_mut())? {
let io: Box<dyn BlockIO> = match detect(stream.as_mut()).context("Detecting file type")? {
Some(Format::Iso) => crate::io::iso::DiscIOISO::new(stream)?,
Some(Format::Ciso) => crate::io::ciso::DiscIOCISO::new(stream)?,
Some(Format::Gcz) => {
@ -143,10 +141,8 @@ pub fn open(filename: &Path) -> Result<Box<dyn BlockIO>> {
crate::io::gcz::DiscIOGCZ::new(stream)?
}
#[cfg(not(feature = "compress-zlib"))]
{
return Err(Error::DiscFormat("GCZ support is disabled".to_string()));
}
}
Some(Format::Nfs) => match path.parent() {
Some(parent) if parent.is_dir() => {
crate::io::nfs::DiscIONFS::new(path.parent().unwrap())?
@ -172,11 +168,11 @@ pub const WBFS_MAGIC: MagicBytes = *b"WBFS";
pub const WIA_MAGIC: MagicBytes = *b"WIA\x01";
pub const RVZ_MAGIC: MagicBytes = *b"RVZ\x01";
pub fn detect<R: Read + ?Sized>(stream: &mut R) -> Result<Option<Format>> {
pub fn detect<R: Read + ?Sized>(stream: &mut R) -> io::Result<Option<Format>> {
let data: [u8; 0x20] = match read_from(stream) {
Ok(magic) => magic,
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => return Ok(None),
Err(e) => return Err(e).context("Reading magic bytes"),
Err(e) => return Err(e),
};
let out = match *array_ref!(data, 0, 4) {
CISO_MAGIC => Some(Format::Ciso),

View File

@ -192,7 +192,7 @@ impl Disc {
/// Detects the format of a disc image from a read stream.
#[inline]
pub fn detect<R>(stream: &mut R) -> Result<Option<Format>>
pub fn detect<R>(stream: &mut R) -> std::io::Result<Option<Format>>
where R: Read + ?Sized {
io::block::detect(stream)
}

View File

@ -181,7 +181,7 @@ fn extract_file(bytes: &[u8], out_path: &Path, quiet: bool) -> nod::Result<()> {
}
fn extract_node(
node: &Node,
node: Node,
partition: &mut dyn PartitionBase,
base_path: &Path,
name: &str,

View File

@ -3,6 +3,9 @@ use argp::FromArgs;
pub mod cmd;
pub(crate) mod util;
// Re-export nod
pub use nod;
#[derive(FromArgs, Debug)]
#[argp(subcommand)]
pub enum SubCommand {