1use std::ptr;
2
3use super::CFURL;
4use crate::raw;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7#[repr(i64)]
8pub enum CFURLComponent {
9 Scheme = 1,
10 Authority = 2,
11 Path = 3,
12 ResourceSpecifier = 4,
13 User = 5,
14 Password = 6,
15 Host = 8,
16 Port = 9,
17 Parameters = 10,
18 Query = 11,
19 Fragment = 12,
20}
21
22impl CFURL {
23 #[must_use]
24 pub fn parse(value: &str, base: Option<&Self>) -> Option<Self> {
25 let length = i64::try_from(value.len()).ok()?;
26 let reference = unsafe {
27 raw::CFURLCreateWithBytes(
28 ptr::null(),
29 value.as_ptr(),
30 length,
31 0x0800_0100,
32 base.map_or(ptr::null(), |base| base.as_ptr().cast()),
33 )
34 };
35 let reference = unsafe { Self::from_raw(reference.cast_mut().cast()) }?;
36 if base.is_none() {
37 return Some(reference);
38 }
39 let absolute = unsafe { raw::CFURLCopyAbsoluteURL(reference.as_ptr().cast()) };
40 unsafe { Self::from_raw(absolute.cast_mut().cast()) }
41 }
42
43 #[must_use]
44 pub fn component(&self, component: CFURLComponent) -> Option<String> {
45 let url = self.as_ptr().cast();
46 let range =
47 unsafe { raw::CFURLGetByteRangeForComponent(url, component as i64, ptr::null_mut()) };
48 let start = usize::try_from(range.location).ok()?;
49 let length = usize::try_from(range.length).ok()?;
50 let byte_count = unsafe { raw::CFURLGetBytes(url, ptr::null_mut(), 0) };
51 let mut bytes = vec![0; usize::try_from(byte_count).ok()?];
52 let copied = unsafe { raw::CFURLGetBytes(url, bytes.as_mut_ptr(), byte_count) };
53 if copied != byte_count {
54 return None;
55 }
56 let end = start.checked_add(length)?;
57 String::from_utf8(bytes.get(start..end)?.to_vec()).ok()
58 }
59}