Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/objc2-core-foundation/src/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 18 kB image not shown  

Quelle  url.rs

  Sprache: Rust
 

#[allow(unused_imports)]
use crate::{CFIndex, CFRetained, CFURL};

/// [`Path`][std::path::Path] conversion.
#[cfg(feature = "std")]
#[cfg(unix)] // TODO: Use as_encoded_bytes/from_encoded_bytes_unchecked once in MSRV.
impl CFURL {
    #[inline]
    fn from_path(
        path: &std::path::Path,
        is_directory: bool,
        base: Option<&CFURL>,
    ) -> Option<CFRetained<CFURL>> {
        use std::os::unix::ffi::OsStrExt;

        // CFURL expects to get a string with the system encoding, and will
        // internally handle the different encodings, depending on if compiled
        // for Apple platforms or Windows (which is very rare, but could
        // technically happen).
        let bytes = path.as_os_str().as_bytes();

        // Never gonna happen, allocations can't be this large in Rust.
        debug_assert!(bytes.len() < CFIndex::MAX as usize);
        let len = bytes.len() as CFIndex;

        if let Some(base) = base {
            // The base URL must be a directory URL (have a trailing "/").
            // If the path is absolute, this URL is ignored.
            //
            // TODO: Expose this publicly?
            unsafe {
                Self::from_file_system_representation_relative_to_base(
                    None,
                    bytes.as_ptr(),
                    len,
                    is_directory,
                    Some(base),
                )
            }
        } else {
            unsafe {
                Self::from_file_system_representation(None, bytes.as_ptr(), len, is_directory)
            }
        }
    }

    /// Create a file url from a [`Path`][std::path::Path].
    ///
    /// This is useful because a lot of CoreFoundation APIs use `CFURL` to
    /// represent file-system paths as well.
    ///
    /// Non-unicode parts of the URL will be percent-encoded, and the url will
    /// have the scheme `file://`.
    ///
    /// If the path is relative, it will be considered relative to the current
    /// directory.
    ///
    /// Returns `None` when given an invalid path (such as a path containing
    /// interior NUL bytes). The exact checks are not guaranteed.
    ///
    ///
    /// # Examples
    ///
    /// ```
    /// use std::path::Path;
    /// use objc2_core_foundation::CFURL;
    ///
    /// // Absolute paths work as you'd expect.
    /// let url = CFURL::from_file_path("/tmp/file.txt").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/tmp/file.txt"));
    ///
    /// // Relative paths are relative to the current directory.
    /// let url = CFURL::from_file_path("foo.txt").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), std::env::current_dir().unwrap().join("foo.txt"));
    ///
    /// // Some invalid paths return `None`.
    /// assert!(CFURL::from_file_path("").is_none());
    /// // Another example of an invalid path containing interior NUL bytes.
    /// assert!(CFURL::from_file_path("/a/\0a").is_none());
    ///
    /// // Trailing NUL bytes are stripped.
    /// // NOTE: This only seems to work on some versions of CoreFoundation.
    /// let url = CFURL::from_file_path("/a\0\0").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/a"));
    /// ```
    #[inline]
    #[doc(alias = "CFURLCreateFromFileSystemRepresentation")]
    pub fn from_file_path<P: AsRef<std::path::Path>>(path: P) -> Option<CFRetained<CFURL>> {
        Self::from_path(path.as_ref(), false, None)
    }

    /// Create a directory url from a [`Path`][std::path::Path].
    ///
    /// This differs from [`from_file_path`][Self::from_file_path] in that the
    /// path is treated as a directory, which means that other normalization
    /// rules are applied to it (to make it end with a `/`).
    ///
    ///
    /// # Examples
    ///
    /// ```
    /// use std::path::Path;
    /// use objc2_core_foundation::CFURL;
    ///
    /// // Directory paths get trailing slashes appended
    /// let url = CFURL::from_directory_path("/Library").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/Library/"));
    ///
    /// // Unless they already have them.
    /// let url = CFURL::from_directory_path("/Library/").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/Library/"));
    ///
    /// // Similarly for relative paths.
    /// let url = CFURL::from_directory_path("foo").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), std::env::current_dir().unwrap().join("foo/"));
    ///
    /// // Various dots may be stripped.
    /// let url = CFURL::from_directory_path("/Library/././.").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/Library/"));
    ///
    /// // Though of course not if they have semantic meaning.
    /// let url = CFURL::from_directory_path("/Library/..").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/Library/.."));
    /// ```
    #[inline]
    #[doc(alias = "CFURLCreateFromFileSystemRepresentation")]
    pub fn from_directory_path<P: AsRef<std::path::Path>>(path: P) -> Option<CFRetained<CFURL>> {
        Self::from_path(path.as_ref(), true, None)
    }

