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}