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