    /// Extract the path part of the URL as a [`PathBuf`][std::path::PathBuf].
    ///
    /// This will return a path regardless of whether the scheme is `file://`.
    /// It is the responsibility of the caller to ensure that the URL is valid
    /// to use as a file URL.
    ///
    ///
    /// # Compatibility note
    ///
    /// This currently does not work for non-unicode paths (which are fairly
    /// rare on macOS since HFS+ was been superseded by APFS).
    ///
    /// This also currently always returns absolute paths (it converts
    /// relative URL paths to absolute), but that may change in the future.
    ///
    ///
    /// # Examples
    ///
    /// ```
    /// use std::path::Path;
    /// use objc2_core_foundation::{CFURL, CFString};
    ///
    /// let url = CFURL::from_string(None, &CFString::from_str("file:///tmp/foo.txt"), None).unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/tmp/foo.txt"));
    /// ```
    ///
    /// See also the examples in [`from_file_path`][Self::from_file_path].
    #[doc(alias = "CFURLGetFileSystemRepresentation")]
    pub fn to_file_path(&self) -> Option<std::path::PathBuf> {
        use std::os::unix::ffi::OsStrExt;

        const PATH_MAX: usize = 1024;

        // TODO: if a path is relative with no base, how do we get that
        // relative path out again (without adding current dir?).
        //
        // TODO: Should we do something to handle paths larger than PATH_MAX?
        // What can we even do? (since it's impossible for us to tell why the
        // conversion failed, so we can't know if we need to allocate, or if
        // the URL just cannot be converted).
        let mut buf = [0u8; PATH_MAX];
        let result = unsafe {
            self.file_system_representation(true, buf.as_mut_ptr(), buf.len() as CFIndex)
        };
        if !result {
            return None;
        }

        // SAFETY: CF is guaranteed to null-terminate the buffer if
        // the function succeeded.
        let cstr = unsafe { core::ffi::CStr::from_bytes_until_nul(&buf).unwrap_unchecked() };

        let path = std::ffi::OsStr::from_bytes(cstr.to_bytes());
        Some(path.into())
    }
}

/// String conversion.
impl CFURL {
    /// Create an URL from a `CFString`.
    ///
    /// Returns `None` if the URL is considered invalid by CoreFoundation. The
    /// exact details of which strings are invalid URLs are considered an
    /// implementation detail.
    ///
    /// Note in particular that not all strings that the URL spec considers
    /// invalid are considered invalid by CoreFoundation too. If you need
    /// spec-compliant parsing, consider the [`url`] crate instead.
    ///
    /// [`url`]: https://docs.rs/url/
    ///
    /// # Examples
    ///
    /// Construct and inspect a `CFURL`.
    ///
    /// ```
    /// use objc2_core_foundation::{
    ///     CFString, CFURL, CFURLCopyHostName, CFURLCopyScheme, CFURLCopyPath,
    /// };
    ///
    /// let url = CFURL::from_string(None, &CFString::from_str("http://example.com/foo"), None).unwrap();
    /// assert_eq!(url.string().to_string(), "http://example.com/foo");
    /// assert_eq!(CFURLCopyScheme(&url).unwrap().to_string(), "http");
    /// assert_eq!(CFURLCopyHostName(&url).unwrap().to_string(), "example.com");
    /// assert_eq!(CFURLCopyPath(&url).unwrap().to_string(), "/foo");
    /// ```
    ///
    /// Fail parsing certain strings.
    ///
    /// ```
    /// use objc2_core_foundation::{CFString, CFURL};
    ///
    /// // Percent-encoding needs two characters.
    /// assert_eq!(CFURL::from_string(None, &CFString::from_str("http://example.com/%A"), None), None);
    ///
    /// // Two hash-characters is disallowed.
    /// assert_eq!(CFURL::from_string(None, &CFString::from_str("='_blank'>http://example.com/abc#a#b"), None), None);
    /// ```
    #[inline]
    #[doc(alias = "CFURLCreateWithString")]
    pub fn from_string(
        allocator: Option<&crate::CFAllocator>,
        url_string: &crate::CFString,
        base_url: Option<&CFURL>,
    ) -> Option<CFRetained<Self>> {
        Self::__from_string(allocator, Some(url_string), base_url)
    }

