1use std::{ptr::null_mut, slice::from_raw_parts_mut};
2
3use core_foundation::{
4 base::{kCFAllocatorDefault, Boolean, CFAllocatorRef, CFTypeID, OSStatus, TCFType},
5 declare_TCFType, impl_CFTypeDescription, impl_TCFType,
6};
7use libc::{c_void, size_t};
8
9pub const kCMBlockBufferNoErr: OSStatus = 0;
10pub const kCMBlockBufferStructureAllocationFailedErr: OSStatus = -12700;
11pub const kCMBlockBufferBlockAllocationFailedErr: OSStatus = -12701;
12pub const kCMBlockBufferBadCustomBlockSourceErr: OSStatus = -12702;
13pub const kCMBlockBufferBadOffsetParameterErr: OSStatus = -12703;
14pub const kCMBlockBufferBadLengthParameterErr: OSStatus = -12704;
15pub const kCMBlockBufferBadPointerParameterErr: OSStatus = -12705;
16pub const kCMBlockBufferEmptyBBufErr: OSStatus = -12706;
17pub const kCMBlockBufferUnallocatedBlock: OSStatus = -12707;
18pub const kCMBlockBufferInsufficientSpaceErr: OSStatus = -12708;
19
20pub type CMBlockBufferFlags = u32;
21
22pub const kCMBlockBufferAssureMemoryNowFlag: CMBlockBufferFlags = 1 << 0;
23pub const kCMBlockBufferAlwaysCopyDataFlag: CMBlockBufferFlags = 1 << 1;
24pub const kCMBlockBufferDontOptimizeDepthFlag: CMBlockBufferFlags = 1 << 2;
25pub const kCMBlockBufferPermitEmptyReferenceFlag: CMBlockBufferFlags = 1 << 3;
26
27#[repr(C)]
28pub struct OpaqueCMBlockBuffer(c_void);
29
30pub type CMBlockBufferRef = *mut OpaqueCMBlockBuffer;
31
32#[repr(C, align(4))]
33pub struct CMBlockBufferCustomBlockSource {
34 pub version: u32,
35 pub AllocateBlock: extern "C" fn(*mut c_void, size_t) -> *mut c_void,
36 pub FreeBlock: extern "C" fn(*mut c_void, *mut c_void, size_t),
37 pub refcon: *mut c_void,
38}
39
40pub const kCMBlockBufferCustomBlockSourceVersion: u32 = 0;
41
42extern "C" {
43 pub fn CMBlockBufferCreateEmpty(
44 structureAllocator: CFAllocatorRef,
45 subBlockCapacity: size_t,
46 flags: CMBlockBufferFlags,
47 blockBufferOut: *mut CMBlockBufferRef,
48 ) -> OSStatus;
49 pub fn CMBlockBufferCreateWithMemoryBlock(
50 structureAllocator: CFAllocatorRef,
51 memoryBlock: *const c_void,
52 blockLength: size_t,
53 blockAllocator: CFAllocatorRef,
54 customBlockSource: *const CMBlockBufferCustomBlockSource,
55 offsetToData: size_t,
56 dataLength: size_t,
57 flags: CMBlockBufferFlags,
58 blockBufferOut: *mut CMBlockBufferRef,
59 ) -> OSStatus;
60 pub fn CMBlockBufferCreateWithBufferReference(
61 structureAllocator: CFAllocatorRef,
62 bufferReference: CMBlockBufferRef,
63 offsetToData: size_t,
64 dataLength: size_t,
65 flags: CMBlockBufferFlags,
66 blockBufferOut: *mut CMBlockBufferRef,
67 ) -> OSStatus;
68 pub fn CMBlockBufferCreateContiguous(
69 structureAllocator: CFAllocatorRef,
70 sourceBuffer: CMBlockBufferRef,
71 blockAllocator: CFAllocatorRef,
72 customBlockSource: *const CMBlockBufferCustomBlockSource,
73 offsetToData: size_t,
74 dataLength: size_t,
75 flags: CMBlockBufferFlags,
76 blockBufferOut: *mut CMBlockBufferRef,
77 ) -> OSStatus;
78 pub fn CMBlockBufferGetTypeID() -> CFTypeID;
79 pub fn CMBlockBufferAppendMemoryBlock(
80 theBuffer: CMBlockBufferRef,
81 memoryBlock: *const c_void,
82 blockLength: size_t,
83 blockAllocator: CFAllocatorRef,
84 customBlockSource: *const CMBlockBufferCustomBlockSource,
85 offsetToData: size_t,
86 dataLength: size_t,
87 flags: CMBlockBufferFlags,
88 ) -> OSStatus;
89 pub fn CMBlockBufferAppendBufferReference(
90 theBuffer: CMBlockBufferRef,
91 targetBBuf: CMBlockBufferRef,
92 offsetToData: size_t,
93 dataLength: size_t,
94 flags: CMBlockBufferFlags,
95 ) -> OSStatus;
96 pub fn CMBlockBufferAssureBlockMemory(theBuffer: CMBlockBufferRef) -> OSStatus;
97 pub fn CMBlockBufferAccessDataBytes(
98 theBuffer: CMBlockBufferRef,
99 offset: size_t,
100 length: size_t,
101 temporaryBlock: *mut c_void,
102 returnedPointer: *mut *mut c_void,
103 ) -> OSStatus;
104 pub fn CMBlockBufferCopyDataBytes(
105 theSourceBuffer: CMBlockBufferRef,
106 offsetToData: size_t,
107 dataLength: size_t,
108 destination: *mut c_void,
109 ) -> OSStatus;
110 pub fn CMBlockBufferReplaceDataBytes(
111 sourceBytes: *const c_void,
112 destinationBuffer: CMBlockBufferRef,
113 offsetIntoDestination: size_t,
114 dataLength: size_t,
115 ) -> OSStatus;
116 pub fn CMBlockBufferFillDataBytes(
117 fillByte: u8,
118 destinationBuffer: CMBlockBufferRef,
119 offsetIntoDestination: size_t,
120 dataLength: size_t,
121 ) -> OSStatus;
122 pub fn CMBlockBufferGetDataPointer(
123 theBuffer: CMBlockBufferRef,
124 offset: size_t,
125 lengthAtOffset: *mut size_t,
126 totalLength: *mut size_t,
127 dataPointer: *mut *mut c_void,
128 ) -> OSStatus;
129 pub fn CMBlockBufferGetDataLength(theBuffer: CMBlockBufferRef) -> size_t;
130 pub fn CMBlockBufferIsRangeContiguous(theBuffer: CMBlockBufferRef, offset: size_t, length: size_t) -> Boolean;
131 pub fn CMBlockBufferIsEmpty(theBuffer: CMBlockBufferRef) -> Boolean;
132}
133
134declare_TCFType! {
135 CMBlockBuffer, CMBlockBufferRef
136}
137impl_TCFType!(CMBlockBuffer, CMBlockBufferRef, CMBlockBufferGetTypeID);
138impl_CFTypeDescription!(CMBlockBuffer);
139
140impl CMBlockBuffer {
141 #[inline]
142 pub fn new_empty(sub_block_capacity: size_t, flags: CMBlockBufferFlags) -> Result<CMBlockBuffer, OSStatus> {
143 unsafe {
144 let mut block_buffer: CMBlockBufferRef = null_mut();
145 let status = CMBlockBufferCreateEmpty(kCFAllocatorDefault, sub_block_capacity, flags, &mut block_buffer);
146 if status == kCMBlockBufferNoErr {
147 Ok(TCFType::wrap_under_create_rule(block_buffer))
148 } else {
149 Err(status)
150 }
151 }
152 }
153
154 #[inline]
155 pub unsafe fn new_with_memory_block(
156 memory_block: &[u8],
157 custom_block_source: *const CMBlockBufferCustomBlockSource,
158 offset_to_data: size_t,
159 data_length: size_t,
160 flags: CMBlockBufferFlags,
161 ) -> Result<CMBlockBuffer, OSStatus> {
162 unsafe {
163 let mut block_buffer: CMBlockBufferRef = null_mut();
164 let status = CMBlockBufferCreateWithMemoryBlock(
165 kCFAllocatorDefault,
166 memory_block.as_ptr() as *const c_void,
167 memory_block.len() as size_t,
168 kCFAllocatorDefault,
169 custom_block_source,
170 offset_to_data,
171 data_length,
172 flags,
173 &mut block_buffer,
174 );
175 if status == kCMBlockBufferNoErr {
176 Ok(TCFType::wrap_under_create_rule(block_buffer))
177 } else {
178 Err(status)
179 }
180 }
181 }
182
183 #[inline]
184 pub fn new_with_buffer_reference(
185 &self,
186 offset_to_data: size_t,
187 data_length: size_t,
188 flags: CMBlockBufferFlags,
189 ) -> Result<CMBlockBuffer, OSStatus> {
190 unsafe {
191 let mut block_buffer: CMBlockBufferRef = null_mut();
192 let status = CMBlockBufferCreateWithBufferReference(
193 kCFAllocatorDefault,
194 self.as_concrete_TypeRef(),
195 offset_to_data,
196 data_length,
197 flags,
198 &mut block_buffer,
199 );
200 if status == kCMBlockBufferNoErr {
201 Ok(TCFType::wrap_under_create_rule(block_buffer))
202 } else {
203 Err(status)
204 }
205 }
206 }
207
208 #[inline]
209 pub unsafe fn new_contiguous(
210 &self,
211 custom_block_source: *const CMBlockBufferCustomBlockSource,
212 offset_to_data: size_t,
213 data_length: size_t,
214 flags: CMBlockBufferFlags,
215 ) -> Result<CMBlockBuffer, OSStatus> {
216 unsafe {
217 let mut block_buffer: CMBlockBufferRef = null_mut();
218 let status = CMBlockBufferCreateContiguous(
219 kCFAllocatorDefault,
220 self.as_concrete_TypeRef(),
221 kCFAllocatorDefault,
222 custom_block_source,
223 offset_to_data,
224 data_length,
225 flags,
226 &mut block_buffer,
227 );
228 if status == kCMBlockBufferNoErr {
229 Ok(TCFType::wrap_under_create_rule(block_buffer))
230 } else {
231 Err(status)
232 }
233 }
234 }
235
236 #[inline]
237 pub unsafe fn append_memory_block(
238 &self,
239 memory_block: &[u8],
240 custom_block_source: *const CMBlockBufferCustomBlockSource,
241 offset_to_data: size_t,
242 data_length: size_t,
243 flags: CMBlockBufferFlags,
244 ) -> Result<(), OSStatus> {
245 unsafe {
246 let status = CMBlockBufferAppendMemoryBlock(
247 self.as_concrete_TypeRef(),
248 memory_block.as_ptr() as *const c_void,
249 memory_block.len() as size_t,
250 kCFAllocatorDefault,
251 custom_block_source,
252 offset_to_data,
253 data_length,
254 flags,
255 );
256 if status == kCMBlockBufferNoErr {
257 Ok(())
258 } else {
259 Err(status)
260 }
261 }
262 }
263
264 #[inline]
265 pub fn append_buffer_reference(
266 &self,
267 target_block_buf: &CMBlockBuffer,
268 offset_to_data: size_t,
269 data_length: size_t,
270 flags: CMBlockBufferFlags,
271 ) -> Result<(), OSStatus> {
272 unsafe {
273 let status = CMBlockBufferAppendBufferReference(self.as_concrete_TypeRef(), target_block_buf.0, offset_to_data, data_length, flags);
274 if status == kCMBlockBufferNoErr {
275 Ok(())
276 } else {
277 Err(status)
278 }
279 }
280 }
281
282 #[inline]
283 pub fn assure_block_memory(&self) -> OSStatus {
284 unsafe { CMBlockBufferAssureBlockMemory(self.as_concrete_TypeRef()) }
285 }
286
287 #[inline]
288 pub fn access_data_bytes(&self, offset: size_t, temporary_block: &mut [u8]) -> Result<&mut [u8], OSStatus> {
289 unsafe {
290 let mut returned_pointer: *mut c_void = null_mut();
291 let status = CMBlockBufferAccessDataBytes(
292 self.as_concrete_TypeRef(),
293 offset,
294 temporary_block.len() as size_t,
295 temporary_block.as_mut_ptr() as *mut c_void,
296 &mut returned_pointer,
297 );
298 if status == kCMBlockBufferNoErr {
299 Ok(from_raw_parts_mut(returned_pointer as *mut u8, temporary_block.len()))
300 } else {
301 Err(status)
302 }
303 }
304 }
305
306 #[inline]
307 pub fn copy_data_bytes(&self, offset_to_data: size_t, destination: &mut [u8]) -> Result<(), OSStatus> {
308 unsafe {
309 let status = CMBlockBufferCopyDataBytes(
310 self.as_concrete_TypeRef(),
311 offset_to_data,
312 destination.len() as size_t,
313 destination.as_mut_ptr() as *mut c_void,
314 );
315 if status == kCMBlockBufferNoErr {
316 Ok(())
317 } else {
318 Err(status)
319 }
320 }
321 }
322
323 #[inline]
324 pub fn replace_data_bytes(&self, source_bytes: &[u8], offset_into_destination: size_t) -> Result<(), OSStatus> {
325 unsafe {
326 let status = CMBlockBufferReplaceDataBytes(
327 source_bytes.as_ptr() as *const c_void,
328 self.as_concrete_TypeRef(),
329 offset_into_destination,
330 source_bytes.len() as size_t,
331 );
332 if status == kCMBlockBufferNoErr {
333 Ok(())
334 } else {
335 Err(status)
336 }
337 }
338 }
339
340 #[inline]
341 pub fn fill_data_bytes(&self, fill_byte: u8, offset_into_destination: size_t, data_length: size_t) -> Result<(), OSStatus> {
342 unsafe {
343 let status = CMBlockBufferFillDataBytes(fill_byte, self.as_concrete_TypeRef(), offset_into_destination, data_length);
344 if status == kCMBlockBufferNoErr {
345 Ok(())
346 } else {
347 Err(status)
348 }
349 }
350 }
351
352 #[inline]
353 pub fn get_data(&self, offset: size_t) -> Result<&mut [u8], OSStatus> {
354 unsafe {
355 let mut length_at_offset: size_t = 0;
356 let mut total_length: size_t = 0;
357 let mut data_pointer: *mut c_void = null_mut();
358 let status = CMBlockBufferGetDataPointer(self.as_concrete_TypeRef(), offset, &mut length_at_offset, &mut total_length, &mut data_pointer);
359 if status == kCMBlockBufferNoErr {
360 Ok(from_raw_parts_mut(data_pointer as *mut u8, length_at_offset))
361 } else {
362 Err(status)
363 }
364 }
365 }
366
367 #[inline]
368 pub fn get_data_length(&self) -> size_t {
369 unsafe { CMBlockBufferGetDataLength(self.as_concrete_TypeRef()) }
370 }
371
372 #[inline]
373 pub fn is_range_contiguous(&self, offset: size_t, length: size_t) -> bool {
374 unsafe { CMBlockBufferIsRangeContiguous(self.as_concrete_TypeRef(), offset, length) != 0 }
375 }
376
377 #[inline]
378 pub fn is_empty(&self) -> bool {
379 unsafe { CMBlockBufferIsEmpty(self.as_concrete_TypeRef()) != 0 }
380 }
381}