sevenz_rust2/
encoder_options.rs

1use std::fmt::Debug;
2
3#[cfg(feature = "compress")]
4pub use lzma_rust2::LZMA2Options;
5#[cfg(feature = "ppmd")]
6use ppmd_rust::{PPMD7_MAX_MEM_SIZE, PPMD7_MAX_ORDER, PPMD7_MIN_MEM_SIZE, PPMD7_MIN_ORDER};
7
8#[cfg(feature = "compress")]
9use crate::EncoderConfiguration;
10#[cfg(feature = "aes256")]
11use crate::Password;
12
13#[cfg(feature = "bzip2")]
14#[cfg_attr(docsrs, doc(cfg(feature = "bzip2")))]
15#[derive(Debug, Copy, Clone)]
16pub struct Bzip2Options(pub(crate) u32);
17
18#[cfg(feature = "bzip2")]
19impl Bzip2Options {
20    pub const fn from_level(level: u32) -> Self {
21        Self(level)
22    }
23}
24
25#[cfg(feature = "bzip2")]
26impl Default for Bzip2Options {
27    fn default() -> Self {
28        Self(6)
29    }
30}
31
32#[cfg(any(feature = "brotli", feature = "lz4"))]
33const MINIMAL_SKIPPABLE_FRAME_SIZE: u32 = 64 * 1024;
34#[cfg(feature = "brotli")]
35const DEFAULT_SKIPPABLE_FRAME_SIZE: u32 = 128 * 1024;
36
37#[cfg(feature = "brotli")]
38#[cfg_attr(docsrs, doc(cfg(feature = "brotli")))]
39#[derive(Debug, Copy, Clone)]
40pub struct BrotliOptions {
41    pub(crate) quality: u32,
42    pub(crate) window: u32,
43    pub(crate) skippable_frame_size: u32,
44}
45
46#[cfg(feature = "brotli")]
47impl BrotliOptions {
48    pub const fn from_quality_window(quality: u32, window: u32) -> Self {
49        let quality = if quality > 11 { 11 } else { quality };
50        let window = if window > 24 { 24 } else { window };
51        Self {
52            quality,
53            window,
54            skippable_frame_size: DEFAULT_SKIPPABLE_FRAME_SIZE,
55        }
56    }
57
58    /// Set's the skippable frame size. The size is defined as the size of uncompressed data a frame
59    /// contains. A value of 0 deactivates skippable frames and uses the native brotli bitstream.
60    /// If a value is set, then a similar skippable frame format used by LZ4 and ZSTD is used.
61    ///
62    /// Af value between 1..=64KiB will be set to 64KiB.
63    ///
64    /// This was first implemented by zstdmt. The default value is 128 KiB.
65    pub fn with_skippable_frame_size(mut self, skippable_frame_size: u32) -> Self {
66        if skippable_frame_size == 0 {
67            self.skippable_frame_size = 0;
68        } else {
69            self.skippable_frame_size =
70                u32::max(skippable_frame_size, MINIMAL_SKIPPABLE_FRAME_SIZE);
71        }
72
73        self
74    }
75}
76
77#[cfg(feature = "brotli")]
78impl Default for BrotliOptions {
79    fn default() -> Self {
80        Self {
81            quality: 11,
82            window: 22,
83            skippable_frame_size: DEFAULT_SKIPPABLE_FRAME_SIZE,
84        }
85    }
86}
87
88#[cfg(feature = "compress")]
89#[cfg_attr(docsrs, doc(cfg(feature = "compress")))]
90#[derive(Debug, Copy, Clone)]
91pub struct DeltaOptions(pub(crate) u32);
92
93#[cfg(feature = "compress")]
94impl DeltaOptions {
95    pub const fn from_distance(distance: u32) -> Self {
96        let distance = if distance == 0 {
97            1
98        } else if distance > 256 {
99            256
100        } else {
101            distance
102        };
103        Self(distance)
104    }
105}
106
107#[cfg(feature = "compress")]
108impl Default for DeltaOptions {
109    fn default() -> Self {
110        Self(1)
111    }
112}
113
114#[cfg(feature = "deflate")]
115#[cfg_attr(docsrs, doc(cfg(feature = "deflate")))]
116#[derive(Debug, Copy, Clone)]
117pub struct DeflateOptions(pub(crate) u32);
118
119#[cfg(feature = "deflate")]
120impl DeflateOptions {
121    pub const fn from_level(level: u32) -> Self {
122        let level = if level > 9 { 9 } else { level };
123        Self(level)
124    }
125}
126
127#[cfg(feature = "deflate")]
128impl Default for DeflateOptions {
129    fn default() -> Self {
130        Self(6)
131    }
132}
133
134#[cfg(feature = "lz4")]
135#[cfg_attr(docsrs, doc(cfg(feature = "lz4")))]
136#[derive(Debug, Copy, Clone, Default)]
137pub struct LZ4Options {
138    pub(crate) skippable_frame_size: u32,
139}
140
141#[cfg(feature = "lz4")]
142impl LZ4Options {
143    /// Set's the skippable frame size. The size is defined as the size of uncompressed data a frame
144    /// contains. A value of 0 deactivates skippable frames and uses the native LZ4 bitstream.
145    /// If a value is set, then the similar skippable frame format is used.
146    ///
147    /// Af value between 1..=64KiB will be set to 64KiB.
148    ///
149    /// This was first implemented by zstdmt.
150    ///
151    /// Defaults to not use the skippable frame format at all, since LZ4 is extremely fast and will
152    /// most likely saturate IO even on a single thread.
153    pub fn with_skippable_frame_size(mut self, skippable_frame_size: u32) -> Self {
154        if skippable_frame_size == 0 {
155            self.skippable_frame_size = 0;
156        } else {
157            self.skippable_frame_size =
158                u32::max(skippable_frame_size, MINIMAL_SKIPPABLE_FRAME_SIZE);
159        }
160
161        self
162    }
163}
164
165#[cfg(feature = "ppmd")]
166#[cfg_attr(docsrs, doc(cfg(feature = "ppmd")))]
167#[derive(Debug, Copy, Clone)]
168pub struct PPMDOptions {
169    pub(crate) order: u32,
170    pub(crate) memory_size: u32,
171}
172
173#[cfg(feature = "ppmd")]
174impl PPMDOptions {
175    pub const fn from_level(level: u32) -> Self {
176        const ORDERS: [u32; 10] = [3, 4, 4, 5, 5, 6, 8, 16, 24, 32];
177
178        let level = if level > 9 { 9 } else { level };
179        let order = ORDERS[level as usize];
180        let memory_size = 1 << (level + 19);
181
182        Self { order, memory_size }
183    }
184
185    pub const fn from_order_memory_size(order: u32, memory_size: u32) -> Self {
186        let order = if order > PPMD7_MAX_ORDER {
187            PPMD7_MAX_ORDER
188        } else if order < PPMD7_MIN_ORDER {
189            PPMD7_MIN_ORDER
190        } else {
191            order
192        };
193        let memory_size = if memory_size > PPMD7_MAX_MEM_SIZE {
194            PPMD7_MAX_MEM_SIZE
195        } else if memory_size < PPMD7_MIN_MEM_SIZE {
196            PPMD7_MIN_MEM_SIZE
197        } else {
198            memory_size
199        };
200        Self { order, memory_size }
201    }
202}
203
204#[cfg(feature = "ppmd")]
205impl Default for PPMDOptions {
206    fn default() -> Self {
207        Self::from_level(6)
208    }
209}
210
211#[cfg(feature = "zstd")]
212#[cfg_attr(docsrs, doc(cfg(feature = "zstd")))]
213#[derive(Debug, Copy, Clone)]
214pub struct ZStandardOptions(pub(crate) u32);
215
216#[cfg(feature = "zstd")]
217impl ZStandardOptions {
218    pub const fn from_level(level: u32) -> Self {
219        let level = if level > 22 { 22 } else { level };
220        Self(level)
221    }
222}
223
224#[cfg(feature = "zstd")]
225impl Default for ZStandardOptions {
226    fn default() -> Self {
227        Self(3)
228    }
229}
230
231#[cfg_attr(docsrs, doc(cfg(feature = "aes256")))]
232#[cfg(feature = "aes256")]
233#[derive(Debug, Clone)]
234pub struct AesEncoderOptions {
235    pub password: Password,
236    pub iv: [u8; 16],
237    pub salt: [u8; 16],
238    pub num_cycles_power: u8,
239}
240
241#[cfg(feature = "aes256")]
242impl AesEncoderOptions {
243    pub fn new(password: Password) -> Self {
244        let mut iv = [0; 16];
245        getrandom::fill(&mut iv).expect("Can't generate IV");
246
247        let mut salt = [0; 16];
248        getrandom::fill(&mut salt).expect("Can't generate salt");
249
250        Self {
251            password,
252            iv,
253            salt,
254            num_cycles_power: 8,
255        }
256    }
257
258    pub(crate) fn properties(&self) -> [u8; 34] {
259        let mut props = [0u8; 34];
260        self.write_properties(&mut props);
261        props
262    }
263
264    #[inline]
265    pub(crate) fn write_properties(&self, props: &mut [u8]) {
266        assert!(props.len() >= 34);
267        props[0] = (self.num_cycles_power & 0x3F) | 0xC0;
268        props[1] = 0xFF;
269        props[2..18].copy_from_slice(&self.salt);
270        props[18..34].copy_from_slice(&self.iv);
271    }
272}
273
274#[derive(Debug, Clone)]
275pub enum EncoderOptions {
276    Num(u32),
277    #[cfg(feature = "compress")]
278    #[cfg_attr(docsrs, doc(cfg(feature = "compress")))]
279    Delta(DeltaOptions),
280    #[cfg(feature = "compress")]
281    #[cfg_attr(docsrs, doc(cfg(feature = "compress")))]
282    LZMA2(LZMA2Options),
283    #[cfg(feature = "brotli")]
284    #[cfg_attr(docsrs, doc(cfg(feature = "brotli")))]
285    BROTLI(BrotliOptions),
286    #[cfg(feature = "bzip2")]
287    #[cfg_attr(docsrs, doc(cfg(feature = "bzip2")))]
288    BZIP2(Bzip2Options),
289    #[cfg(feature = "deflate")]
290    #[cfg_attr(docsrs, doc(cfg(feature = "deflate")))]
291    DEFLATE(DeflateOptions),
292    #[cfg(feature = "lz4")]
293    #[cfg_attr(docsrs, doc(cfg(feature = "lz4")))]
294    LZ4(LZ4Options),
295    #[cfg(feature = "ppmd")]
296    #[cfg_attr(docsrs, doc(cfg(feature = "ppmd")))]
297    PPMD(PPMDOptions),
298    #[cfg(feature = "zstd")]
299    #[cfg_attr(docsrs, doc(cfg(feature = "zstd")))]
300    ZSTD(ZStandardOptions),
301    #[cfg(feature = "aes256")]
302    #[cfg_attr(docsrs, doc(cfg(feature = "aes256")))]
303    Aes(AesEncoderOptions),
304}
305
306#[cfg(feature = "aes256")]
307impl From<AesEncoderOptions> for EncoderOptions {
308    fn from(value: AesEncoderOptions) -> Self {
309        Self::Aes(value)
310    }
311}
312
313#[cfg(all(feature = "aes256", feature = "compress"))]
314impl From<AesEncoderOptions> for EncoderConfiguration {
315    fn from(value: AesEncoderOptions) -> Self {
316        Self::new(crate::EncoderMethod::AES256SHA256).with_options(EncoderOptions::Aes(value))
317    }
318}
319
320#[cfg(feature = "compress")]
321impl From<DeltaOptions> for EncoderConfiguration {
322    fn from(options: DeltaOptions) -> Self {
323        Self::new(crate::EncoderMethod::DELTA_FILTER).with_options(EncoderOptions::Delta(options))
324    }
325}
326
327#[cfg(feature = "compress")]
328impl From<LZMA2Options> for EncoderConfiguration {
329    fn from(options: LZMA2Options) -> Self {
330        Self::new(crate::EncoderMethod::LZMA2).with_options(EncoderOptions::LZMA2(options))
331    }
332}
333
334#[cfg(feature = "bzip2")]
335impl From<Bzip2Options> for EncoderConfiguration {
336    fn from(options: Bzip2Options) -> Self {
337        Self::new(crate::EncoderMethod::BZIP2).with_options(EncoderOptions::BZIP2(options))
338    }
339}
340
341#[cfg(feature = "brotli")]
342impl From<BrotliOptions> for EncoderConfiguration {
343    fn from(options: BrotliOptions) -> Self {
344        Self::new(crate::EncoderMethod::BROTLI).with_options(EncoderOptions::BROTLI(options))
345    }
346}
347
348#[cfg(feature = "deflate")]
349impl From<DeflateOptions> for EncoderConfiguration {
350    fn from(options: DeflateOptions) -> Self {
351        Self::new(crate::EncoderMethod::DEFLATE).with_options(EncoderOptions::DEFLATE(options))
352    }
353}
354
355#[cfg(feature = "lz4")]
356impl From<LZ4Options> for EncoderConfiguration {
357    fn from(options: LZ4Options) -> Self {
358        Self::new(crate::EncoderMethod::LZ4).with_options(EncoderOptions::LZ4(options))
359    }
360}
361
362#[cfg(feature = "ppmd")]
363impl From<PPMDOptions> for EncoderConfiguration {
364    fn from(options: PPMDOptions) -> Self {
365        Self::new(crate::EncoderMethod::PPMD).with_options(EncoderOptions::PPMD(options))
366    }
367}
368
369#[cfg(feature = "zstd")]
370impl From<ZStandardOptions> for EncoderConfiguration {
371    fn from(options: ZStandardOptions) -> Self {
372        Self::new(crate::EncoderMethod::ZSTD).with_options(EncoderOptions::ZSTD(options))
373    }
374}
375
376impl From<u32> for EncoderOptions {
377    fn from(n: u32) -> Self {
378        Self::Num(n)
379    }
380}
381
382#[cfg(feature = "compress")]
383impl From<DeltaOptions> for EncoderOptions {
384    fn from(o: DeltaOptions) -> Self {
385        Self::Delta(o)
386    }
387}
388
389#[cfg(feature = "compress")]
390impl From<LZMA2Options> for EncoderOptions {
391    fn from(o: LZMA2Options) -> Self {
392        Self::LZMA2(o)
393    }
394}
395
396#[cfg(feature = "bzip2")]
397impl From<Bzip2Options> for EncoderOptions {
398    fn from(o: Bzip2Options) -> Self {
399        Self::BZIP2(o)
400    }
401}
402
403#[cfg(feature = "brotli")]
404impl From<BrotliOptions> for EncoderOptions {
405    fn from(o: BrotliOptions) -> Self {
406        Self::BROTLI(o)
407    }
408}
409
410#[cfg(feature = "deflate")]
411impl From<DeflateOptions> for EncoderOptions {
412    fn from(o: DeflateOptions) -> Self {
413        Self::DEFLATE(o)
414    }
415}
416
417#[cfg(feature = "lz4")]
418impl From<LZ4Options> for EncoderOptions {
419    fn from(o: LZ4Options) -> Self {
420        Self::LZ4(o)
421    }
422}
423
424#[cfg(feature = "ppmd")]
425impl From<PPMDOptions> for EncoderOptions {
426    fn from(o: PPMDOptions) -> Self {
427        Self::PPMD(o)
428    }
429}
430
431#[cfg(feature = "zstd")]
432impl From<ZStandardOptions> for EncoderOptions {
433    fn from(o: ZStandardOptions) -> Self {
434        Self::ZSTD(o)
435    }
436}
437
438impl EncoderOptions {
439    pub fn get_lzma2_dict_size(&self) -> u32 {
440        match self {
441            EncoderOptions::Num(n) => *n,
442            #[cfg(feature = "compress")]
443            EncoderOptions::LZMA2(o) => o.dict_size,
444            #[allow(unused)]
445            _ => 0,
446        }
447    }
448}