From ab84ad75629b0a4124221023ca91411d2cd62a32 Mon Sep 17 00:00:00 2001
From: Ben Bridle <ben@derelict.engineering>
Date: Tue, 25 Mar 2025 12:46:49 +1300
Subject: Restructure program

This commit also includes changes to devices according to the latest
devices specification, in particular the math and system devices.
---
 src/devices/file_device/bedrock_file_path.rs | 287 ---------------------------
 1 file changed, 287 deletions(-)
 delete mode 100644 src/devices/file_device/bedrock_file_path.rs

(limited to 'src/devices/file_device/bedrock_file_path.rs')

diff --git a/src/devices/file_device/bedrock_file_path.rs b/src/devices/file_device/bedrock_file_path.rs
deleted file mode 100644
index fdd8f79..0000000
--- a/src/devices/file_device/bedrock_file_path.rs
+++ /dev/null
@@ -1,287 +0,0 @@
-use super::*;
-
-use std::cmp::Ordering;
-use std::ffi::OsString;
-
-
-#[derive(Clone)]
-pub struct BedrockFilePath {
-    /// Sandbox directory
-    base: PathBuf,
-    /// Path relative to sandbox directory
-    relative: PathBuf,
-    bytes: Vec<u8>,
-    entry_type: Option<EntryType>,
-}
-
-impl BedrockFilePath {
-    pub fn from_buffer(buffer: [u8; 256], base: &Path) -> Option<Self> {
-        let base = base.to_path_buf();
-        let relative = buffer_to_path(buffer)?;
-        let bytes = path_to_bytes(&relative)?;
-        let entry_type = get_entry_type(base.join(&relative));
-        assert_path_is_safe(&relative, &base)?;
-        Some(Self { base, relative, bytes, entry_type })
-    }
-
-    /// Construct an instance from an absolute path and a prefix of that path.
-    pub fn from_path(path: &Path, base: &Path) -> Option<Self> {
-        let base = base.to_path_buf();
-        let relative = path.strip_prefix(&base).ok()?.to_path_buf();
-        let bytes = path_to_bytes(&relative)?;
-        let entry_type = get_entry_type(base.join(&relative));
-        assert_path_is_safe(&relative, &base)?;
-        Some( Self { base, relative, bytes, entry_type } )
-    }
-
-    /// Get the base path used by this path.
-    pub fn base(&self) -> &Path {
-        &self.base
-    }
-
-    /// Get this path as a Bedrock-style path, which can be passed to
-    /// a Bedrock program.
-    pub fn as_bytes(&self) -> &[u8] {
-        &self.bytes
-    }
-
-    /// Get this path as a byte buffer, from which a CircularPathBuffer
-    /// can be populated.
-    pub fn as_buffer(&self) -> [u8; 256] {
-        let mut buffer: [u8; 256] = [0; 256];
-        buffer[..self.bytes.len()].copy_from_slice(&self.bytes);
-        return buffer;
-    }
-
-    /// Get this path as an absolute operating-system path, which can
-    /// be used to open a file or directory.
-    pub fn as_path(&self) -> PathBuf {
-        self.base.join(&self.relative)
-    }
-
-    /// Get the entry type of this path.
-    pub fn entry_type(&self) -> Option<EntryType> {
-        self.entry_type
-    }
-
-    /// Get a path which represents the parent of this path.
-    pub fn parent(&self) -> Option<Self> {
-        #[cfg(target_family = "unix")] {
-            Self::from_path(self.as_path().parent()?, &self.base)
-        }
-        #[cfg(target_family = "windows")] {
-            if self.base.components().count() != 0 {
-                // Sandboxed path, cannot ascend to a virtual root directory.
-                Self::from_path(self.as_path().parent()?, &self.base)
-            } else {
-                // Unsandboxed path, we can ascend to a virtual root directory.
-                match self.as_path().parent() {
-                    // Ascend to concrete parent directory.
-                    Some(parent) => Self::from_path(parent, &self.base),
-                    // Ascend into a virtual root directory.
-                    None => {
-                        if self.relative.components().count() != 0 {
-                            // Ascend from concrete path to virtual root.
-                            let blank = PathBuf::from("");
-                            BedrockFilePath::from_path(&blank, &blank)
-                        } else {
-                            // Cannot ascend above the virtual root.
-                            None
-                        }
-                    },
-                }
-            }
-        }
-    }
-
-    /// Returns true if the file would be hidden by the default file browser.
-    pub fn is_hidden(&self) -> bool {
-        #[cfg(target_family = "unix")] {
-            if let Some(stem) = self.relative.file_stem() {
-                if let Some(string) = stem.to_str() {
-                    return string.starts_with('.');
-                }
-            }
-        }
-        #[cfg(target_family = "windows")] {
-            use std::os::windows::fs::MetadataExt;
-            // See https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
-            // const FILE_ATTRIBUTE_HIDDEN: u32 = 0x00000002;
-            // const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: u32 = 0x00002000;
-            if let Ok(metadata) = std::fs::metadata(self.as_path()) {
-                return metadata.file_attributes() & 0x2002 != 0;
-            }
-        }
-        return false;
-    }
-}
-
-
-/// Converts the contents of a CircularPathBuffer to a relative path.
-fn buffer_to_path(bytes: [u8; 256]) -> Option<PathBuf> {
-    // The buffer must be non-empty and slash-prefixed.
-    if bytes[0] != ('/' as u8) {
-        return None;
-    }
-
-    // Find the index of the first null byte.
-    let mut null_i = None;
-    for (i, b) in bytes.iter().enumerate() {
-        if *b == 0x00 {
-            null_i = Some(i);
-            break;
-        }
-    }
-    // Take a slice, excluding the leading slash, up to the trailing null.
-    let slice = &bytes[1..null_i?];
-
-    #[cfg(target_family = "unix")] {
-        use std::os::unix::ffi::OsStringExt;
-        let vec = Vec::from(slice);
-        return Some(OsString::from_vec(vec).into())
-    }
-    #[cfg(target_family = "windows")] {
-        use std::os::windows::ffi::OsStringExt;
-        let mut string = String::from_utf8_lossy(slice).to_string();
-        // Convert drive-current-directory paths to drive-root paths. This is
-        // needed because the paths C: and C:/ point to separate directories,
-        // but trailing forward-slashes are optional in Bedrock.
-        if string.ends_with(':') {
-            string.push('/');
-        }
-        let utf16: Vec<u16> = string.replace(r"/", r"\").encode_utf16().collect();
-        return Some(OsString::from_wide(&utf16).into())
-    }
-}
-
-/// Convert an operating system path to a Bedrock-style byte path.
-///
-/// A byte path contains at most 255 bytes, and is not null-terminated.
-fn path_to_bytes(path: &Path) -> Option<Vec<u8>> {
-    #[cfg(target_family = "unix")]
-    let string = path.as_os_str().to_str()?.to_string();
-    #[cfg(target_family = "windows")]
-    let string = path.as_os_str().to_str()?.replace(r"\", r"/");
-
-    // Remove any trailing forward-slash and add a leading forward-slash.
-    let mut prefixed_string = String::from("/");
-    prefixed_string.push_str(string.trim_end_matches('/'));
-    let slice = prefixed_string.as_bytes();
-
-    // Error if bytes does not fit into a CircularPathBuffer.
-    if slice.len() > 255 { return None; }
-
-    Some(Vec::from(slice))
-}
-
-/// Returns true if a relative path can be safely attached to a base without
-/// breaking out of the sandbox.
-fn assert_path_is_safe(relative: &Path, _base: &Path) -> Option<()> {
-    #[cfg(target_family = "unix")] {
-        // Error if path contains special components.
-        for component in relative.components() {
-            match component {
-                Component::Normal(_) => continue,
-                _ => return None,
-            }
-        }
-    }
-    #[cfg(target_family = "windows")] {
-        // If the base path is empty, the relative path needs to be able to
-        // contain the prefix and root element. If the base path is not
-        // empty, the relative path must not contain these elements else
-        // they will override the base path when joined.
-        if _base.components().count() != 0 {
-            for component in relative.components() {
-                match component {
-                    Component::Normal(_) => continue,
-                    _ => return None,
-                }
-            }
-        }
-    }
-    return Some(());
-}
-
-fn get_entry_type(absolute: PathBuf) -> Option<EntryType> {
-    #[cfg(target_family = "windows")] {
-        // If path is empty, this is a virtual root directory.
-        if absolute.components().count() == 0 {
-            return Some(EntryType::Directory)
-        }
-    }
-    let metadata = std::fs::metadata(absolute).ok()?;
-    if metadata.is_file() {
-        Some(EntryType::File)
-    } else if metadata.is_dir() {
-        Some(EntryType::Directory)
-    } else {
-        None
-    }
-}
-
-impl std::fmt::Debug for BedrockFilePath {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
-        self.as_path().fmt(f)
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-impl PartialEq for BedrockFilePath {
-    fn eq(&self, other: &Self) -> bool {
-        self.bytes == other.bytes && self.entry_type == other.entry_type
-    }
-}
-
-impl Eq for BedrockFilePath {}
-
-impl PartialOrd for BedrockFilePath {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for BedrockFilePath {
-    fn cmp(&self, other: &Self) -> Ordering {
-        match self.entry_type.cmp(&other.entry_type) {
-            Ordering::Equal => compare_ascii_slices(&self.bytes, &other.bytes),
-            ordering => ordering,
-        }
-    }
-}
-
-/// Compare two ASCII byte-slices in case-agnostic alphabetic order.
-fn compare_ascii_slices(left: &[u8], right: &[u8]) -> Ordering {
-    let l = std::cmp::min(left.len(), right.len());
-    let lhs = &left[..l];
-    let rhs = &right[..l];
-
-    for i in 0..l {
-        let a = remap_ascii(lhs[i]);
-        let b = remap_ascii(rhs[i]);
-        match a.cmp(&b) {
-            Ordering::Equal => (),
-            non_eq => return non_eq,
-        }
-    }
-
-    left.len().cmp(&right.len())
-}
-
-/// Remap ASCII values so that they sort in case-agnostic alphabetic order:
-///
-/// ```text
-///    !"#$%&'()*+,-./0123456789:;<=>?
-///   @`AaBbCcDdEeFfGgHhIiJjKkLlMmNnOo
-///   PpQqRrSsTtUuVvWwXxYyZz[{\|]}^~_
-/// ```
-fn remap_ascii(c: u8) -> u8 {
-    if 0x40 <= c && c <= 0x5F {
-        (c - 0x40) * 2 + 0x40
-    } else if 0x60 <= c && c <= 0x7F {
-        (c - 0x60) * 2 + 0x41
-    } else {
-        c
-    }
-}
-- 
cgit v1.2.3-70-g09d2