1use crate::{
2 aa_byte_stream::{ArchiveFlags, ByteStream},
3 aa_entry_blob::{EntryAclBlob, EntryXatBlob},
4 aa_entry_stream::{EntryAttributes, EntryMessage, PathList},
5 aa_field_key::{FieldKey, FieldKeySet},
6 aa_header::Header,
7 ffi, util, CompressionError, Result,
8};
9use std::ffi::{c_char, c_void, CStr};
10use std::ptr::NonNull;
11
12#[allow(dead_code)]
13#[derive(Debug)]
14enum ArchiveStreamUpstream {
15 Byte(Box<ByteStream>),
16 Archive(Box<ArchiveStream>),
17}
18
19#[derive(Debug)]
21pub struct ArchiveStream {
22 handle: NonNull<c_void>,
23 _upstream: Option<ArchiveStreamUpstream>,
24 closed: bool,
25 _message_handler: Option<Box<ArchiveMessageState>>,
26}
27
28impl ArchiveStream {
29 pub fn extract_output(dir: &str, flags: ArchiveFlags, n_threads: i32) -> Result<Self> {
31 let dir = util::cstring("dir", dir)?;
32 let handle = unsafe {
33 ffi::aa_archive_stream::compression_rs_aa_extract_archive_output_stream_open(
34 dir.as_ptr(),
35 flags.bits(),
36 n_threads,
37 )
38 };
39 Ok(Self {
40 handle: util::nonnull_handle(handle, "AAExtractArchiveOutputStreamOpen")?,
41 _upstream: None,
42 closed: false,
43 _message_handler: None,
44 })
45 }
46
47 pub fn encode_output(stream: ByteStream, flags: ArchiveFlags, n_threads: i32) -> Result<Self> {
49 let handle = unsafe {
50 ffi::aa_archive_stream::compression_rs_aa_encode_archive_output_stream_open(
51 stream.as_ptr(),
52 flags.bits(),
53 n_threads,
54 )
55 };
56 Ok(Self {
57 handle: util::nonnull_handle(handle, "AAEncodeArchiveOutputStreamOpen")?,
58 _upstream: Some(ArchiveStreamUpstream::Byte(Box::new(stream))),
59 closed: false,
60 _message_handler: None,
61 })
62 }
63
64 pub fn decode_input(stream: ByteStream, flags: ArchiveFlags, n_threads: i32) -> Result<Self> {
66 let handle = unsafe {
67 ffi::aa_archive_stream::compression_rs_aa_decode_archive_input_stream_open(
68 stream.as_ptr(),
69 flags.bits(),
70 n_threads,
71 )
72 };
73 Ok(Self {
74 handle: util::nonnull_handle(handle, "AADecodeArchiveInputStreamOpen")?,
75 _upstream: Some(ArchiveStreamUpstream::Byte(Box::new(stream))),
76 closed: false,
77 _message_handler: None,
78 })
79 }
80
81 pub fn convert_output(
83 stream: ArchiveStream,
84 insert_key_set: &FieldKeySet,
85 remove_key_set: &FieldKeySet,
86 flags: ArchiveFlags,
87 n_threads: i32,
88 ) -> Result<Self> {
89 let handle = unsafe {
90 ffi::aa_archive_stream::compression_rs_aa_convert_archive_output_stream_open(
91 stream.as_ptr(),
92 insert_key_set.as_ptr(),
93 remove_key_set.as_ptr(),
94 flags.bits(),
95 n_threads,
96 )
97 };
98 Ok(Self {
99 handle: util::nonnull_handle(handle, "AAConvertArchiveOutputStreamOpen")?,
100 _upstream: Some(ArchiveStreamUpstream::Archive(Box::new(stream))),
101 closed: false,
102 _message_handler: None,
103 })
104 }
105
106 pub(crate) fn as_ptr(&self) -> *mut c_void {
107 self.handle.as_ptr()
108 }
109
110 fn ensure_open(&self) -> Result<()> {
111 if self.closed {
112 Err(CompressionError::Closed {
113 resource: "archive stream",
114 })
115 } else {
116 Ok(())
117 }
118 }
119
120 pub fn write_header(&mut self, header: &Header) -> Result<()> {
122 self.ensure_open()?;
123 let status = unsafe {
124 ffi::aa_archive_stream::compression_rs_aa_archive_stream_write_header(
125 self.as_ptr(),
126 header.as_ptr(),
127 )
128 };
129 util::status_result("AAArchiveStreamWriteHeader", status)
130 }
131
132 pub fn write_blob(&mut self, key: FieldKey, buffer: &[u8]) -> Result<()> {
134 self.ensure_open()?;
135 let status = unsafe {
136 ffi::aa_archive_stream::compression_rs_aa_archive_stream_write_blob(
137 self.as_ptr(),
138 key.raw(),
139 buffer.as_ptr(),
140 buffer.len(),
141 )
142 };
143 util::status_result("AAArchiveStreamWriteBlob", status)
144 }
145
146 pub fn read_header(&mut self) -> Result<Option<Header>> {
148 self.ensure_open()?;
149 let mut status = 0_i32;
150 let handle = unsafe {
151 ffi::aa_archive_stream::compression_rs_aa_archive_stream_read_header_new(
152 self.as_ptr(),
153 &mut status,
154 )
155 };
156 match status {
157 1 => Ok(Some(Header::from_handle(
158 handle,
159 "AAArchiveStreamReadHeader",
160 )?)),
161 0 => Ok(None),
162 code => Err(CompressionError::OperationFailed {
163 operation: "AAArchiveStreamReadHeader",
164 code,
165 }),
166 }
167 }
168
169 pub fn read_header_into(&mut self, header: &mut Header) -> Result<bool> {
171 self.ensure_open()?;
172 match unsafe {
173 ffi::aa_archive_stream::compression_rs_aa_archive_stream_read_header_into(
174 self.as_ptr(),
175 header.as_ptr(),
176 )
177 } {
178 1 => Ok(true),
179 0 => Ok(false),
180 code => Err(CompressionError::OperationFailed {
181 operation: "AAArchiveStreamReadHeader",
182 code,
183 }),
184 }
185 }
186
187 pub fn read_blob(&mut self, key: FieldKey, buffer: &mut [u8]) -> Result<()> {
189 self.ensure_open()?;
190 let status = unsafe {
191 ffi::aa_archive_stream::compression_rs_aa_archive_stream_read_blob(
192 self.as_ptr(),
193 key.raw(),
194 buffer.as_mut_ptr(),
195 buffer.len(),
196 )
197 };
198 util::status_result("AAArchiveStreamReadBlob", status)
199 }
200
201 pub fn write_path_list(
203 &mut self,
204 path_list: &PathList,
205 key_set: &FieldKeySet,
206 dir: &str,
207 flags: ArchiveFlags,
208 n_threads: i32,
209 ) -> Result<()> {
210 self.ensure_open()?;
211 let dir = util::cstring("dir", dir)?;
212 let status = unsafe {
213 ffi::aa_archive_stream::compression_rs_aa_archive_stream_write_path_list(
214 self.as_ptr(),
215 path_list.as_ptr(),
216 key_set.as_ptr(),
217 dir.as_ptr(),
218 flags.bits(),
219 n_threads,
220 )
221 };
222 util::status_result("AAArchiveStreamWritePathList", status)
223 }
224
225 pub fn process_into(
227 &mut self,
228 output: &mut Self,
229 flags: ArchiveFlags,
230 n_threads: i32,
231 ) -> Result<u64> {
232 self.ensure_open()?;
233 output.ensure_open()?;
234 util::off_t_result("AAArchiveStreamProcess", unsafe {
235 ffi::aa_archive_stream::compression_rs_aa_archive_stream_process(
236 self.as_ptr(),
237 output.as_ptr(),
238 flags.bits(),
239 n_threads,
240 )
241 })
242 }
243
244 pub fn cancel(&mut self) -> Result<()> {
246 self.ensure_open()?;
247 unsafe { ffi::aa_archive_stream::compression_rs_aa_archive_stream_cancel(self.as_ptr()) };
248 Ok(())
249 }
250
251 #[deprecated(
252 since = "0.2.2",
253 note = "Use ArchiveStream::cancel; AAArchiveStreamAbort is a deprecated AppleArchive compatibility shim."
254 )]
255 pub fn abort(&mut self) -> Result<()> {
257 self.ensure_open()?;
258 unsafe { ffi::aa_archive_stream::compression_rs_aa_archive_stream_abort(self.as_ptr()) };
259 Ok(())
260 }
261
262 pub fn close(&mut self) -> Result<()> {
264 if self.closed {
265 return Ok(());
266 }
267 let status = unsafe {
268 ffi::aa_archive_stream::compression_rs_aa_archive_stream_close(self.as_ptr())
269 };
270 self.closed = true;
271 util::status_result("AAArchiveStreamClose", status)
272 }
273}
274
275impl Drop for ArchiveStream {
276 fn drop(&mut self) {
277 unsafe { ffi::aa_archive_stream::compression_rs_aa_archive_stream_release(self.as_ptr()) };
278 }
279}
280
281fn custom_archive_stream_error(operation: &'static str) -> CompressionError {
282 CompressionError::OperationFailed {
283 operation,
284 code: -1,
285 }
286}
287
288fn custom_archive_stream_code(error: &CompressionError) -> i32 {
289 match error {
290 CompressionError::OperationFailed { code, .. } if *code < 0 => *code,
291 _ => -1,
292 }
293}
294
295struct CustomArchiveStreamState {
296 callbacks: Box<dyn CustomArchiveStreamCallbacks>,
297}
298
299pub trait CustomArchiveStreamCallbacks {
301 fn write_header(&mut self, _header: &Header) -> Result<()> {
303 Err(custom_archive_stream_error("AAArchiveStreamWriteHeader"))
304 }
305
306 fn write_blob(&mut self, _key: FieldKey, _buffer: &[u8]) -> Result<()> {
308 Err(custom_archive_stream_error("AAArchiveStreamWriteBlob"))
309 }
310
311 fn read_header(&mut self) -> Result<Option<Header>> {
313 Err(custom_archive_stream_error("AAArchiveStreamReadHeader"))
314 }
315
316 fn read_blob(&mut self, _key: FieldKey, _buffer: &mut [u8]) -> Result<()> {
318 Err(custom_archive_stream_error("AAArchiveStreamReadBlob"))
319 }
320
321 fn cancel(&mut self) {}
323
324 fn close(&mut self) -> Result<()> {
326 Ok(())
327 }
328}
329
330unsafe fn custom_archive_stream_state(
331 arg: *mut c_void,
332) -> Option<&'static mut CustomArchiveStreamState> {
333 if arg.is_null() {
334 None
335 } else {
336 Some(unsafe { &mut *arg.cast::<CustomArchiveStreamState>() })
337 }
338}
339
340unsafe fn custom_archive_stream_slice<'a>(
341 buffer: *const c_void,
342 length: usize,
343) -> Option<&'a [u8]> {
344 if length == 0 {
345 Some(&[])
346 } else if buffer.is_null() {
347 None
348 } else {
349 Some(unsafe { std::slice::from_raw_parts(buffer.cast::<u8>(), length) })
350 }
351}
352
353unsafe fn custom_archive_stream_slice_mut<'a>(
354 buffer: *mut c_void,
355 length: usize,
356) -> Option<&'a mut [u8]> {
357 if length == 0 {
358 Some(&mut [])
359 } else if buffer.is_null() {
360 None
361 } else {
362 Some(unsafe { std::slice::from_raw_parts_mut(buffer.cast::<u8>(), length) })
363 }
364}
365
366fn guard_archive_status(f: impl FnOnce() -> i32) -> i32 {
369 std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)).unwrap_or(-1)
370}
371
372unsafe extern "C" fn custom_archive_stream_write_header(
373 arg: *mut c_void,
374 header: *mut c_void,
375) -> i32 {
376 let Some(state) = (unsafe { custom_archive_stream_state(arg) }) else {
377 return -1;
378 };
379 if header.is_null() {
380 return -1;
381 }
382 match Header::from_raw_clone(header, "AAHeaderClone") {
383 Ok(header) => guard_archive_status(|| match state.callbacks.write_header(&header) {
384 Ok(()) => 0,
385 Err(error) => custom_archive_stream_code(&error),
386 }),
387 Err(error) => custom_archive_stream_code(&error),
388 }
389}
390
391unsafe extern "C" fn custom_archive_stream_write_blob(
392 arg: *mut c_void,
393 key: u32,
394 buffer: *const c_void,
395 length: usize,
396) -> i32 {
397 let Some(state) = (unsafe { custom_archive_stream_state(arg) }) else {
398 return -1;
399 };
400 let Some(buffer) = (unsafe { custom_archive_stream_slice(buffer, length) }) else {
401 return -1;
402 };
403 guard_archive_status(|| match state.callbacks.write_blob(FieldKey::from_raw(key), buffer) {
404 Ok(()) => 0,
405 Err(error) => custom_archive_stream_code(&error),
406 })
407}
408
409unsafe extern "C" fn custom_archive_stream_read_header(
410 arg: *mut c_void,
411 header_out: *mut *mut c_void,
412) -> i32 {
413 let Some(state) = (unsafe { custom_archive_stream_state(arg) }) else {
414 return -1;
415 };
416 let Ok(header) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
417 state.callbacks.read_header()
418 })) else {
419 return -1;
420 };
421 match header {
422 Ok(Some(header)) => {
423 if header_out.is_null() {
424 return -1;
425 }
426 let raw = match header.clone_raw() {
427 Ok(raw) => raw,
428 Err(error) => return custom_archive_stream_code(&error),
429 };
430 unsafe { *header_out = raw };
431 1
432 }
433 Ok(None) => 0,
434 Err(error) => custom_archive_stream_code(&error),
435 }
436}
437
438unsafe extern "C" fn custom_archive_stream_read_blob(
439 arg: *mut c_void,
440 key: u32,
441 buffer: *mut c_void,
442 length: usize,
443) -> i32 {
444 let Some(state) = (unsafe { custom_archive_stream_state(arg) }) else {
445 return -1;
446 };
447 let Some(buffer) = (unsafe { custom_archive_stream_slice_mut(buffer, length) }) else {
448 return -1;
449 };
450 guard_archive_status(|| match state.callbacks.read_blob(FieldKey::from_raw(key), buffer) {
451 Ok(()) => 0,
452 Err(error) => custom_archive_stream_code(&error),
453 })
454}
455
456unsafe extern "C" fn custom_archive_stream_cancel(arg: *mut c_void) {
457 if let Some(state) = unsafe { custom_archive_stream_state(arg) } {
458 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| state.callbacks.cancel()));
459 }
460}
461
462unsafe extern "C" fn custom_archive_stream_close(arg: *mut c_void) -> i32 {
463 if arg.is_null() {
464 return 0;
465 }
466 let mut state = unsafe { Box::from_raw(arg.cast::<CustomArchiveStreamState>()) };
467 guard_archive_status(|| match state.callbacks.close() {
468 Ok(()) => 0,
469 Err(error) => custom_archive_stream_code(&error),
470 })
471}
472
473impl ArchiveStream {
474 pub fn custom<T: CustomArchiveStreamCallbacks + 'static>(callbacks: T) -> Result<Self> {
476 let handle =
477 unsafe { ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_open() };
478 let stream = Self {
479 handle: util::nonnull_handle(handle, "AACustomArchiveStreamOpen")?,
480 _upstream: None,
481 closed: false,
482 _message_handler: None,
483 };
484 let state = Box::new(CustomArchiveStreamState {
485 callbacks: Box::new(callbacks),
486 });
487 let data = Box::into_raw(state).cast::<c_void>();
488 unsafe {
489 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_data(
490 stream.as_ptr(),
491 data,
492 );
493 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_write_header_proc(
494 stream.as_ptr(),
495 Some(custom_archive_stream_write_header),
496 );
497 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_write_blob_proc(
498 stream.as_ptr(),
499 Some(custom_archive_stream_write_blob),
500 );
501 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_read_header_proc(
502 stream.as_ptr(),
503 Some(custom_archive_stream_read_header),
504 );
505 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_read_blob_proc(
506 stream.as_ptr(),
507 Some(custom_archive_stream_read_blob),
508 );
509 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_cancel_proc(
510 stream.as_ptr(),
511 Some(custom_archive_stream_cancel),
512 );
513 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_abort_proc(
514 stream.as_ptr(),
515 Some(custom_archive_stream_cancel),
516 );
517 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_close_proc(
518 stream.as_ptr(),
519 Some(custom_archive_stream_close),
520 );
521 }
522 Ok(stream)
523 }
524}
525
526pub enum EntryMessageData {
528 None,
530 Header(Header),
532 EntryIds {
534 idx: u64,
536 idz: u64,
538 },
539 Progress {
541 total: u64,
543 current: u64,
545 },
546 Attributes(EntryAttributes),
548 Xat(EntryXatBlob),
550 Acl(EntryAclBlob),
552}
553
554impl std::fmt::Debug for EntryMessageData {
555 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
556 match self {
557 Self::None => f.write_str("None"),
558 Self::Header(_) => f.write_str("Header(..)"),
559 Self::EntryIds { idx, idz } => f
560 .debug_struct("EntryIds")
561 .field("idx", idx)
562 .field("idz", idz)
563 .finish(),
564 Self::Progress { total, current } => f
565 .debug_struct("Progress")
566 .field("total", total)
567 .field("current", current)
568 .finish(),
569 Self::Attributes(attributes) => f.debug_tuple("Attributes").field(attributes).finish(),
570 Self::Xat(_) => f.write_str("Xat(..)"),
571 Self::Acl(_) => f.write_str("Acl(..)"),
572 }
573 }
574}
575
576#[derive(Debug)]
578pub struct EntryMessageEvent {
579 pub message: EntryMessage,
581 pub path: String,
583 pub data: EntryMessageData,
585}
586
587pub trait EntryMessageHandler {
589 fn handle(&mut self, event: &mut EntryMessageEvent) -> Result<i32>;
591}
592
593impl<F> EntryMessageHandler for F
594where
595 F: FnMut(&mut EntryMessageEvent) -> Result<i32>,
596{
597 fn handle(&mut self, event: &mut EntryMessageEvent) -> Result<i32> {
598 self(event)
599 }
600}
601
602struct ArchiveMessageState {
603 handler: Box<dyn EntryMessageHandler>,
604}
605
606impl std::fmt::Debug for ArchiveMessageState {
607 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
608 f.write_str("ArchiveMessageState(..)")
609 }
610}
611
612fn archive_message_code(error: &CompressionError) -> i32 {
613 match error {
614 CompressionError::OperationFailed { code, .. } if *code < 0 => *code,
615 _ => -1,
616 }
617}
618
619unsafe fn archive_message_state(arg: *mut c_void) -> Option<&'static mut ArchiveMessageState> {
620 if arg.is_null() {
621 None
622 } else {
623 Some(unsafe { &mut *arg.cast::<ArchiveMessageState>() })
624 }
625}
626
627unsafe fn archive_message_pair(data: *mut c_void) -> Option<(u64, u64)> {
628 if data.is_null() {
629 None
630 } else {
631 let values = unsafe { std::slice::from_raw_parts(data.cast::<u64>(), 2) };
632 Some((values[0], values[1]))
633 }
634}
635
636fn archive_message_data(message: EntryMessage, data: *mut c_void) -> Result<EntryMessageData> {
637 match message {
638 EntryMessage::SearchPruneDir
639 | EntryMessage::SearchExclude
640 | EntryMessage::SearchFail
641 | EntryMessage::EncodeScanning => Ok(EntryMessageData::None),
642 EntryMessage::ExtractBegin
643 | EntryMessage::ConvertExclude
644 | EntryMessage::ProcessExclude => {
645 if data.is_null() {
646 Ok(EntryMessageData::None)
647 } else {
648 Ok(EntryMessageData::Header(Header::from_raw_clone(
649 data,
650 "AAHeaderClone",
651 )?))
652 }
653 }
654 EntryMessage::ExtractEnd | EntryMessage::ExtractFail => {
655 if let Some((idx, idz)) = unsafe { archive_message_pair(data) } {
656 Ok(EntryMessageData::EntryIds { idx, idz })
657 } else {
658 Ok(EntryMessageData::None)
659 }
660 }
661 EntryMessage::EncodeWriting | EntryMessage::DecodeReading => {
662 if let Some((total, current)) = unsafe { archive_message_pair(data) } {
663 Ok(EntryMessageData::Progress { total, current })
664 } else {
665 Ok(EntryMessageData::None)
666 }
667 }
668 EntryMessage::ExtractAttributes => {
669 if data.is_null() {
670 Ok(EntryMessageData::None)
671 } else {
672 Ok(EntryMessageData::Attributes(unsafe {
673 *data.cast::<EntryAttributes>()
674 }))
675 }
676 }
677 EntryMessage::ExtractXat => {
678 if data.is_null() {
679 Ok(EntryMessageData::None)
680 } else {
681 Ok(EntryMessageData::Xat(EntryXatBlob::clone_from_raw(data)?))
682 }
683 }
684 EntryMessage::ExtractAcl => {
685 if data.is_null() {
686 Ok(EntryMessageData::None)
687 } else {
688 Ok(EntryMessageData::Acl(EntryAclBlob::clone_from_raw(data)?))
689 }
690 }
691 }
692}
693
694fn archive_message_sync(
695 message: EntryMessage,
696 data_ptr: *mut c_void,
697 data: &EntryMessageData,
698) -> Result<()> {
699 match (message, data) {
700 (EntryMessage::ExtractAttributes, EntryMessageData::Attributes(attributes)) => {
701 if !data_ptr.is_null() {
702 unsafe { *data_ptr.cast::<EntryAttributes>() = *attributes };
703 }
704 Ok(())
705 }
706 (EntryMessage::ExtractXat, EntryMessageData::Xat(xat)) => {
707 if data_ptr.is_null() {
708 Ok(())
709 } else {
710 EntryXatBlob::sync_into_raw(data_ptr, xat)
711 }
712 }
713 (EntryMessage::ExtractAcl, EntryMessageData::Acl(acl)) => {
714 if data_ptr.is_null() {
715 Ok(())
716 } else {
717 EntryAclBlob::sync_into_raw(data_ptr, acl)
718 }
719 }
720 _ => Ok(()),
721 }
722}
723
724unsafe extern "C" fn archive_entry_message_proc(
725 arg: *mut c_void,
726 message_raw: u32,
727 path: *const c_char,
728 data: *mut c_void,
729) -> i32 {
730 let Some(state) = (unsafe { archive_message_state(arg) }) else {
731 return -1;
732 };
733 let Some(message) = EntryMessage::from_raw(message_raw) else {
734 return -1;
735 };
736 if path.is_null() {
737 return -1;
738 }
739 let mut event = match archive_message_data(message, data) {
740 Ok(event_data) => EntryMessageEvent {
741 message,
742 path: unsafe { CStr::from_ptr(path) }
743 .to_string_lossy()
744 .into_owned(),
745 data: event_data,
746 },
747 Err(error) => return archive_message_code(&error),
748 };
749 match state.handler.handle(&mut event) {
750 Ok(code) => match archive_message_sync(message, data, &event.data) {
751 Ok(()) => code,
752 Err(error) => archive_message_code(&error),
753 },
754 Err(error) => archive_message_code(&error),
755 }
756}
757
758impl ArchiveStream {
759 pub fn extract_output_with_messages<T: EntryMessageHandler + 'static>(
761 dir: &str,
762 flags: ArchiveFlags,
763 n_threads: i32,
764 handler: T,
765 ) -> Result<Self> {
766 let dir = util::cstring("dir", dir)?;
767 let mut message_handler = Box::new(ArchiveMessageState {
768 handler: Box::new(handler),
769 });
770 let handle = unsafe {
771 ffi::aa_archive_stream::compression_rs_aa_extract_archive_output_stream_open_with_messages(
772 dir.as_ptr(),
773 flags.bits(),
774 n_threads,
775 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
776 Some(archive_entry_message_proc),
777 )
778 };
779 Ok(Self {
780 handle: util::nonnull_handle(handle, "AAExtractArchiveOutputStreamOpen")?,
781 _upstream: None,
782 closed: false,
783 _message_handler: Some(message_handler),
784 })
785 }
786
787 pub fn encode_output_with_messages<T: EntryMessageHandler + 'static>(
789 stream: ByteStream,
790 flags: ArchiveFlags,
791 n_threads: i32,
792 handler: T,
793 ) -> Result<Self> {
794 let mut message_handler = Box::new(ArchiveMessageState {
795 handler: Box::new(handler),
796 });
797 let handle = unsafe {
798 ffi::aa_archive_stream::compression_rs_aa_encode_archive_output_stream_open_with_messages(
799 stream.as_ptr(),
800 flags.bits(),
801 n_threads,
802 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
803 Some(archive_entry_message_proc),
804 )
805 };
806 Ok(Self {
807 handle: util::nonnull_handle(handle, "AAEncodeArchiveOutputStreamOpen")?,
808 _upstream: Some(ArchiveStreamUpstream::Byte(Box::new(stream))),
809 closed: false,
810 _message_handler: Some(message_handler),
811 })
812 }
813
814 pub fn decode_input_with_messages<T: EntryMessageHandler + 'static>(
816 stream: ByteStream,
817 flags: ArchiveFlags,
818 n_threads: i32,
819 handler: T,
820 ) -> Result<Self> {
821 let mut message_handler = Box::new(ArchiveMessageState {
822 handler: Box::new(handler),
823 });
824 let handle = unsafe {
825 ffi::aa_archive_stream::compression_rs_aa_decode_archive_input_stream_open_with_messages(
826 stream.as_ptr(),
827 flags.bits(),
828 n_threads,
829 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
830 Some(archive_entry_message_proc),
831 )
832 };
833 Ok(Self {
834 handle: util::nonnull_handle(handle, "AADecodeArchiveInputStreamOpen")?,
835 _upstream: Some(ArchiveStreamUpstream::Byte(Box::new(stream))),
836 closed: false,
837 _message_handler: Some(message_handler),
838 })
839 }
840
841 pub fn convert_output_with_messages<T: EntryMessageHandler + 'static>(
843 stream: ArchiveStream,
844 insert_key_set: &FieldKeySet,
845 remove_key_set: &FieldKeySet,
846 flags: ArchiveFlags,
847 n_threads: i32,
848 handler: T,
849 ) -> Result<Self> {
850 let mut message_handler = Box::new(ArchiveMessageState {
851 handler: Box::new(handler),
852 });
853 let handle = unsafe {
854 ffi::aa_archive_stream::compression_rs_aa_convert_archive_output_stream_open_with_messages(
855 stream.as_ptr(),
856 insert_key_set.as_ptr(),
857 remove_key_set.as_ptr(),
858 flags.bits(),
859 n_threads,
860 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
861 Some(archive_entry_message_proc),
862 )
863 };
864 Ok(Self {
865 handle: util::nonnull_handle(handle, "AAConvertArchiveOutputStreamOpen")?,
866 _upstream: Some(ArchiveStreamUpstream::Archive(Box::new(stream))),
867 closed: false,
868 _message_handler: Some(message_handler),
869 })
870 }
871
872 pub fn write_path_list_with_messages<T: EntryMessageHandler + 'static>(
874 &mut self,
875 path_list: &PathList,
876 key_set: &FieldKeySet,
877 dir: &str,
878 flags: ArchiveFlags,
879 n_threads: i32,
880 handler: T,
881 ) -> Result<()> {
882 self.ensure_open()?;
883 let dir = util::cstring("dir", dir)?;
884 let mut message_handler = Box::new(ArchiveMessageState {
885 handler: Box::new(handler),
886 });
887 let status = unsafe {
888 ffi::aa_archive_stream::compression_rs_aa_archive_stream_write_path_list_with_messages(
889 self.as_ptr(),
890 path_list.as_ptr(),
891 key_set.as_ptr(),
892 dir.as_ptr(),
893 flags.bits(),
894 n_threads,
895 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
896 Some(archive_entry_message_proc),
897 )
898 };
899 util::status_result("AAArchiveStreamWritePathList", status)
900 }
901
902 pub fn process_into_with_messages<T: EntryMessageHandler + 'static>(
904 &mut self,
905 output: &mut Self,
906 flags: ArchiveFlags,
907 n_threads: i32,
908 handler: T,
909 ) -> Result<u64> {
910 self.ensure_open()?;
911 output.ensure_open()?;
912 let mut message_handler = Box::new(ArchiveMessageState {
913 handler: Box::new(handler),
914 });
915 util::off_t_result("AAArchiveStreamProcess", unsafe {
916 ffi::aa_archive_stream::compression_rs_aa_archive_stream_process_with_messages(
917 self.as_ptr(),
918 output.as_ptr(),
919 flags.bits(),
920 n_threads,
921 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
922 Some(archive_entry_message_proc),
923 )
924 })
925 }
926}