Skip to main content

compression/
aa_archive_stream.rs

1use crate::{
2    aa_byte_stream::{ArchiveFlags, ByteStream},
3    aa_entry_stream::PathList,
4    aa_field_key::{FieldKey, FieldKeySet},
5    aa_header::Header,
6    ffi, util, CompressionError, Result,
7};
8use std::ffi::c_void;
9use std::ptr::NonNull;
10
11#[allow(dead_code)]
12#[derive(Debug)]
13enum ArchiveStreamUpstream {
14    Byte(Box<ByteStream>),
15    Archive(Box<ArchiveStream>),
16}
17
18#[derive(Debug)]
19pub struct ArchiveStream {
20    handle: NonNull<c_void>,
21    _upstream: Option<ArchiveStreamUpstream>,
22    closed: bool,
23}
24
25impl ArchiveStream {
26    pub fn extract_output(dir: &str, flags: ArchiveFlags, n_threads: i32) -> Result<Self> {
27        let dir = util::cstring("dir", dir)?;
28        let handle = unsafe {
29            ffi::aa_archive_stream::compression_rs_aa_extract_archive_output_stream_open(
30                dir.as_ptr(),
31                flags.bits(),
32                n_threads,
33            )
34        };
35        Ok(Self {
36            handle: util::nonnull_handle(handle, "AAExtractArchiveOutputStreamOpen")?,
37            _upstream: None,
38            closed: false,
39        })
40    }
41
42    pub fn encode_output(stream: ByteStream, flags: ArchiveFlags, n_threads: i32) -> Result<Self> {
43        let handle = unsafe {
44            ffi::aa_archive_stream::compression_rs_aa_encode_archive_output_stream_open(
45                stream.as_ptr(),
46                flags.bits(),
47                n_threads,
48            )
49        };
50        Ok(Self {
51            handle: util::nonnull_handle(handle, "AAEncodeArchiveOutputStreamOpen")?,
52            _upstream: Some(ArchiveStreamUpstream::Byte(Box::new(stream))),
53            closed: false,
54        })
55    }
56
57    pub fn decode_input(stream: ByteStream, flags: ArchiveFlags, n_threads: i32) -> Result<Self> {
58        let handle = unsafe {
59            ffi::aa_archive_stream::compression_rs_aa_decode_archive_input_stream_open(
60                stream.as_ptr(),
61                flags.bits(),
62                n_threads,
63            )
64        };
65        Ok(Self {
66            handle: util::nonnull_handle(handle, "AADecodeArchiveInputStreamOpen")?,
67            _upstream: Some(ArchiveStreamUpstream::Byte(Box::new(stream))),
68            closed: false,
69        })
70    }
71
72    pub fn convert_output(
73        stream: ArchiveStream,
74        insert_key_set: &FieldKeySet,
75        remove_key_set: &FieldKeySet,
76        flags: ArchiveFlags,
77        n_threads: i32,
78    ) -> Result<Self> {
79        let handle = unsafe {
80            ffi::aa_archive_stream::compression_rs_aa_convert_archive_output_stream_open(
81                stream.as_ptr(),
82                insert_key_set.as_ptr(),
83                remove_key_set.as_ptr(),
84                flags.bits(),
85                n_threads,
86            )
87        };
88        Ok(Self {
89            handle: util::nonnull_handle(handle, "AAConvertArchiveOutputStreamOpen")?,
90            _upstream: Some(ArchiveStreamUpstream::Archive(Box::new(stream))),
91            closed: false,
92        })
93    }
94
95    pub(crate) fn as_ptr(&self) -> *mut c_void {
96        self.handle.as_ptr()
97    }
98
99    fn ensure_open(&self) -> Result<()> {
100        if self.closed {
101            Err(CompressionError::Closed {
102                resource: "archive stream",
103            })
104        } else {
105            Ok(())
106        }
107    }
108
109    pub fn write_header(&mut self, header: &Header) -> Result<()> {
110        self.ensure_open()?;
111        let status = unsafe {
112            ffi::aa_archive_stream::compression_rs_aa_archive_stream_write_header(
113                self.as_ptr(),
114                header.as_ptr(),
115            )
116        };
117        util::status_result("AAArchiveStreamWriteHeader", status)
118    }
119
120    pub fn write_blob(&mut self, key: FieldKey, buffer: &[u8]) -> Result<()> {
121        self.ensure_open()?;
122        let status = unsafe {
123            ffi::aa_archive_stream::compression_rs_aa_archive_stream_write_blob(
124                self.as_ptr(),
125                key.raw(),
126                buffer.as_ptr(),
127                buffer.len(),
128            )
129        };
130        util::status_result("AAArchiveStreamWriteBlob", status)
131    }
132
133    pub fn read_header(&mut self) -> Result<Option<Header>> {
134        self.ensure_open()?;
135        let mut status = 0_i32;
136        let handle = unsafe {
137            ffi::aa_archive_stream::compression_rs_aa_archive_stream_read_header_new(
138                self.as_ptr(),
139                &mut status,
140            )
141        };
142        match status {
143            1 => Ok(Some(Header::from_handle(
144                handle,
145                "AAArchiveStreamReadHeader",
146            )?)),
147            0 => Ok(None),
148            code => Err(CompressionError::OperationFailed {
149                operation: "AAArchiveStreamReadHeader",
150                code,
151            }),
152        }
153    }
154
155    pub fn read_header_into(&mut self, header: &mut Header) -> Result<bool> {
156        self.ensure_open()?;
157        match unsafe {
158            ffi::aa_archive_stream::compression_rs_aa_archive_stream_read_header_into(
159                self.as_ptr(),
160                header.as_ptr(),
161            )
162        } {
163            1 => Ok(true),
164            0 => Ok(false),
165            code => Err(CompressionError::OperationFailed {
166                operation: "AAArchiveStreamReadHeader",
167                code,
168            }),
169        }
170    }
171
172    pub fn read_blob(&mut self, key: FieldKey, buffer: &mut [u8]) -> Result<()> {
173        self.ensure_open()?;
174        let status = unsafe {
175            ffi::aa_archive_stream::compression_rs_aa_archive_stream_read_blob(
176                self.as_ptr(),
177                key.raw(),
178                buffer.as_mut_ptr(),
179                buffer.len(),
180            )
181        };
182        util::status_result("AAArchiveStreamReadBlob", status)
183    }
184
185    pub fn write_path_list(
186        &mut self,
187        path_list: &PathList,
188        key_set: &FieldKeySet,
189        dir: &str,
190        flags: ArchiveFlags,
191        n_threads: i32,
192    ) -> Result<()> {
193        self.ensure_open()?;
194        let dir = util::cstring("dir", dir)?;
195        let status = unsafe {
196            ffi::aa_archive_stream::compression_rs_aa_archive_stream_write_path_list(
197                self.as_ptr(),
198                path_list.as_ptr(),
199                key_set.as_ptr(),
200                dir.as_ptr(),
201                flags.bits(),
202                n_threads,
203            )
204        };
205        util::status_result("AAArchiveStreamWritePathList", status)
206    }
207
208    pub fn process_into(
209        &mut self,
210        output: &mut Self,
211        flags: ArchiveFlags,
212        n_threads: i32,
213    ) -> Result<u64> {
214        self.ensure_open()?;
215        output.ensure_open()?;
216        util::off_t_result("AAArchiveStreamProcess", unsafe {
217            ffi::aa_archive_stream::compression_rs_aa_archive_stream_process(
218                self.as_ptr(),
219                output.as_ptr(),
220                flags.bits(),
221                n_threads,
222            )
223        })
224    }
225
226    pub fn cancel(&mut self) -> Result<()> {
227        self.ensure_open()?;
228        unsafe { ffi::aa_archive_stream::compression_rs_aa_archive_stream_cancel(self.as_ptr()) };
229        Ok(())
230    }
231
232    pub fn close(&mut self) -> Result<()> {
233        if self.closed {
234            return Ok(());
235        }
236        let status = unsafe {
237            ffi::aa_archive_stream::compression_rs_aa_archive_stream_close(self.as_ptr())
238        };
239        self.closed = true;
240        util::status_result("AAArchiveStreamClose", status)
241    }
242}
243
244impl Drop for ArchiveStream {
245    fn drop(&mut self) {
246        unsafe { ffi::aa_archive_stream::compression_rs_aa_archive_stream_release(self.as_ptr()) };
247    }
248}