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
366unsafe extern "C" fn custom_archive_stream_write_header(
367 arg: *mut c_void,
368 header: *mut c_void,
369) -> i32 {
370 let Some(state) = (unsafe { custom_archive_stream_state(arg) }) else {
371 return -1;
372 };
373 if header.is_null() {
374 return -1;
375 }
376 let header = match Header::from_raw_clone(header, "AAHeaderClone") {
377 Ok(header) => header,
378 Err(error) => return custom_archive_stream_code(&error),
379 };
380 match state.callbacks.write_header(&header) {
381 Ok(()) => 0,
382 Err(error) => custom_archive_stream_code(&error),
383 }
384}
385
386unsafe extern "C" fn custom_archive_stream_write_blob(
387 arg: *mut c_void,
388 key: u32,
389 buffer: *const c_void,
390 length: usize,
391) -> i32 {
392 let Some(state) = (unsafe { custom_archive_stream_state(arg) }) else {
393 return -1;
394 };
395 let Some(buffer) = (unsafe { custom_archive_stream_slice(buffer, length) }) else {
396 return -1;
397 };
398 match state.callbacks.write_blob(FieldKey::from_raw(key), buffer) {
399 Ok(()) => 0,
400 Err(error) => custom_archive_stream_code(&error),
401 }
402}
403
404unsafe extern "C" fn custom_archive_stream_read_header(
405 arg: *mut c_void,
406 header_out: *mut *mut c_void,
407) -> i32 {
408 let Some(state) = (unsafe { custom_archive_stream_state(arg) }) else {
409 return -1;
410 };
411 match state.callbacks.read_header() {
412 Ok(Some(header)) => {
413 if header_out.is_null() {
414 return -1;
415 }
416 let raw = match header.clone_raw() {
417 Ok(raw) => raw,
418 Err(error) => return custom_archive_stream_code(&error),
419 };
420 unsafe { *header_out = raw };
421 1
422 }
423 Ok(None) => 0,
424 Err(error) => custom_archive_stream_code(&error),
425 }
426}
427
428unsafe extern "C" fn custom_archive_stream_read_blob(
429 arg: *mut c_void,
430 key: u32,
431 buffer: *mut c_void,
432 length: usize,
433) -> i32 {
434 let Some(state) = (unsafe { custom_archive_stream_state(arg) }) else {
435 return -1;
436 };
437 let Some(buffer) = (unsafe { custom_archive_stream_slice_mut(buffer, length) }) else {
438 return -1;
439 };
440 match state.callbacks.read_blob(FieldKey::from_raw(key), buffer) {
441 Ok(()) => 0,
442 Err(error) => custom_archive_stream_code(&error),
443 }
444}
445
446unsafe extern "C" fn custom_archive_stream_cancel(arg: *mut c_void) {
447 if let Some(state) = unsafe { custom_archive_stream_state(arg) } {
448 state.callbacks.cancel();
449 }
450}
451
452unsafe extern "C" fn custom_archive_stream_close(arg: *mut c_void) -> i32 {
453 if arg.is_null() {
454 return 0;
455 }
456 let mut state = unsafe { Box::from_raw(arg.cast::<CustomArchiveStreamState>()) };
457 match state.callbacks.close() {
458 Ok(()) => 0,
459 Err(error) => custom_archive_stream_code(&error),
460 }
461}
462
463impl ArchiveStream {
464 pub fn custom<T: CustomArchiveStreamCallbacks + 'static>(callbacks: T) -> Result<Self> {
466 let handle =
467 unsafe { ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_open() };
468 let stream = Self {
469 handle: util::nonnull_handle(handle, "AACustomArchiveStreamOpen")?,
470 _upstream: None,
471 closed: false,
472 _message_handler: None,
473 };
474 let state = Box::new(CustomArchiveStreamState {
475 callbacks: Box::new(callbacks),
476 });
477 let data = Box::into_raw(state).cast::<c_void>();
478 unsafe {
479 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_data(
480 stream.as_ptr(),
481 data,
482 );
483 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_write_header_proc(
484 stream.as_ptr(),
485 Some(custom_archive_stream_write_header),
486 );
487 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_write_blob_proc(
488 stream.as_ptr(),
489 Some(custom_archive_stream_write_blob),
490 );
491 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_read_header_proc(
492 stream.as_ptr(),
493 Some(custom_archive_stream_read_header),
494 );
495 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_read_blob_proc(
496 stream.as_ptr(),
497 Some(custom_archive_stream_read_blob),
498 );
499 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_cancel_proc(
500 stream.as_ptr(),
501 Some(custom_archive_stream_cancel),
502 );
503 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_abort_proc(
504 stream.as_ptr(),
505 Some(custom_archive_stream_cancel),
506 );
507 ffi::aa_archive_stream::compression_rs_aa_custom_archive_stream_set_close_proc(
508 stream.as_ptr(),
509 Some(custom_archive_stream_close),
510 );
511 }
512 Ok(stream)
513 }
514}
515
516pub enum EntryMessageData {
518 None,
520 Header(Header),
522 EntryIds {
524 idx: u64,
526 idz: u64,
528 },
529 Progress {
531 total: u64,
533 current: u64,
535 },
536 Attributes(EntryAttributes),
538 Xat(EntryXatBlob),
540 Acl(EntryAclBlob),
542}
543
544impl std::fmt::Debug for EntryMessageData {
545 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
546 match self {
547 Self::None => f.write_str("None"),
548 Self::Header(_) => f.write_str("Header(..)"),
549 Self::EntryIds { idx, idz } => f
550 .debug_struct("EntryIds")
551 .field("idx", idx)
552 .field("idz", idz)
553 .finish(),
554 Self::Progress { total, current } => f
555 .debug_struct("Progress")
556 .field("total", total)
557 .field("current", current)
558 .finish(),
559 Self::Attributes(attributes) => f.debug_tuple("Attributes").field(attributes).finish(),
560 Self::Xat(_) => f.write_str("Xat(..)"),
561 Self::Acl(_) => f.write_str("Acl(..)"),
562 }
563 }
564}
565
566#[derive(Debug)]
568pub struct EntryMessageEvent {
569 pub message: EntryMessage,
571 pub path: String,
573 pub data: EntryMessageData,
575}
576
577pub trait EntryMessageHandler {
579 fn handle(&mut self, event: &mut EntryMessageEvent) -> Result<i32>;
581}
582
583impl<F> EntryMessageHandler for F
584where
585 F: FnMut(&mut EntryMessageEvent) -> Result<i32>,
586{
587 fn handle(&mut self, event: &mut EntryMessageEvent) -> Result<i32> {
588 self(event)
589 }
590}
591
592struct ArchiveMessageState {
593 handler: Box<dyn EntryMessageHandler>,
594}
595
596impl std::fmt::Debug for ArchiveMessageState {
597 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
598 f.write_str("ArchiveMessageState(..)")
599 }
600}
601
602fn archive_message_code(error: &CompressionError) -> i32 {
603 match error {
604 CompressionError::OperationFailed { code, .. } if *code < 0 => *code,
605 _ => -1,
606 }
607}
608
609unsafe fn archive_message_state(arg: *mut c_void) -> Option<&'static mut ArchiveMessageState> {
610 if arg.is_null() {
611 None
612 } else {
613 Some(unsafe { &mut *arg.cast::<ArchiveMessageState>() })
614 }
615}
616
617unsafe fn archive_message_pair(data: *mut c_void) -> Option<(u64, u64)> {
618 if data.is_null() {
619 None
620 } else {
621 let values = unsafe { std::slice::from_raw_parts(data.cast::<u64>(), 2) };
622 Some((values[0], values[1]))
623 }
624}
625
626fn archive_message_data(message: EntryMessage, data: *mut c_void) -> Result<EntryMessageData> {
627 match message {
628 EntryMessage::SearchPruneDir
629 | EntryMessage::SearchExclude
630 | EntryMessage::SearchFail
631 | EntryMessage::EncodeScanning => Ok(EntryMessageData::None),
632 EntryMessage::ExtractBegin
633 | EntryMessage::ConvertExclude
634 | EntryMessage::ProcessExclude => {
635 if data.is_null() {
636 Ok(EntryMessageData::None)
637 } else {
638 Ok(EntryMessageData::Header(Header::from_raw_clone(
639 data,
640 "AAHeaderClone",
641 )?))
642 }
643 }
644 EntryMessage::ExtractEnd | EntryMessage::ExtractFail => {
645 if let Some((idx, idz)) = unsafe { archive_message_pair(data) } {
646 Ok(EntryMessageData::EntryIds { idx, idz })
647 } else {
648 Ok(EntryMessageData::None)
649 }
650 }
651 EntryMessage::EncodeWriting | EntryMessage::DecodeReading => {
652 if let Some((total, current)) = unsafe { archive_message_pair(data) } {
653 Ok(EntryMessageData::Progress { total, current })
654 } else {
655 Ok(EntryMessageData::None)
656 }
657 }
658 EntryMessage::ExtractAttributes => {
659 if data.is_null() {
660 Ok(EntryMessageData::None)
661 } else {
662 Ok(EntryMessageData::Attributes(unsafe {
663 *data.cast::<EntryAttributes>()
664 }))
665 }
666 }
667 EntryMessage::ExtractXat => {
668 if data.is_null() {
669 Ok(EntryMessageData::None)
670 } else {
671 Ok(EntryMessageData::Xat(EntryXatBlob::clone_from_raw(data)?))
672 }
673 }
674 EntryMessage::ExtractAcl => {
675 if data.is_null() {
676 Ok(EntryMessageData::None)
677 } else {
678 Ok(EntryMessageData::Acl(EntryAclBlob::clone_from_raw(data)?))
679 }
680 }
681 }
682}
683
684fn archive_message_sync(
685 message: EntryMessage,
686 data_ptr: *mut c_void,
687 data: &EntryMessageData,
688) -> Result<()> {
689 match (message, data) {
690 (EntryMessage::ExtractAttributes, EntryMessageData::Attributes(attributes)) => {
691 if !data_ptr.is_null() {
692 unsafe { *data_ptr.cast::<EntryAttributes>() = *attributes };
693 }
694 Ok(())
695 }
696 (EntryMessage::ExtractXat, EntryMessageData::Xat(xat)) => {
697 if data_ptr.is_null() {
698 Ok(())
699 } else {
700 EntryXatBlob::sync_into_raw(data_ptr, xat)
701 }
702 }
703 (EntryMessage::ExtractAcl, EntryMessageData::Acl(acl)) => {
704 if data_ptr.is_null() {
705 Ok(())
706 } else {
707 EntryAclBlob::sync_into_raw(data_ptr, acl)
708 }
709 }
710 _ => Ok(()),
711 }
712}
713
714unsafe extern "C" fn archive_entry_message_proc(
715 arg: *mut c_void,
716 message_raw: u32,
717 path: *const c_char,
718 data: *mut c_void,
719) -> i32 {
720 let Some(state) = (unsafe { archive_message_state(arg) }) else {
721 return -1;
722 };
723 let Some(message) = EntryMessage::from_raw(message_raw) else {
724 return -1;
725 };
726 if path.is_null() {
727 return -1;
728 }
729 let mut event = match archive_message_data(message, data) {
730 Ok(event_data) => EntryMessageEvent {
731 message,
732 path: unsafe { CStr::from_ptr(path) }
733 .to_string_lossy()
734 .into_owned(),
735 data: event_data,
736 },
737 Err(error) => return archive_message_code(&error),
738 };
739 match state.handler.handle(&mut event) {
740 Ok(code) => match archive_message_sync(message, data, &event.data) {
741 Ok(()) => code,
742 Err(error) => archive_message_code(&error),
743 },
744 Err(error) => archive_message_code(&error),
745 }
746}
747
748impl ArchiveStream {
749 pub fn extract_output_with_messages<T: EntryMessageHandler + 'static>(
751 dir: &str,
752 flags: ArchiveFlags,
753 n_threads: i32,
754 handler: T,
755 ) -> Result<Self> {
756 let dir = util::cstring("dir", dir)?;
757 let mut message_handler = Box::new(ArchiveMessageState {
758 handler: Box::new(handler),
759 });
760 let handle = unsafe {
761 ffi::aa_archive_stream::compression_rs_aa_extract_archive_output_stream_open_with_messages(
762 dir.as_ptr(),
763 flags.bits(),
764 n_threads,
765 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
766 Some(archive_entry_message_proc),
767 )
768 };
769 Ok(Self {
770 handle: util::nonnull_handle(handle, "AAExtractArchiveOutputStreamOpen")?,
771 _upstream: None,
772 closed: false,
773 _message_handler: Some(message_handler),
774 })
775 }
776
777 pub fn encode_output_with_messages<T: EntryMessageHandler + 'static>(
779 stream: ByteStream,
780 flags: ArchiveFlags,
781 n_threads: i32,
782 handler: T,
783 ) -> Result<Self> {
784 let mut message_handler = Box::new(ArchiveMessageState {
785 handler: Box::new(handler),
786 });
787 let handle = unsafe {
788 ffi::aa_archive_stream::compression_rs_aa_encode_archive_output_stream_open_with_messages(
789 stream.as_ptr(),
790 flags.bits(),
791 n_threads,
792 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
793 Some(archive_entry_message_proc),
794 )
795 };
796 Ok(Self {
797 handle: util::nonnull_handle(handle, "AAEncodeArchiveOutputStreamOpen")?,
798 _upstream: Some(ArchiveStreamUpstream::Byte(Box::new(stream))),
799 closed: false,
800 _message_handler: Some(message_handler),
801 })
802 }
803
804 pub fn decode_input_with_messages<T: EntryMessageHandler + 'static>(
806 stream: ByteStream,
807 flags: ArchiveFlags,
808 n_threads: i32,
809 handler: T,
810 ) -> Result<Self> {
811 let mut message_handler = Box::new(ArchiveMessageState {
812 handler: Box::new(handler),
813 });
814 let handle = unsafe {
815 ffi::aa_archive_stream::compression_rs_aa_decode_archive_input_stream_open_with_messages(
816 stream.as_ptr(),
817 flags.bits(),
818 n_threads,
819 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
820 Some(archive_entry_message_proc),
821 )
822 };
823 Ok(Self {
824 handle: util::nonnull_handle(handle, "AADecodeArchiveInputStreamOpen")?,
825 _upstream: Some(ArchiveStreamUpstream::Byte(Box::new(stream))),
826 closed: false,
827 _message_handler: Some(message_handler),
828 })
829 }
830
831 pub fn convert_output_with_messages<T: EntryMessageHandler + 'static>(
833 stream: ArchiveStream,
834 insert_key_set: &FieldKeySet,
835 remove_key_set: &FieldKeySet,
836 flags: ArchiveFlags,
837 n_threads: i32,
838 handler: T,
839 ) -> Result<Self> {
840 let mut message_handler = Box::new(ArchiveMessageState {
841 handler: Box::new(handler),
842 });
843 let handle = unsafe {
844 ffi::aa_archive_stream::compression_rs_aa_convert_archive_output_stream_open_with_messages(
845 stream.as_ptr(),
846 insert_key_set.as_ptr(),
847 remove_key_set.as_ptr(),
848 flags.bits(),
849 n_threads,
850 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
851 Some(archive_entry_message_proc),
852 )
853 };
854 Ok(Self {
855 handle: util::nonnull_handle(handle, "AAConvertArchiveOutputStreamOpen")?,
856 _upstream: Some(ArchiveStreamUpstream::Archive(Box::new(stream))),
857 closed: false,
858 _message_handler: Some(message_handler),
859 })
860 }
861
862 pub fn write_path_list_with_messages<T: EntryMessageHandler + 'static>(
864 &mut self,
865 path_list: &PathList,
866 key_set: &FieldKeySet,
867 dir: &str,
868 flags: ArchiveFlags,
869 n_threads: i32,
870 handler: T,
871 ) -> Result<()> {
872 self.ensure_open()?;
873 let dir = util::cstring("dir", dir)?;
874 let mut message_handler = Box::new(ArchiveMessageState {
875 handler: Box::new(handler),
876 });
877 let status = unsafe {
878 ffi::aa_archive_stream::compression_rs_aa_archive_stream_write_path_list_with_messages(
879 self.as_ptr(),
880 path_list.as_ptr(),
881 key_set.as_ptr(),
882 dir.as_ptr(),
883 flags.bits(),
884 n_threads,
885 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
886 Some(archive_entry_message_proc),
887 )
888 };
889 util::status_result("AAArchiveStreamWritePathList", status)
890 }
891
892 pub fn process_into_with_messages<T: EntryMessageHandler + 'static>(
894 &mut self,
895 output: &mut Self,
896 flags: ArchiveFlags,
897 n_threads: i32,
898 handler: T,
899 ) -> Result<u64> {
900 self.ensure_open()?;
901 output.ensure_open()?;
902 let mut message_handler = Box::new(ArchiveMessageState {
903 handler: Box::new(handler),
904 });
905 util::off_t_result("AAArchiveStreamProcess", unsafe {
906 ffi::aa_archive_stream::compression_rs_aa_archive_stream_process_with_messages(
907 self.as_ptr(),
908 output.as_ptr(),
909 flags.bits(),
910 n_threads,
911 std::ptr::addr_of_mut!(*message_handler).cast::<c_void>(),
912 Some(archive_entry_message_proc),
913 )
914 })
915 }
916}