Skip to main content

compression/
aea.rs

1use crate::{
2    aa_byte_stream::{ArchiveCompressionAlgorithm, ArchiveFlags, ByteStream, ByteStreamUpstream},
3    aa_entry_blob::NamedBlobEntry,
4    ffi, util, CompressionError, Result,
5};
6use std::ffi::{c_void, CStr};
7use std::ptr::{null, null_mut, NonNull};
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
10#[repr(u32)]
11pub enum AeaProfile {
12    HkdfSha256HmacNoneEcdsaP256 = 0,
13    HkdfSha256AesctrHmacSymmetricNone = 1,
14    HkdfSha256AesctrHmacSymmetricEcdsaP256 = 2,
15    HkdfSha256AesctrHmacEcdheP256None = 3,
16    HkdfSha256AesctrHmacEcdheP256EcdsaP256 = 4,
17    HkdfSha256AesctrHmacScryptNone = 5,
18}
19
20impl AeaProfile {
21    const fn from_raw(raw: u32) -> Option<Self> {
22        match raw {
23            x if x == Self::HkdfSha256HmacNoneEcdsaP256 as u32 => {
24                Some(Self::HkdfSha256HmacNoneEcdsaP256)
25            }
26            x if x == Self::HkdfSha256AesctrHmacSymmetricNone as u32 => {
27                Some(Self::HkdfSha256AesctrHmacSymmetricNone)
28            }
29            x if x == Self::HkdfSha256AesctrHmacSymmetricEcdsaP256 as u32 => {
30                Some(Self::HkdfSha256AesctrHmacSymmetricEcdsaP256)
31            }
32            x if x == Self::HkdfSha256AesctrHmacEcdheP256None as u32 => {
33                Some(Self::HkdfSha256AesctrHmacEcdheP256None)
34            }
35            x if x == Self::HkdfSha256AesctrHmacEcdheP256EcdsaP256 as u32 => {
36                Some(Self::HkdfSha256AesctrHmacEcdheP256EcdsaP256)
37            }
38            x if x == Self::HkdfSha256AesctrHmacScryptNone as u32 => {
39                Some(Self::HkdfSha256AesctrHmacScryptNone)
40            }
41            _ => None,
42        }
43    }
44
45    pub const fn raw(self) -> u32 {
46        self as u32
47    }
48
49    pub const fn ciphersuite(self) -> AeaCiphersuite {
50        match self {
51            Self::HkdfSha256HmacNoneEcdsaP256 => AeaCiphersuite::HkdfSha256Hmac,
52            Self::HkdfSha256AesctrHmacSymmetricNone
53            | Self::HkdfSha256AesctrHmacSymmetricEcdsaP256
54            | Self::HkdfSha256AesctrHmacEcdheP256None
55            | Self::HkdfSha256AesctrHmacEcdheP256EcdsaP256
56            | Self::HkdfSha256AesctrHmacScryptNone => AeaCiphersuite::HkdfSha256AesctrHmac,
57        }
58    }
59
60    pub const fn signature_mode(self) -> AeaSignatureMode {
61        match self {
62            Self::HkdfSha256HmacNoneEcdsaP256
63            | Self::HkdfSha256AesctrHmacSymmetricEcdsaP256
64            | Self::HkdfSha256AesctrHmacEcdheP256EcdsaP256 => AeaSignatureMode::EcdsaP256,
65            Self::HkdfSha256AesctrHmacSymmetricNone
66            | Self::HkdfSha256AesctrHmacEcdheP256None
67            | Self::HkdfSha256AesctrHmacScryptNone => AeaSignatureMode::None,
68        }
69    }
70
71    pub const fn encryption_mode(self) -> AeaEncryptionMode {
72        match self {
73            Self::HkdfSha256HmacNoneEcdsaP256 => AeaEncryptionMode::None,
74            Self::HkdfSha256AesctrHmacSymmetricNone
75            | Self::HkdfSha256AesctrHmacSymmetricEcdsaP256 => AeaEncryptionMode::Symmetric,
76            Self::HkdfSha256AesctrHmacEcdheP256None
77            | Self::HkdfSha256AesctrHmacEcdheP256EcdsaP256 => AeaEncryptionMode::EcdheP256,
78            Self::HkdfSha256AesctrHmacScryptNone => AeaEncryptionMode::Scrypt,
79        }
80    }
81}
82
83#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
84#[repr(u32)]
85pub enum AeaContextField {
86    Profile = 0,
87    PaddingSize = 1,
88    ChecksumMode = 2,
89    CompressionAlgorithm = 3,
90    CompressionBlockSize = 4,
91    AuthData = 5,
92    MainKey = 6,
93    SigningPublicKey = 7,
94    SigningPrivateKey = 8,
95    SymmetricKey = 9,
96    RecipientPublicKey = 10,
97    RecipientPrivateKey = 11,
98    SignatureEncryptionKey = 12,
99    RawSize = 13,
100    ContainerSize = 14,
101    BlocksPerCluster = 17,
102    ArchiveIdentifier = 18,
103    Password = 19,
104}
105
106impl AeaContextField {
107    pub const fn raw(self) -> u32 {
108        self as u32
109    }
110}
111
112#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
113#[repr(u32)]
114pub enum AeaContextFieldRepresentation {
115    Raw = 0,
116    X963 = 1,
117    Generate = 2,
118}
119
120impl AeaContextFieldRepresentation {
121    const fn raw(self) -> u32 {
122        self as u32
123    }
124}
125
126#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
127#[repr(u32)]
128pub enum AeaCiphersuite {
129    HkdfSha256Hmac = 0,
130    HkdfSha256AesctrHmac = 1,
131}
132
133#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
134#[repr(u32)]
135pub enum AeaSignatureMode {
136    None = 0,
137    EcdsaP256 = 1,
138}
139
140#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
141#[repr(u32)]
142pub enum AeaEncryptionMode {
143    None = 0,
144    Symmetric = 1,
145    EcdheP256 = 2,
146    Scrypt = 3,
147}
148
149#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
150#[repr(u32)]
151pub enum AeaChecksumMode {
152    None = 0,
153    MurmurHash64 = 1,
154    Sha256 = 2,
155}
156
157impl AeaChecksumMode {
158    const fn from_raw(raw: u32) -> Option<Self> {
159        match raw {
160            x if x == Self::None as u32 => Some(Self::None),
161            x if x == Self::MurmurHash64 as u32 => Some(Self::MurmurHash64),
162            x if x == Self::Sha256 as u32 => Some(Self::Sha256),
163            _ => None,
164        }
165    }
166
167    const fn raw(self) -> u32 {
168        self as u32
169    }
170}
171
172#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
173pub struct AeaPadding;
174
175impl AeaPadding {
176    pub const NONE: u64 = 0;
177    pub const ADAPTIVE: u64 = 1;
178    pub const MIN_SIZE: u64 = 16;
179}
180
181#[derive(Debug)]
182pub struct AeaContext {
183    handle: NonNull<c_void>,
184}
185
186impl AeaContext {
187    fn from_handle(handle: *mut c_void, operation: &'static str) -> Result<Self> {
188        Ok(Self {
189            handle: util::nonnull_handle(handle, operation)?,
190        })
191    }
192
193    fn open_byte_stream(
194        handle: *mut c_void,
195        operation: &'static str,
196        upstream: ByteStream,
197    ) -> Result<ByteStream> {
198        ByteStream::from_handle_with_upstream(
199            handle,
200            operation,
201            Some(ByteStreamUpstream::Stream(Box::new(upstream))),
202        )
203    }
204
205    pub fn with_profile(profile: AeaProfile) -> Result<Self> {
206        let handle =
207            unsafe { ffi::aea::compression_rs_aea_context_create_with_profile(profile.raw()) };
208        Self::from_handle(handle, "AEAContextCreateWithProfile")
209    }
210
211    pub fn from_encrypted_stream(stream: &mut ByteStream) -> Result<Self> {
212        let handle = unsafe {
213            ffi::aea::compression_rs_aea_context_create_with_encrypted_stream(stream.as_ptr())
214        };
215        Self::from_handle(handle, "AEAContextCreateWithEncryptedStream")
216    }
217
218    pub(crate) fn as_ptr(&self) -> *mut c_void {
219        self.handle.as_ptr()
220    }
221
222    pub fn field_uint(&self, field: AeaContextField) -> Result<u64> {
223        let value = unsafe {
224            ffi::aea::compression_rs_aea_context_get_field_uint(self.as_ptr(), field.raw())
225        };
226        if value == u64::MAX {
227            Err(CompressionError::OperationFailed {
228                operation: "AEAContextGetFieldUInt",
229                code: -1,
230            })
231        } else {
232            Ok(value)
233        }
234    }
235
236    pub fn field_blob(
237        &self,
238        field: AeaContextField,
239        representation: AeaContextFieldRepresentation,
240    ) -> Result<Vec<u8>> {
241        let mut size = 0_usize;
242        let status = unsafe {
243            ffi::aea::compression_rs_aea_context_get_field_blob(
244                self.as_ptr(),
245                field.raw(),
246                representation.raw(),
247                0,
248                null_mut(),
249                &mut size,
250            )
251        };
252        util::status_result("AEAContextGetFieldBlob", status)?;
253
254        let mut data = vec![0_u8; size];
255        let status = unsafe {
256            ffi::aea::compression_rs_aea_context_get_field_blob(
257                self.as_ptr(),
258                field.raw(),
259                representation.raw(),
260                data.len(),
261                if data.is_empty() {
262                    null_mut()
263                } else {
264                    data.as_mut_ptr()
265                },
266                &mut size,
267            )
268        };
269        util::status_result("AEAContextGetFieldBlob", status)?;
270        Ok(data)
271    }
272
273    pub fn set_field_uint(&mut self, field: AeaContextField, value: u64) -> Result<()> {
274        let status = unsafe {
275            ffi::aea::compression_rs_aea_context_set_field_uint(self.as_ptr(), field.raw(), value)
276        };
277        util::status_result("AEAContextSetFieldUInt", status)
278    }
279
280    pub fn set_field_blob(
281        &mut self,
282        field: AeaContextField,
283        representation: AeaContextFieldRepresentation,
284        value: &[u8],
285    ) -> Result<()> {
286        let value_ptr = if value.is_empty() {
287            null()
288        } else {
289            value.as_ptr()
290        };
291        let status = unsafe {
292            ffi::aea::compression_rs_aea_context_set_field_blob(
293                self.as_ptr(),
294                field.raw(),
295                representation.raw(),
296                value_ptr,
297                value.len(),
298            )
299        };
300        util::status_result("AEAContextSetFieldBlob", status)
301    }
302
303    pub fn generate_field_blob(&mut self, field: AeaContextField) -> Result<()> {
304        let status = unsafe {
305            ffi::aea::compression_rs_aea_context_generate_field_blob(self.as_ptr(), field.raw())
306        };
307        util::status_result("AEAContextGenerateFieldBlob", status)
308    }
309
310    pub fn decrypt_attributes(&mut self) -> Result<()> {
311        let status =
312            unsafe { ffi::aea::compression_rs_aea_context_decrypt_attributes(self.as_ptr()) };
313        util::status_result("AEAContextDecryptAttributes", status)
314    }
315
316    pub fn profile(&self) -> Result<AeaProfile> {
317        let raw = u32::try_from(self.field_uint(AeaContextField::Profile)?).unwrap_or(u32::MAX);
318        AeaProfile::from_raw(raw).ok_or_else(|| CompressionError::OperationFailed {
319            operation: "AEAContextGetProfile",
320            code: i32::try_from(raw).unwrap_or(i32::MAX),
321        })
322    }
323
324    pub fn checksum_mode(&self) -> Result<AeaChecksumMode> {
325        let raw =
326            u32::try_from(self.field_uint(AeaContextField::ChecksumMode)?).unwrap_or(u32::MAX);
327        AeaChecksumMode::from_raw(raw).ok_or_else(|| CompressionError::OperationFailed {
328            operation: "AEAContextGetChecksumMode",
329            code: i32::try_from(raw).unwrap_or(i32::MAX),
330        })
331    }
332
333    pub fn compression_algorithm(&self) -> Result<ArchiveCompressionAlgorithm> {
334        let raw = u32::try_from(self.field_uint(AeaContextField::CompressionAlgorithm)?)
335            .unwrap_or(u32::MAX);
336        ArchiveCompressionAlgorithm::from_raw(raw).ok_or_else(|| {
337            CompressionError::OperationFailed {
338                operation: "AEAContextGetCompressionAlgorithm",
339                code: i32::try_from(raw).unwrap_or(i32::MAX),
340            }
341        })
342    }
343
344    pub fn compression_block_size(&self) -> Result<usize> {
345        usize::try_from(self.field_uint(AeaContextField::CompressionBlockSize)?).map_err(|_| {
346            CompressionError::OperationFailed {
347                operation: "AEAContextGetCompressionBlockSize",
348                code: i32::MAX,
349            }
350        })
351    }
352
353    pub fn raw_size(&self) -> Result<u64> {
354        self.field_uint(AeaContextField::RawSize)
355    }
356
357    pub fn container_size(&self) -> Result<u64> {
358        self.field_uint(AeaContextField::ContainerSize)
359    }
360
361    pub fn auth_data(&self) -> Result<Vec<u8>> {
362        self.field_blob(
363            AeaContextField::AuthData,
364            AeaContextFieldRepresentation::Raw,
365        )
366    }
367
368    pub fn signature_encryption_key(&self) -> Result<Vec<u8>> {
369        self.field_blob(
370            AeaContextField::SignatureEncryptionKey,
371            AeaContextFieldRepresentation::Raw,
372        )
373    }
374
375    pub fn archive_identifier(&self) -> Result<Vec<u8>> {
376        self.field_blob(
377            AeaContextField::ArchiveIdentifier,
378            AeaContextFieldRepresentation::Raw,
379        )
380    }
381
382    pub fn main_key(&self) -> Result<Vec<u8>> {
383        self.field_blob(AeaContextField::MainKey, AeaContextFieldRepresentation::Raw)
384    }
385
386    pub fn set_compression_algorithm(
387        &mut self,
388        compression_algorithm: ArchiveCompressionAlgorithm,
389    ) -> Result<()> {
390        self.set_field_uint(
391            AeaContextField::CompressionAlgorithm,
392            u64::from(compression_algorithm.as_raw()),
393        )
394    }
395
396    pub fn set_compression_block_size(&mut self, compression_block_size: usize) -> Result<()> {
397        self.set_field_uint(
398            AeaContextField::CompressionBlockSize,
399            u64::try_from(compression_block_size).unwrap_or(u64::MAX),
400        )
401    }
402
403    pub fn set_checksum_mode(&mut self, checksum_mode: AeaChecksumMode) -> Result<()> {
404        self.set_field_uint(
405            AeaContextField::ChecksumMode,
406            u64::from(checksum_mode.raw()),
407        )
408    }
409
410    pub fn set_padding_size(&mut self, padding_size: u64) -> Result<()> {
411        self.set_field_uint(AeaContextField::PaddingSize, padding_size)
412    }
413
414    pub fn set_auth_data_bytes(&mut self, auth_data: &[u8]) -> Result<()> {
415        self.set_field_blob(
416            AeaContextField::AuthData,
417            AeaContextFieldRepresentation::Raw,
418            auth_data,
419        )
420    }
421
422    pub fn set_auth_data_blob(&mut self, auth_data: &AeaAuthData) -> Result<()> {
423        self.set_auth_data_bytes(&auth_data.encoded_data()?)
424    }
425
426    pub fn set_signature_encryption_key(&mut self, key: &[u8]) -> Result<()> {
427        self.set_field_blob(
428            AeaContextField::SignatureEncryptionKey,
429            AeaContextFieldRepresentation::Raw,
430            key,
431        )
432    }
433
434    pub fn set_symmetric_key(&mut self, key: &[u8]) -> Result<()> {
435        self.set_field_blob(
436            AeaContextField::SymmetricKey,
437            AeaContextFieldRepresentation::Raw,
438            key,
439        )
440    }
441
442    pub fn set_password(&mut self, password: &[u8]) -> Result<()> {
443        self.set_field_blob(
444            AeaContextField::Password,
445            AeaContextFieldRepresentation::Raw,
446            password,
447        )
448    }
449
450    pub fn set_signing_public_key(&mut self, key: &[u8]) -> Result<()> {
451        self.set_field_blob(
452            AeaContextField::SigningPublicKey,
453            AeaContextFieldRepresentation::X963,
454            key,
455        )
456    }
457
458    pub fn set_signing_private_key(&mut self, key: &[u8]) -> Result<()> {
459        self.set_field_blob(
460            AeaContextField::SigningPrivateKey,
461            AeaContextFieldRepresentation::X963,
462            key,
463        )
464    }
465
466    pub fn set_recipient_public_key(&mut self, key: &[u8]) -> Result<()> {
467        self.set_field_blob(
468            AeaContextField::RecipientPublicKey,
469            AeaContextFieldRepresentation::X963,
470            key,
471        )
472    }
473
474    pub fn set_recipient_private_key(&mut self, key: &[u8]) -> Result<()> {
475        self.set_field_blob(
476            AeaContextField::RecipientPrivateKey,
477            AeaContextFieldRepresentation::X963,
478            key,
479        )
480    }
481
482    pub fn set_main_key(&mut self, key: &[u8]) -> Result<()> {
483        self.set_field_blob(
484            AeaContextField::MainKey,
485            AeaContextFieldRepresentation::Raw,
486            key,
487        )
488    }
489
490    pub fn encryption_output_stream(
491        &self,
492        encrypted_stream: ByteStream,
493        flags: ArchiveFlags,
494        n_threads: i32,
495    ) -> Result<ByteStream> {
496        let handle = unsafe {
497            ffi::aea::compression_rs_aea_encryption_output_stream_open(
498                encrypted_stream.as_ptr(),
499                self.as_ptr(),
500                flags.bits(),
501                n_threads,
502            )
503        };
504        Self::open_byte_stream(handle, "AEAEncryptionOutputStreamOpen", encrypted_stream)
505    }
506
507    pub fn encryption_output_stream_existing(
508        &self,
509        encrypted_stream: ByteStream,
510        flags: ArchiveFlags,
511        n_threads: i32,
512    ) -> Result<ByteStream> {
513        let handle = unsafe {
514            ffi::aea::compression_rs_aea_encryption_output_stream_open_existing(
515                encrypted_stream.as_ptr(),
516                self.as_ptr(),
517                flags.bits(),
518                n_threads,
519            )
520        };
521        Self::open_byte_stream(
522            handle,
523            "AEAEncryptionOutputStreamOpenExisting",
524            encrypted_stream,
525        )
526    }
527
528    pub fn decryption_input_stream(
529        &mut self,
530        encrypted_stream: ByteStream,
531        flags: ArchiveFlags,
532        n_threads: i32,
533    ) -> Result<ByteStream> {
534        let handle = unsafe {
535            ffi::aea::compression_rs_aea_decryption_input_stream_open(
536                encrypted_stream.as_ptr(),
537                self.as_ptr(),
538                flags.bits(),
539                n_threads,
540            )
541        };
542        Self::open_byte_stream(handle, "AEADecryptionInputStreamOpen", encrypted_stream)
543    }
544
545    pub fn decryption_random_access_input_stream(
546        &mut self,
547        encrypted_stream: ByteStream,
548        alloc_limit: usize,
549        flags: ArchiveFlags,
550        n_threads: i32,
551    ) -> Result<ByteStream> {
552        let handle = unsafe {
553            ffi::aea::compression_rs_aea_decryption_random_access_input_stream_open(
554                encrypted_stream.as_ptr(),
555                self.as_ptr(),
556                alloc_limit,
557                flags.bits(),
558                n_threads,
559            )
560        };
561        Self::open_byte_stream(
562            handle,
563            "AEADecryptionRandomAccessInputStreamOpen",
564            encrypted_stream,
565        )
566    }
567
568    pub fn close_encryption_output_stream(&mut self, stream: &mut ByteStream) -> Result<()> {
569        let status = unsafe {
570            ffi::aea::compression_rs_aea_encryption_output_stream_close_and_update_context(
571                stream.as_ptr(),
572                self.as_ptr(),
573            )
574        };
575        util::status_result("AEAEncryptionOutputStreamCloseAndUpdateContext", status)?;
576        stream.mark_closed();
577        Ok(())
578    }
579
580    pub fn sign_stream(&self, stream: &mut ByteStream) -> Result<()> {
581        let status =
582            unsafe { ffi::aea::compression_rs_aea_stream_sign(stream.as_ptr(), self.as_ptr()) };
583        util::status_result("AEAStreamSign", status)
584    }
585}
586
587impl Drop for AeaContext {
588    fn drop(&mut self) {
589        unsafe { ffi::aea::compression_rs_aea_context_release(self.as_ptr()) };
590    }
591}
592
593#[derive(Debug)]
594pub struct AeaAuthData {
595    handle: NonNull<c_void>,
596}
597
598impl AeaAuthData {
599    fn from_handle(handle: *mut c_void, operation: &'static str) -> Result<Self> {
600        Ok(Self {
601            handle: util::nonnull_handle(handle, operation)?,
602        })
603    }
604
605    pub fn new() -> Result<Self> {
606        let handle = unsafe { ffi::aea::compression_rs_aea_auth_data_create() };
607        Self::from_handle(handle, "AEAAuthDataCreate")
608    }
609
610    pub fn from_context(context: &AeaContext) -> Result<Self> {
611        let handle =
612            unsafe { ffi::aea::compression_rs_aea_auth_data_create_with_context(context.as_ptr()) };
613        Self::from_handle(handle, "AEAAuthDataCreateWithContext")
614    }
615
616    pub(crate) fn as_ptr(&self) -> *mut c_void {
617        self.handle.as_ptr()
618    }
619
620    pub fn entry_count(&self) -> u32 {
621        unsafe { ffi::aea::compression_rs_aea_auth_data_get_entry_count(self.as_ptr()) }
622    }
623
624    pub fn is_empty(&self) -> bool {
625        self.entry_count() == 0
626    }
627
628    pub fn entry(&self, index: u32) -> Result<NamedBlobEntry> {
629        let mut key_length = 0_usize;
630        let mut data_size = 0_usize;
631        let status = unsafe {
632            ffi::aea::compression_rs_aea_auth_data_get_entry(
633                self.as_ptr(),
634                index,
635                0,
636                null_mut(),
637                &mut key_length,
638                0,
639                null_mut(),
640                &mut data_size,
641            )
642        };
643        util::status_result("AEAAuthDataGetEntry", status)?;
644
645        let mut key = vec![0_i8; key_length.saturating_add(1)];
646        let mut value = vec![0_u8; data_size];
647        let status = unsafe {
648            ffi::aea::compression_rs_aea_auth_data_get_entry(
649                self.as_ptr(),
650                index,
651                key.len(),
652                key.as_mut_ptr(),
653                &mut key_length,
654                value.len(),
655                if value.is_empty() {
656                    null_mut()
657                } else {
658                    value.as_mut_ptr()
659                },
660                &mut data_size,
661            )
662        };
663        util::status_result("AEAAuthDataGetEntry", status)?;
664
665        let key = unsafe { CStr::from_ptr(key.as_ptr()) }
666            .to_str()
667            .map_err(|_| CompressionError::Utf8Error {
668                operation: "AEAAuthDataGetEntry",
669            })?
670            .to_string();
671
672        Ok(NamedBlobEntry { key, value })
673    }
674
675    pub fn entries(&self) -> Result<Vec<NamedBlobEntry>> {
676        (0..self.entry_count())
677            .map(|index| self.entry(index))
678            .collect()
679    }
680
681    pub fn append_entry(&mut self, entry: &NamedBlobEntry) -> Result<()> {
682        let key = util::cstring("key", &entry.key)?;
683        let data_ptr = if entry.value.is_empty() {
684            null()
685        } else {
686            entry.value.as_ptr()
687        };
688        let status = unsafe {
689            ffi::aea::compression_rs_aea_auth_data_append_entry(
690                self.as_ptr(),
691                key.as_ptr(),
692                data_ptr,
693                entry.value.len(),
694            )
695        };
696        util::status_result("AEAAuthDataAppendEntry", status)
697    }
698
699    pub fn set_entry(&mut self, index: u32, entry: &NamedBlobEntry) -> Result<()> {
700        let key = util::cstring("key", &entry.key)?;
701        let data_ptr = if entry.value.is_empty() {
702            null()
703        } else {
704            entry.value.as_ptr()
705        };
706        let status = unsafe {
707            ffi::aea::compression_rs_aea_auth_data_set_entry(
708                self.as_ptr(),
709                index,
710                key.as_ptr(),
711                data_ptr,
712                entry.value.len(),
713            )
714        };
715        util::status_result("AEAAuthDataSetEntry", status)
716    }
717
718    pub fn clear(&mut self) -> Result<()> {
719        let status = unsafe { ffi::aea::compression_rs_aea_auth_data_clear(self.as_ptr()) };
720        util::status_result("AEAAuthDataClear", status)
721    }
722
723    pub fn remove_entry(&mut self, index: u32) -> Result<()> {
724        let status =
725            unsafe { ffi::aea::compression_rs_aea_auth_data_remove_entry(self.as_ptr(), index) };
726        util::status_result("AEAAuthDataRemoveEntry", status)
727    }
728
729    pub fn encoded_size(&self) -> usize {
730        unsafe { ffi::aea::compression_rs_aea_auth_data_get_encoded_size(self.as_ptr()) }
731    }
732
733    pub fn encoded_data(&self) -> Result<Vec<u8>> {
734        let size = self.encoded_size();
735        let mut data = vec![0_u8; size];
736        if size == 0 {
737            return Ok(data);
738        }
739        let copied = unsafe {
740            ffi::aea::compression_rs_aea_auth_data_copy_encoded_data(
741                self.as_ptr(),
742                data.as_mut_ptr(),
743            )
744        };
745        if copied {
746            Ok(data)
747        } else {
748            Err(CompressionError::OperationFailed {
749                operation: "AEAAuthDataGetEncodedData",
750                code: -1,
751            })
752        }
753    }
754}
755
756impl Clone for AeaAuthData {
757    fn clone(&self) -> Self {
758        let mut clone = Self::new().expect("AEAAuthDataCreate returned null");
759        for entry in self.entries().expect("AEAAuthDataGetEntry failed") {
760            clone
761                .append_entry(&entry)
762                .expect("AEAAuthDataAppendEntry failed");
763        }
764        clone
765    }
766}
767
768impl Drop for AeaAuthData {
769    fn drop(&mut self) {
770        unsafe { ffi::aea::compression_rs_aea_auth_data_release(self.as_ptr()) };
771    }
772}