Skip to main content

core_graphics2/
data_provider.rs

1use std::{ffi::CString, ptr::null_mut, sync::Arc};
2
3use core_foundation::{
4    base::{CFTypeID, TCFType},
5    data::{CFData, CFDataRef},
6    impl_CFTypeDescription, impl_TCFType,
7    url::{CFURLRef, CFURL},
8};
9use libc::{c_char, c_void, off_t, size_t};
10
11#[repr(C)]
12pub struct __CGDataProvider(c_void);
13
14pub type CGDataProviderRef = *const __CGDataProvider;
15
16pub type CGDataProviderGetBytesCallback = extern "C" fn(*mut c_void, *mut c_void, size_t) -> size_t;
17pub type CGDataProviderSkipForwardCallback = extern "C" fn(*mut c_void, off_t) -> off_t;
18pub type CGDataProviderRewindCallback = extern "C" fn(*mut c_void);
19pub type CGDataProviderReleaseInfoCallback = extern "C" fn(*mut c_void);
20
21#[repr(C)]
22pub struct CGDataProviderSequentialCallbacks {
23    pub version: u32,
24    pub getBytes: CGDataProviderGetBytesCallback,
25    pub skipForward: CGDataProviderSkipForwardCallback,
26    pub rewind: CGDataProviderRewindCallback,
27    pub releaseInfo: CGDataProviderReleaseInfoCallback,
28}
29
30pub type CGDataProviderGetBytePointerCallback = extern "C" fn(*mut c_void) -> *mut c_void;
31pub type CGDataProviderReleaseBytePointerCallback = extern "C" fn(*mut c_void, *const c_void);
32pub type CGDataProviderGetBytesAtPositionCallback = extern "C" fn(*mut c_void, *mut c_void, off_t, size_t);
33
34#[repr(C)]
35pub struct CGDataProviderDirectCallbacks {
36    pub version: u32,
37    pub getBytePointer: CGDataProviderGetBytePointerCallback,
38    pub releaseBytePointer: CGDataProviderReleaseBytePointerCallback,
39    pub getBytesAtPosition: CGDataProviderGetBytesAtPositionCallback,
40    pub releaseInfo: CGDataProviderReleaseInfoCallback,
41}
42
43pub type CGDataProviderReleaseDataCallback = extern "C" fn(*mut c_void, *const c_void, size_t);
44
45extern "C" {
46    pub fn CGDataProviderGetTypeID() -> CFTypeID;
47    pub fn CGDataProviderCreateSequential(info: *mut c_void, callbacks: *const CGDataProviderSequentialCallbacks) -> CGDataProviderRef;
48    pub fn CGDataProviderCreateDirect(info: *mut c_void, size: off_t, callbacks: *const CGDataProviderDirectCallbacks) -> CGDataProviderRef;
49    pub fn CGDataProviderCreateWithData(
50        info: *mut c_void,
51        data: *const c_void,
52        size: size_t,
53        releaseData: Option<CGDataProviderReleaseDataCallback>,
54    ) -> CGDataProviderRef;
55    pub fn CGDataProviderCreateWithCFData(data: CFDataRef) -> CGDataProviderRef;
56    pub fn CGDataProviderCreateWithURL(url: CFURLRef) -> CGDataProviderRef;
57    pub fn CGDataProviderCreateWithFilename(filename: *const c_char) -> CGDataProviderRef;
58    pub fn CGDataProviderRetain(provider: CGDataProviderRef) -> CGDataProviderRef;
59    pub fn CGDataProviderRelease(provider: CGDataProviderRef);
60    pub fn CGDataProviderCopyData(provider: CGDataProviderRef) -> CFDataRef;
61    pub fn CGDataProviderGetInfo(provider: CGDataProviderRef) -> *mut c_void;
62}
63
64pub struct CGDataProvider(CGDataProviderRef);
65
66impl Drop for CGDataProvider {
67    fn drop(&mut self) {
68        unsafe { CGDataProviderRelease(self.0) }
69    }
70}
71
72impl_TCFType!(CGDataProvider, CGDataProviderRef, CGDataProviderGetTypeID);
73impl_CFTypeDescription!(CGDataProvider);
74
75impl CGDataProvider {
76    pub unsafe fn new_sequential(info: *mut c_void, callbacks: *const CGDataProviderSequentialCallbacks) -> Option<Self> {
77        let provider = CGDataProviderCreateSequential(info, callbacks);
78        if provider.is_null() {
79            None
80        } else {
81            Some(TCFType::wrap_under_create_rule(provider))
82        }
83    }
84
85    pub unsafe fn new_direct(info: *mut c_void, size: off_t, callbacks: *const CGDataProviderDirectCallbacks) -> Option<Self> {
86        let provider = CGDataProviderCreateDirect(info, size, callbacks);
87        if provider.is_null() {
88            None
89        } else {
90            Some(TCFType::wrap_under_create_rule(provider))
91        }
92    }
93
94    pub fn from_buffer<T>(buffer: Arc<T>) -> Option<Self>
95    where
96        T: AsRef<[u8]> + Sync + Send,
97    {
98        unsafe {
99            let ptr = (*buffer).as_ref().as_ptr() as *const c_void;
100            let len = (*buffer).as_ref().len() as size_t;
101            let info = Arc::into_raw(buffer) as *mut c_void;
102            let data_provider = CGDataProviderCreateWithData(info, ptr, len, Some(release::<T>));
103            if data_provider.is_null() {
104                drop(Arc::from_raw(info));
105                return None;
106            } else {
107                return Some(TCFType::wrap_under_create_rule(data_provider));
108            }
109        }
110
111        extern "C" fn release<T>(info: *mut c_void, _: *const c_void, _: size_t) {
112            unsafe { drop(Arc::from_raw(info as *mut T)) }
113        }
114    }
115
116    pub unsafe fn from_slice(buffer: &[u8]) -> Option<Self> {
117        let ptr = buffer.as_ptr() as *const c_void;
118        let len = buffer.len() as size_t;
119        let data_provider = CGDataProviderCreateWithData(null_mut(), ptr, len, None);
120        if data_provider.is_null() {
121            None
122        } else {
123            Some(TCFType::wrap_under_create_rule(data_provider))
124        }
125    }
126
127    pub fn from_data(data: &CFData) -> Option<Self> {
128        unsafe {
129            let data_provider = CGDataProviderCreateWithCFData(data.as_concrete_TypeRef());
130            if data_provider.is_null() {
131                None
132            } else {
133                Some(TCFType::wrap_under_create_rule(data_provider))
134            }
135        }
136    }
137
138    pub fn from_url(url: CFURL) -> Option<Self> {
139        unsafe {
140            let data_provider = CGDataProviderCreateWithURL(url.as_concrete_TypeRef());
141            if data_provider.is_null() {
142                None
143            } else {
144                Some(TCFType::wrap_under_create_rule(data_provider))
145            }
146        }
147    }
148
149    pub fn from_filename(filename: &str) -> Option<Self> {
150        let c_str = CString::new(filename).ok()?;
151        unsafe {
152            let data_provider = CGDataProviderCreateWithFilename(c_str.as_ptr() as *const c_char);
153            if data_provider.is_null() {
154                None
155            } else {
156                Some(TCFType::wrap_under_create_rule(data_provider))
157            }
158        }
159    }
160
161    pub fn copy_data(&self) -> Option<CFData> {
162        unsafe {
163            let data = CGDataProviderCopyData(self.as_concrete_TypeRef());
164            if data.is_null() {
165                None
166            } else {
167                Some(TCFType::wrap_under_create_rule(data))
168            }
169        }
170    }
171
172    pub unsafe fn get_info(&self) -> *mut c_void {
173        unsafe { CGDataProviderGetInfo(self.as_concrete_TypeRef()) }
174    }
175}