From 7921064ae2156293bb5d5e1a32bc4b5fabc45926 Mon Sep 17 00:00:00 2001 From: Moritz Gmeiner Date: Tue, 29 Jul 2025 20:34:35 +0200 Subject: [PATCH] moved short name str into separate buffer --- fat-bits/src/dir.rs | 106 ++++++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 28 deletions(-) diff --git a/fat-bits/src/dir.rs b/fat-bits/src/dir.rs index bc8e7a4..be69a54 100644 --- a/fat-bits/src/dir.rs +++ b/fat-bits/src/dir.rs @@ -64,24 +64,30 @@ pub struct DirEntry { file_size: u32, + // buffer for holding short name str representation + // initial dot if hidden (1) + // stem (8) + // dot (1) + // extension (3) + short_name: [u8; 13], long_name: Option, } impl Display for DirEntry { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut name = self.name_string().unwrap_or_else(|| "".to_owned()); + let name = self.name_str().unwrap_or(""); - if self.attr.contains(Attr::Directory) { - name.push('/'); - } + // add slash to end of dir_names + let dir_slash = if self.is_dir() { "/" } else { " " }; write!( f, - "{} {}", + "{} {}{}", self.attr, // self.create_time().format("%a %b %d %H:%M:%S%.3f %Y"), // self.write_time().format("%a %b %d %H:%M:%S%.3f %Y"), name, + dir_slash, )?; Ok(()) @@ -92,7 +98,7 @@ impl DirEntry { pub fn load(bytes: &[u8]) -> anyhow::Result { assert_eq!(bytes.len(), 32); - let name = bytes[..11].try_into().unwrap(); + let name: [u8; 11] = bytes[..11].try_into().unwrap(); let attr = Attr::from_bits_truncate(bytes[11]); let create_time_tenths = bytes[13]; @@ -130,6 +136,32 @@ impl DirEntry { ) } + let mut short_name = [0; 13]; + + let mut short_name_iter = short_name.iter_mut(); + + if attr.contains(Attr::Hidden) { + // if hidden: lead with '.' + *short_name_iter.next().unwrap() = b'.'; + } + + if name[0] != 0 && name[0] != 0xe5 { + // dir_entry is not free + + for c in name[..8].iter().filter(|&x| x != &0x20) { + *short_name_iter.next().unwrap() = *c; + } + + if &name[8..] != &[0x20, 0x20, 0x20] { + // if extension is not empty: add dot and extension + *short_name_iter.next().unwrap() = b'.'; + + for c in name[8..].iter().filter(|&x| x != &0x20) { + *short_name_iter.next().unwrap() = *c; + } + } + } + Ok(DirEntry { name, attr, @@ -141,6 +173,7 @@ impl DirEntry { write_time, write_date, file_size, + short_name, long_name: None, }) } @@ -216,29 +249,19 @@ impl DirEntry { std::str::from_utf8(self.extension()).ok() } - pub fn name_string(&self) -> Option { - if let Some(long_filename) = self.long_name() { - return Some(long_filename.to_owned()); + fn short_name(&self) -> &[u8] { + &self.short_name + } + + fn short_name_str(&self) -> Option<&str> { + let mut short_name = self.short_name(); + + // remove trailing zeros + while short_name.last() == Some(&0) { + short_name = &short_name[..short_name.len() - 1]; } - let name = std::str::from_utf8(&self.name[..8]).ok()?.trim_ascii_end(); - let ext = std::str::from_utf8(&self.name[8..]).ok()?.trim_ascii_end(); - - let mut s = String::new(); - - if self.attr.contains(Attr::Hidden) { - s.push('.'); - } - - s += name; - - if !ext.is_empty() { - s.push('.'); - - s += ext; - } - - Some(s) + std::str::from_utf8(short_name).ok() } pub fn long_name(&self) -> Option<&str> { @@ -249,6 +272,33 @@ impl DirEntry { self.long_name = Some(long_name); } + pub fn name_str(&self) -> Option<&str> { + if let Some(long_filename) = self.long_name() { + return Some(long_filename); + } + + self.short_name_str() + + // let name = std::str::from_utf8(&self.name[..8]).ok()?.trim_ascii_end(); + // let ext = std::str::from_utf8(&self.name[8..]).ok()?.trim_ascii_end(); + + // let mut s = String::new(); + + // if self.attr.contains(Attr::Hidden) { + // s.push('.'); + // } + + // s += name; + + // if !ext.is_empty() { + // s.push('.'); + + // s += ext; + // } + + // Some(s) + } + pub fn attr(&self) -> Attr { self.attr } @@ -540,7 +590,7 @@ impl DirIter { .map_err(|e| { anyhow::anyhow!( "failed to get long filename for {}: {}", - dir_entry.name_string().as_deref().unwrap_or(""), + dir_entry.name_str().as_deref().unwrap_or(""), e ) })? {