1#[cfg(feature = "alloc")]
2use alloc::borrow::Cow;
3#[cfg(feature = "alloc")]
4use alloc::boxed::Box;
5#[cfg(feature = "alloc")]
6use alloc::vec::Vec;
7
8use crate::BlockDecodeWorkspace;
9use zrip_core::dict::Dictionary;
10use zrip_core::error::DecompressError;
11
12pub struct DecompressContext {
28 dict: Option<Dictionary>,
29 output: Vec<u8>,
30 ws: Box<BlockDecodeWorkspace>,
31}
32
33impl Default for DecompressContext {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl DecompressContext {
40 pub fn new() -> Self {
42 Self {
43 dict: None,
44 output: Vec::new(),
45 ws: Box::new(BlockDecodeWorkspace::new()),
46 }
47 }
48
49 pub fn with_dict(dict: Dictionary) -> Self {
51 Self {
52 dict: Some(dict),
53 output: Vec::new(),
54 ws: Box::new(BlockDecodeWorkspace::new()),
55 }
56 }
57
58 pub fn decompress(&mut self, input: &[u8]) -> Result<Cow<'_, [u8]>, DecompressError> {
60 self.decompress_with_limit(input, zrip_core::DEFAULT_DECOMPRESS_LIMIT)
61 }
62
63 pub fn decompress_with_limit(
68 &mut self,
69 input: &[u8],
70 max_output: usize,
71 ) -> Result<Cow<'_, [u8]>, DecompressError> {
72 self.output.clear();
73 let dict_ref = self.dict.as_ref();
74 let mut offset = 0;
75 while offset < input.len() {
76 let remaining = &input[offset..];
77 if let Some(skip_len) = super::skip_skippable_frame(remaining) {
78 offset += skip_len;
79 continue;
80 }
81 let consumed = super::decompress_frame(
82 remaining,
83 &mut self.output,
84 max_output,
85 dict_ref,
86 &mut self.ws,
87 )?;
88 offset += consumed;
89 }
90 if self.output.len() >= zrip_core::LARGE_OUTPUT_THRESHOLD {
91 Ok(Cow::Owned(core::mem::take(&mut self.output)))
92 } else {
93 Ok(Cow::Borrowed(&self.output))
94 }
95 }
96}