    /// Create an URL from a string without checking it for validity.
    ///
    /// Returns `None` on some OS versions when the string contains interior
    /// NUL bytes.
    ///
    /// # Safety
    ///
    /// The URL must be valid.
    ///
    /// Note that it is unclear whether this is actually a safety requirement,
    /// or simply a correctness requirement. So we conservatively mark this
    /// function as `unsafe`.
    #[inline]
    #[cfg(feature = "CFString")]
    #[doc(alias = "CFURLCreateWithBytes")]
    pub unsafe fn from_str_unchecked(s: &str) -> Option<CFRetained<Self>> {
        let ptr = s.as_ptr();

        // Never gonna happen, allocations can't be this large in Rust.
        debug_assert!(s.len() < CFIndex::MAX as usize);
        let len = s.len() as CFIndex;

        let encoding = crate::CFStringBuiltInEncodings::EncodingUTF8;
        // SAFETY: The pointer and length are valid, and the encoding is a
        // superset of ASCII.
        //
        // Unlike `CFURLCreateWithString`, this does _not_ verify the URL at
        // all, and thus we propagate the validity checks to the user. See
        // also the source code for the checks:
        // https://github.com/apple-oss-distributions/CF/blob/CF-1153.18/CFURL.c#L1882-L1970
        unsafe { Self::with_bytes(None, ptr, len, encoding.0, None) }
    }

    /// Get the string-representation of the URL.
    ///
    /// The string may be overly sanitized (percent-encoded), do not rely on
    /// this returning exactly the same string as was passed in
    /// [`from_string`][Self::from_string].
    #[doc(alias = "CFURLGetString")]
    pub fn string(&self) -> CFRetained<crate::CFString> {
        // URLs contain valid UTF-8, so this should only fail on allocation
        // error.
        self.__string().expect("failed getting string from CFURL")
    }
}

#[cfg(unix)]
#[cfg(test)]
#[cfg(feature = "CFString")]
#[cfg(feature = "std")]
mod tests {
    use std::ffi::OsStr;
    use std::os::unix::ffi::OsStrExt;
    use std::path::Path;
    use std::{env::current_dir, string::ToString};

    use crate::{CFString, CFURLPathStyle};

    use super::*;

    #[test]
    fn from_string() {
        let url =
            CFURL::from_string(None, &CFString::from_str("https://example.com/xyz"), None).unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new("/xyz"));
        assert_eq!(url.string().to_string(), "https://example.com/xyz");

        // Invalid.
        let url = CFURL::from_string(None, &CFString::from_str("\0"), None);
        assert_eq!(url, None);

        // Also invalid.
        let url = CFURL::from_string(None, &CFString::from_str("http://example.com/%a"), None);
        assert_eq!(url, None);

        // Though using `from_str_unchecked` succeeds.
        let url = unsafe { CFURL::from_str_unchecked("http://example.com/%a") }.unwrap();
        assert_eq!(url.string().to_string(), "http://example.com/%25a");
        assert_eq!(url.to_file_path().unwrap(), Path::new("/%a"));

