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