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!(CMBlockBuffer, CMBlockBufferRef);
135impl_TCFType!(CMBlockBuffer, CMBlockBufferRef, CMBlockBufferGetTypeID);
136impl_CFTypeDescription!(CMBlockBuffer);
137
138impl CMBlockBuffer {
139 #[inline]
140 pub fn new_empty(sub_block_capacity: size_t, flags: CMBlockBufferFlags) -> Result<CMBlockBuffer, OSStatus> {
141 unsafe {
142 let mut block_buffer: CMBlockBufferRef = null_mut();
143 let status = CMBlockBufferCreateEmpty(kCFAllocatorDefault, sub_block_capacity, flags, &mut block_buffer);
144 if status == kCMBlockBufferNoErr {
145 Ok(TCFType::wrap_under_create_rule(block_buffer))
146 } else {
147 Err(status)
148 }
149 }
150 }
151
152 #[inline]
153 pub unsafe fn new_with_memory_block(
154 memory_block: &[u8],
155 custom_block_source: *const CMBlockBufferCustomBlockSource,
156 offset_to_data: size_t,
157 data_length: size_t,
158 flags: CMBlockBufferFlags,
159 ) -> Result<CMBlockBuffer, OSStatus> {
160 unsafe {
161 let mut block_buffer: CMBlockBufferRef = null_mut();
162 let status = CMBlockBufferCreateWithMemoryBlock(
163 kCFAllocatorDefault,
164 memory_block.as_ptr() as *const c_void,
165 memory_block.len() as size_t,
166 kCFAllocatorDefault,
167 custom_block_source,
168 offset_to_data,
169 data_length,
170 flags,
171 &mut block_buffer,
172 );
173 if status == kCMBlockBufferNoErr {
174 Ok(TCFType::wrap_under_create_rule(block_buffer))
175 } else {
176 Err(status)
177 }
178 }
179 }
180
181 #[inline]
182 pub fn new_with_buffer_reference(
183 &self,
184 offset_to_data: size_t,
185 data_length: size_t,
186 flags: CMBlockBufferFlags,
187 ) -> Result<CMBlockBuffer, OSStatus> {
188 unsafe {
189 let mut block_buffer: CMBlockBufferRef = null_mut();
190 let status = CMBlockBufferCreateWithBufferReference(
191 kCFAllocatorDefault,
192 self.as_concrete_TypeRef(),
193 offset_to_data,
194 data_length,
195 flags,
196 &mut block_buffer,
197 );
198 if status == kCMBlockBufferNoErr {
199 Ok(TCFType::wrap_under_create_rule(block_buffer))
200 } else {
201 Err(status)
202 }
203 }
204 }
205
206 #[inline]
207 pub unsafe fn new_contiguous(
208 &self,
209 custom_block_source: *const CMBlockBufferCustomBlockSource,
210 offset_to_data: size_t,
211 data_length: size_t,
212 flags: CMBlockBufferFlags,
213 ) -> Result<CMBlockBuffer, OSStatus> {
214 unsafe {
215 let mut block_buffer: CMBlockBufferRef = null_mut();
216 let status = CMBlockBufferCreateContiguous(
217 kCFAllocatorDefault,
218 self.as_concrete_TypeRef(),
219 kCFAllocatorDefault,
220 custom_block_source,
221 offset_to_data,
222 data_length,
223 flags,
224 &mut block_buffer,
225 );
226 if status == kCMBlockBufferNoErr {
227 Ok(TCFType::wrap_under_create_rule(block_buffer))
228 } else {
229 Err(status)
230 }
231 }
232 }
233
234 #[inline]
235 pub unsafe fn append_memory_block(
236 &self,
237 memory_block: &[u8],
238 custom_block_source: *const CMBlockBufferCustomBlockSource,
239 offset_to_data: size_t,
240 data_length: size_t,
241 flags: CMBlockBufferFlags,
242 ) -> Result<(), OSStatus> {
243 unsafe {
244 let status = CMBlockBufferAppendMemoryBlock(
245 self.as_concrete_TypeRef(),
246 memory_block.as_ptr() as *const c_void,
247 memory_block.len() as size_t,
248 kCFAllocatorDefault,
249 custom_block_source,
250 offset_to_data,
251 data_length,
252 flags,
253 );
254 if status == kCMBlockBufferNoErr {
255 Ok(())
256 } else {
257 Err(status)
258 }
259 }
260 }
261
262 #[inline]
263 pub fn append_buffer_reference(
264 &self,
265 target_block_buf: &CMBlockBuffer,
266 offset_to_data: size_t,
267 data_length: size_t,
268 flags: CMBlockBufferFlags,
269 ) -> Result<(), OSStatus> {
270 unsafe {
271 let status = CMBlockBufferAppendBufferReference(self.as_concrete_TypeRef(), target_block_buf.0, offset_to_data, data_length, flags);
272 if status == kCMBlockBufferNoErr {
273 Ok(())
274 } else {
275 Err(status)
276 }
277 }
278 }
279
280 #[inline]
281 pub fn assure_block_memory(&self) -> OSStatus {
282 unsafe { CMBlockBufferAssureBlockMemory(self.as_concrete_TypeRef()) }
283 }
284
285 #[inline]
286 pub fn access_data_bytes(&self, offset: size_t, temporary_block: &mut [u8]) -> Result<&mut [u8], OSStatus> {
287 unsafe {
288 let mut returned_pointer: *mut c_void = null_mut();
289 let status = CMBlockBufferAccessDataBytes(
290 self.as_concrete_TypeRef(),
291 offset,
292 temporary_block.len() as size_t,
293 temporary_block.as_mut_ptr() as *mut c_void,
294 &mut returned_pointer,
295 );
296 if status == kCMBlockBufferNoErr {
297 Ok(from_raw_parts_mut(returned_pointer as *mut u8, temporary_block.len()))
298 } else {
299 Err(status)
300 }
301 }
302 }
303
304 #[inline]
305 pub fn copy_data_bytes(&self, offset_to_data: size_t, destination: &mut [u8]) -> Result<(), OSStatus> {
306 unsafe {
307 let status = CMBlockBufferCopyDataBytes(
308 self.as_concrete_TypeRef(),
309 offset_to_data,
310 destination.len() as size_t,
311 destination.as_mut_ptr() as *mut c_void,
312 );
313 if status == kCMBlockBufferNoErr {
314 Ok(())
315 } else {
316 Err(status)
317 }
318 }
319 }
320
321 #[inline]
322 pub fn replace_data_bytes(&self, source_bytes: &[u8], offset_into_destination: size_t) -> Result<(), OSStatus> {
323 unsafe {
324 let status = CMBlockBufferReplaceDataBytes(
325 source_bytes.as_ptr() as *const c_void,
326 self.as_concrete_TypeRef(),
327 offset_into_destination,
328 source_bytes.len() as size_t,
329 );
330 if status == kCMBlockBufferNoErr {
331 Ok(())
332 } else {
333 Err(status)
334 }
335 }
336 }
337
338 #[inline]
339 pub fn fill_data_bytes(&self, fill_byte: u8, offset_into_destination: size_t, data_length: size_t) -> Result<(), OSStatus> {
340 unsafe {
341 let status = CMBlockBufferFillDataBytes(fill_byte, self.as_concrete_TypeRef(), offset_into_destination, data_length);
342 if status == kCMBlockBufferNoErr {
343 Ok(())
344 } else {
345 Err(status)
346 }
347 }
348 }
349
350 #[inline]
351 pub fn get_data(&self, offset: size_t) -> Result<&mut [u8], OSStatus> {
352 unsafe {
353 let mut length_at_offset: size_t = 0;
354 let mut total_length: size_t = 0;
355 let mut data_pointer: *mut c_void = null_mut();
356 let status = CMBlockBufferGetDataPointer(self.as_concrete_TypeRef(), offset, &mut length_at_offset, &mut total_length, &mut data_pointer);
357 if status == kCMBlockBufferNoErr {
358 Ok(from_raw_parts_mut(data_pointer as *mut u8, length_at_offset))
359 } else {
360 Err(status)
361 }
362 }
363 }
364
365 #[inline]
366 pub fn get_data_length(&self) -> size_t {
367 unsafe { CMBlockBufferGetDataLength(self.as_concrete_TypeRef()) }
368 }
369
370 #[inline]
371 pub fn is_range_contiguous(&self, offset: size_t, length: size_t) -> bool {
372 unsafe { CMBlockBufferIsRangeContiguous(self.as_concrete_TypeRef(), offset, length) != 0 }
373 }
374
375 #[inline]
376 pub fn is_empty(&self) -> bool {
377 unsafe { CMBlockBufferIsEmpty(self.as_concrete_TypeRef()) != 0 }
378 }
379}