diff options
Diffstat (limited to 'src/devices/file/directory_listing.rs')
-rw-r--r-- | src/devices/file/directory_listing.rs | 121 |
1 files changed, 43 insertions, 78 deletions
diff --git a/src/devices/file/directory_listing.rs b/src/devices/file/directory_listing.rs index 341f353..0cbbde9 100644 --- a/src/devices/file/directory_listing.rs +++ b/src/devices/file/directory_listing.rs @@ -1,5 +1,6 @@ use super::*; + pub struct DirectoryListing { children: Vec<DirectoryChild>, length: u32, @@ -8,51 +9,50 @@ pub struct DirectoryListing { } impl DirectoryListing { - pub fn from_path(path: &Path, base: &Path) -> Result<Self, ()> { - macro_rules! continue_on_err { + pub fn from_path(path: &BedrockFilePath) -> Option<Self> { + macro_rules! unres { ($result:expr) => { match $result { Ok(v) => v, Err(_) => continue} }; } + macro_rules! unopt { + ($option:expr) => { match $option { Some(v) => v, None => continue} }; + } let mut children = Vec::new(); - if let Ok(iter_dir) = std::fs::read_dir(path) { - for (i, entry_result) in iter_dir.enumerate() { - if i == u16::MAX as usize { - eprintln!("Warning, {path:?} contains more than 65536 entries.") - }; - let entry = continue_on_err!(entry_result); - let path = continue_on_err!(remove_base(&entry.path(), &base)); - #[cfg(target_family = "unix")] - let byte_path = path.as_os_str().as_bytes(); - #[cfg(target_family = "windows")] - let byte_path = path.as_os_str().as_encoded_bytes(); - if byte_path.len() > 255 { + let dir_listing = std::fs::read_dir(path.as_path()).ok()?; + for (i, entry_result) in dir_listing.enumerate() { + // Firebreak to prevent emulator from consuming an absurd amount + // of memory when opening too large of a directory. + if i == (u16::MAX as usize) { + break; + } + + let entry = unres!(entry_result); + let entry_path = unopt!(BedrockFilePath::from_path(&entry.path(), path.base())); + if entry_path.filename_is_dot_prefixed() { + continue; + } + let metadata = unres!(std::fs::metadata(&entry.path())); + let entry_type = + if metadata.is_file() { + EntryType::File + } else if metadata.is_dir() { + EntryType::Directory + } else { continue; }; - if filename_dot_prefixed(&path) { - continue; - } - let metadata = continue_on_err!(std::fs::metadata(&entry.path())); - children.push( DirectoryChild { - byte_path: Vec::from(byte_path), - entry_type: if metadata.is_file() { - EntryType::File - } else if metadata.is_dir() { - EntryType::Directory - } else { - continue; - }, - } ) - } - children.sort_unstable(); - let length = u32::try_from(children.len()).unwrap_or(u32::MAX); - let selected = None; - let name_buffer = CircularPathBuffer::new(); - Ok(Self { children, length, selected, name_buffer } ) - } else { - Err(()) + + let child = DirectoryChild { path: entry_path, entry_type }; + children.push(child); } + + children.sort(); + let length = u32::try_from(children.len()).ok()?; + let selected = None; + let name_buffer = CircularPathBuffer::new(); + Some( Self { children, length, selected, name_buffer } ) } + /// Attempts to return a directory child by index. pub fn get(&self, index: u32) -> Option<&DirectoryChild> { self.children.get(index as usize) } @@ -61,13 +61,16 @@ impl DirectoryListing { self.length } + /// Returns the index of the selected child, or zero if no child is selected. pub fn selected(&self) -> u32 { self.selected.unwrap_or(0) } + /// Attempts to select a child by index. pub fn set_selected(&mut self, index: u32) { - if let Some(info) = self.get(index) { - self.name_buffer.populate(&info.byte_path.clone()); + if let Some(child) = self.get(index) { + let buffer = child.path.as_buffer(); + self.name_buffer.populate(buffer); self.selected = Some(index); } else { self.name_buffer.clear(); @@ -83,46 +86,8 @@ impl DirectoryListing { self.selected.and_then(|s| self.get(s).and_then(|i| Some(i.entry_type))) } - pub fn child_path(&self) -> Option<PathBuf> { - self.selected.and_then(|s| self.get(s).and_then(|i| { - Some(bytes_to_path(&i.byte_path)) - })) - } -} - -pub fn remove_base(absolute_path: &Path, base_path: &Path) -> Result<PathBuf, ()> { - if let Ok(relative) = absolute_path.strip_prefix(base_path) { - let mut baseless_path = PathBuf::from("/"); - for component in relative.components() { - match component { - Component::Normal(s) => baseless_path.push(s), - Component::ParentDir => return Err(()), - Component::CurDir => continue, - Component::RootDir => continue, - Component::Prefix(_) => continue, - } - } - return Ok(baseless_path); + pub fn child_path(&self) -> Option<BedrockFilePath> { + self.selected.and_then(|s| self.get(s).and_then(|i| Some(i.path.clone()))) } - return Err(()); } -// Returns true if a dot character directly follows the right-most -// forward-slash character in the path. -fn filename_dot_prefixed(path: &Path) -> bool { - #[cfg(target_family = "unix")] - let bytes = path.as_os_str().as_bytes(); - #[cfg(target_family = "windows")] - let bytes = path.as_os_str().as_encoded_bytes(); - // Find position of final forward-slash byte. - let mut final_slash = None; - for (i, byte) in bytes.iter().enumerate() { - if *byte == b'/' { final_slash = Some(i) } - } - if let Some(i) = final_slash { - if let Some(b'.') = bytes.get(i+1) { - return true; - } - } - return false; -} |