Moved dcb_drv::find_entry to DirPtr::find.

This commit is contained in:
Filipe Rodrigues 2021-06-04 20:54:38 +01:00
parent 3828aeec9b
commit 91ba3b9406
8 changed files with 102 additions and 97 deletions

View File

@ -1,79 +0,0 @@
//! Entry finding
// Imports
use crate::{path::Component, DirEntry, DirEntryKind, DirEntryPtr, DirPtr, Path, PathBuf};
use std::io;
/// Finds an entry given it's path
pub fn find_entry<R: io::Seek + io::Read>(
reader: &mut R, path: &Path,
) -> Result<(DirEntryPtr, DirEntry), FindEntryError> {
// Current directory pointer
let mut cur_dir_ptr = DirPtr::root();
// Current entry
let mut cur_entry = None;
let mut components = path.components();
while let Some(component) = components.next() {
// Get the next entry's name
let entry_name = match component {
// Note: We start at the root, so `Root` doesn't do anything to us
Component::Root | Component::CurDir => continue,
Component::ParentDir => return Err(FindEntryError::ParentDir),
Component::Normal(entry) => entry,
};
// Find the entry
let (entry_ptr, entry) = cur_dir_ptr
.find_entry(reader, entry_name)
.map_err(FindEntryError::FindEntry)?;
// If there's no component after this, break
if components.clone().next().is_none() {
return Ok((entry_ptr, entry));
}
// Else check what entry we got
match entry.kind {
// If we got a file at this stage return error
DirEntryKind::File { .. } => {
return Err(FindEntryError::ExpectedDir {
path: path[..(path.len() - components.remaining().len())].to_path_buf(),
})
},
// If we got a directory, continue
DirEntryKind::Dir { ptr } => {
cur_entry = Some((entry_ptr, entry));
cur_dir_ptr = ptr;
},
};
}
// If we got here, try to return our current entry
cur_entry.ok_or(FindEntryError::EmptyPath)
}
/// Error type for [`find_entry`]
#[derive(Debug, thiserror::Error)]
pub enum FindEntryError {
/// Unable to find entry
#[error("Unable to find entry")]
FindEntry(#[source] crate::ptr::FindEntryError),
/// Cannot go back to parent directory
#[error("Cannot go back to parent directory")]
ParentDir,
/// Expected directory
#[error("Expected directory at {path}")]
ExpectedDir {
/// The path that wasn't a directory
path: PathBuf,
},
/// Path was empty
#[error("Path was empty")]
EmptyPath,
}

View File

@ -30,5 +30,4 @@ The [`DirPtr`] type can be used to access any directory, namely the root directo
The [`Path`] type is used to refer to any entry.
There also exist some utility functions at the root of the crate, such as [`find_entry`]
and [`swap_files`].
There also exist some utility functions at the root of the crate, such as [`swap_files`].

View File

@ -8,7 +8,8 @@
never_type,
unwrap_infallible,
format_args_capture,
str_internals
str_internals,
destructuring_assignment
)]
// Lints
#![warn(clippy::restriction, clippy::pedantic, clippy::nursery)]
@ -69,7 +70,6 @@
// Modules
pub mod dir;
pub mod entry;
pub mod find;
pub mod path;
pub mod ptr;
pub mod swap;
@ -77,7 +77,6 @@ pub mod writer;
// Exports
pub use entry::{DirEntry, DirEntryKind};
pub use find::find_entry;
pub use path::{Path, PathBuf};
pub use ptr::{DirEntryPtr, DirPtr, FilePtr};
pub use swap::swap_files;

View File