        let url = unsafe { CFURL::from_str_unchecked("/\0a\0") }.unwrap();
        assert_eq!(url.string().to_string(), "/%00a%00");
        assert_eq!(url.to_file_path(), None);
    }

    #[test]
    fn to_string_may_extra_percent_encode() {
        let url = CFURL::from_string(None, &CFString::from_str("["), None).unwrap();
        assert_eq!(url.string().to_string(), "%5B");
    }

    #[test]
    #[cfg(feature = "objc2")]
    fn invalid_with_nul_bytes() {
        // This is a bug in newer CF versions:
        // https://github.com/swiftlang/swift-corelibs-foundation/issues/5200
        let url = unsafe { CFURL::from_str_unchecked("a\0aaaaaa") };
        if objc2::available!(macos = 12.0, ios = 15.0, watchos = 8.0, tvos = 15.0, ..) {
            assert_eq!(url, None);
        } else {
            assert_eq!(url.unwrap().string().to_string(), "a%00aaaaaa");
        }
    }

    #[test]
    fn to_from_path() {
        let url = CFURL::from_file_path("/").unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new("/"));

        let url = CFURL::from_file_path("/abc/def").unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new("/abc/def"));

        let url = CFURL::from_directory_path("/abc/def").unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new("/abc/def/"));

        let url = CFURL::from_file_path("relative.txt").unwrap();
        assert_eq!(
            url.to_file_path(),
            Some(current_dir().unwrap().join("relative.txt"))
        );
        assert_eq!(
            url.absolute_url().unwrap().to_file_path(),
            Some(current_dir().unwrap().join("relative.txt"))
        );

        let str = "/with space and wéird UTF-8 chars: ��";
        let url = CFURL::from_file_path(str).unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new(str));
    }

    #[test]
    fn invalid_path() {
        assert_eq!(CFURL::from_file_path(""), None);
        assert_eq!(CFURL::from_file_path("/\0/a"), None);
    }

    #[test]
    fn from_dir_strips_dot() {
        let url = CFURL::from_directory_path("/Library/.").unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new("/Library/"));
    }

    /// Ensure that trailing NULs are completely stripped.
    #[test]
    #[cfg_attr(
        not(target_os = "macos"),
        ignore = "seems to work differently in the simulator"
    )]
    fn path_with_trailing_nul() {
        let url = CFURL::from_file_path("/abc/def\0\0\0").unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new("/abc/def"));

        let path = url
            .file_system_path(CFURLPathStyle::CFURLPOSIXPathStyle)
            .unwrap();
        assert_eq!(path.to_string(), "/abc/def");
        #[allow(deprecated)]
        let path = url
            .file_system_path(CFURLPathStyle::CFURLHFSPathStyle)
            .unwrap();
        assert!(path.to_string().ends_with(":abc:def")); // $DISK_NAME:abc:def
        let path = url
            .file_system_path(CFURLPathStyle::CFURLWindowsPathStyle)
            .unwrap();
        assert_eq!(path.to_string(), "\\abc\\def");
    }

    #[test]
    fn path_with_base() {
        let base = CFURL::from_directory_path("/abc/").unwrap();
        let url = CFURL::from_path(Path::new("def"), false, Some(&base)).unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new("/abc/def"));
        let url = CFURL::from_path(Path::new("def/"), false, Some(&base)).unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new("/abc/def/"));
        let url = CFURL::from_path(Path::new("/def"), false, Some(&base)).unwrap();
        assert_eq!(url.to_file_path().unwrap(), Path::new("/def"));
    }

    #[test]
    fn path_invalid_utf8() {
        // Non-root path.
        let url = CFURL::from_file_path(OsStr::from_bytes(b"abc\xd4def/xyz")).unwrap();
        assert_eq!(url.to_file_path().unwrap(), current_dir().unwrap()); // Huh?
        assert!(url
            .file_system_path(CFURLPathStyle::CFURLPOSIXPathStyle)
            .is_none());
        assert_eq!(url.string().to_string(), "abc%D4def/xyz");
        assert_eq!(url.path().unwrap().to_string(), "abc%D4def/xyz");

        // Root path.
        // lone continuation byte (128) (invalid utf8)
        let url = CFURL::from_file_path(OsStr::from_bytes(b"/\xf8a/b/c")).unwrap();
        assert_eq!(
            url.to_file_path().unwrap(),
            OsStr::from_bytes(b"/\xf8a/b/c")
        );
        assert_eq!(url.string().to_string(), "file:///%F8a/b/c");
        assert_eq!(url.path().unwrap().to_string(), "/%F8a/b/c");

        // Joined paths
        let url = CFURL::from_path(
            Path::new(OsStr::from_bytes(b"sub\xd4/%D4")),
            false,
            Some(&url),
        )
        .unwrap();
        assert_eq!(url.to_file_path(), None);
        assert_eq!(url.string().to_string(), "sub%D4/%25D4");
        assert_eq!(url.path().unwrap().to_string(), "sub%D4/%25D4");
        let abs = url.absolute_url().unwrap();
        assert_eq!(abs.to_file_path(), None);
        assert_eq!(abs.string().to_string(), "file:///%F8a/b/sub%D4/%25D4");
        assert_eq!(abs.path().unwrap().to_string(), "/%F8a/b/sub%D4/%25D4");
    }

    #[test]
    fn path_percent_encoded() {
        let url = CFURL::from_file_path("/%D4").unwrap();
        assert_eq!(url.path().unwrap().to_string(), "/%25D4");
        assert_eq!(url.to_file_path().unwrap(), Path::new("/%D4"));

        let url = CFURL::from_file_path("/%invalid").unwrap();
        assert_eq!(url.path().unwrap().to_string(), "/%25invalid");
        assert_eq!(url.to_file_path().unwrap(), Path::new("/%invalid"));
    }

    #[test]
    fn path_percent_encoded_eq() {
        let normal = CFURL::from_file_path(OsStr::from_bytes(b"\xf8")).unwrap();
        let percent = CFURL::from_file_path("%F8").unwrap();
        // Not equal, even though the filesystem may consider these paths equal.
        assert_ne!(normal, percent);
    }

    #[test]
    #[allow(deprecated)]
    #[ignore = "TODO: Crashes - is this unsound?"]
    fn hfs_invalid_utf8() {
        let url = CFURL::from_file_path(OsStr::from_bytes(b"\xd4")).unwrap();
        assert!(url
            .file_system_path(CFURLPathStyle::CFURLHFSPathStyle)
            .is_none());
    }
}

Messung V0.5 in Prozent
C=64 H=91 G=78

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.