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