@ -5,12 +5,12 @@ pub mod error;
// Exports
pub use error::{
FileCursorError, FindEntryError, ReadEntriesError, ReadEntryError, WriteEntriesError, WriteEntryError,
FileCursorError, FindEntryError, FindError, ReadEntriesError, ReadEntryError, WriteEntriesError, WriteEntryError,
};
// Imports
use super::DirEntry;
use crate::DirEntryKind;
use crate::{path, DirEntryKind, Path};
use ascii::AsciiStr;
use core::str::lossy::Utf8Lossy;
use dcb_bytes::Bytes;
@ -123,6 +123,63 @@ impl DirPtr {
Ok(iter)
}
/// Finds an entry from it's path
pub fn find<R: io::Seek + io::Read>(
self, reader: &mut R, path: &Path,
) -> Result<(DirEntryPtr, DirEntry), FindError> {
// Current directory pointer
let mut cur_ptr = self;
// Current entry
let mut cur_entry = None;
let mut components = path.components();
loop {
match components.next() {
// If we get root, reset us to root and clear any entry we have
Some(path::Component::Root) => (cur_ptr, cur_entry) = (DirPtr::root(), None),
// For current directory just get the next component
Some(path::Component::CurDir) => continue,
// Return `Err` on parent directories
// Note: We don't support parent directories as we'd have to store all
// of the parent directories, because directories don't have
// access to their parents
Some(path::Component::ParentDir) => return Err(FindError::ParentDir),
// On a normal entry, find the entry in the current dir
Some(path::Component::Normal(entry_name)) => {
// Find the entry
let (entry_ptr, entry) = cur_ptr.find_entry(reader, entry_name).map_err(FindError::FindEntry)?;
// If this is the final entry, return it
if components.clone().next().is_none() {
return Ok((entry_ptr, entry));
}
// Else check what entry we got
match entry.kind {
DirEntryKind::File { .. } => {
return Err(FindError::ExpectedDir {
path: path[..(path.len() - components.remaining().len())].to_path_buf(),
})
},
// If we got a directory, continue
DirEntryKind::Dir { ptr } => {
cur_entry = Some((entry_ptr, entry));
cur_ptr = ptr;
},
};
},
// If we're done, return whatever entry we had before running out
None => return cur_entry.ok_or(FindError::EmptyPath),
}
}
}
/// Finds an entry
pub fn find_entry<R: io::Read + io::Seek>(
self, reader: &mut R, entry_name: &AsciiStr,

View File

@ -1,6 +1,7 @@
//! Errors
// Imports
use crate::PathBuf;
use std::io;
/// Error for [`FilePtr::cursor`](super::FilePtr::cursor)
@ -56,6 +57,29 @@ pub enum WriteEntryError {
WriteEntry(#[source] io::Error),
}
/// Error type for [`DirPtr::find`](super::DirPtr::find)
#[derive(Debug, thiserror::Error)]
pub enum FindError {
/// Unable to find entry
#[error("Unable to find entry")]
FindEntry(#[source] crate::ptr::FindEntryError),
/// Cannot go back to parent directory
#[error("Cannot go back to parent directory")]
ParentDir,
/// Expected directory
#[error("Expected directory at {path}")]
ExpectedDir {
/// The path that wasn't a directory
path: PathBuf,
},
/// Path was empty
#[error("Path was empty")]
EmptyPath,
}
/// Error for [`DirPtr::find_entry`](super::DirPtr::find_entry)
#[derive(Debug, thiserror::Error)]
pub enum FindEntryError {

View File

@ -1,7 +1,10 @@
//! File swapping
// Imports
use crate::{ptr::WriteEntryError, DirEntryKind, Path};
use crate::{
ptr,
DirEntryKind, DirPtr, Path,
};
use std::{io, mem};
/// Swaps two files
@ -9,8 +12,8 @@ pub fn swap_files<T: io::Seek + io::Read + io::Write>(
cursor: &mut T, lhs_path: &Path, rhs_path: &Path,
) -> Result<(), SwapFilesError> {
// Find both files and their entry pointers
let (lhs_entry_ptr, mut lhs_entry) = crate::find_entry(cursor, lhs_path).map_err(SwapFilesError::FindLhs)?;
let (rhs_entry_ptr, mut rhs_entry) = crate::find_entry(cursor, rhs_path).map_err(SwapFilesError::FindLhs)?;
let (lhs_entry_ptr, mut lhs_entry) = DirPtr::root().find(cursor, lhs_path).map_err(SwapFilesError::FindLhs)?;
let (rhs_entry_ptr, mut rhs_entry) = DirPtr::root().find(cursor, rhs_path).map_err(SwapFilesError::FindLhs)?;
// Swap both entries' file pointers
match (&mut lhs_entry.kind, &mut rhs_entry.kind) {
@ -36,11 +39,11 @@ pub fn swap_files<T: io::Seek + io::Read + io::Write>(
pub enum SwapFilesError {
/// Unable to find lhs file
#[error("Unable to find lhs file")]
FindLhs(#[source] crate::find::FindEntryError),
FindLhs(#[source] ptr::FindError),
/// Unable to find rhs file
#[error("Unable to find rhs file")]
FindRhs(#[source] crate::find::FindEntryError),
FindRhs(#[source] ptr::FindError),
/// Both paths must be files
#[error("Both paths must be files")]
@ -48,9 +51,9 @@ pub enum SwapFilesError {
/// Unable to write lhs file entry
#[error("Unable to write lhs file entry")]
WriteLhs(#[source] WriteEntryError),
WriteLhs(#[source] ptr::WriteEntryError),
/// Unable to write rhs file entry
#[error("Unable to write rhs file entry")]
WriteRhs(#[source] WriteEntryError),
WriteRhs(#[source] ptr::WriteEntryError),
}

View File

@ -147,7 +147,9 @@ impl<T: io::Seek + io::Read> GameFile<T> {
};
// Then get the entry
let (_, entry) = dcb_drv::find_entry(&mut cursor, path).map_err(OpenFileError::FindFile)?;
let (_, entry) = dcb_drv::DirPtr::root()
.find(&mut cursor, path)
.map_err(OpenFileError::FindFile)?;
match entry.kind {
DirEntryKind::File { ptr, .. } => ptr.cursor(cursor).map_err(OpenFileError::OpenFile),

View File

@ -1,7 +1,7 @@
//! Errors
// Imports
use dcb_drv::{find::FindEntryError, ptr::FileCursorError};
use dcb_drv::ptr;
use std::io;
@ -25,7 +25,7 @@ pub enum OpenFileError {
/// Unable to find file
#[error("Unable to find file")]
FindFile(#[source] FindEntryError),
FindFile(#[source] ptr::FindError),
/// Found directory
#[error("Found directory")]
@ -33,7 +33,7 @@ pub enum OpenFileError {
/// Unable to open file
#[error("Unable to open file")]
OpenFile(#[source] FileCursorError),
OpenFile(#[source] ptr::FileCursorError),
}