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 let mut ws = Box::new(BlockDecodeWorkspace::new());
52 ws.cache_dict(&dict);
53 Self {
54 dict: Some(dict),
55 output: Vec::new(),
56 ws,
57 }
58 }
59
60 pub fn decompress(&mut self, input: &[u8]) -> Result<Cow<'_, [u8]>, DecompressError> {
62 self.decompress_with_limit(input, zrip_core::DEFAULT_DECOMPRESS_LIMIT)
63 }
64
65 pub fn decompress_with_limit(
70 &mut self,
71 input: &[u8],
72 max_output: usize,
73 ) -> Result<Cow<'_, [u8]>, DecompressError> {
74 self.output.clear();
75 let dict_ref = self.dict.as_ref();
76 let mut offset = 0;
77 while offset < input.len() {
78 let remaining = &input[offset..];
79 if let Some(skip_len) = super::skip_skippable_frame(remaining) {
80 offset += skip_len;
81 continue;
82 }
83 let consumed = super::decompress_frame(
84 remaining,
85 &mut self.output,
86 max_output,
87 dict_ref,
88 &mut self.ws,
89 )?;
90 offset += consumed;
91 }
92 if self.output.len() >= zrip_core::LARGE_OUTPUT_THRESHOLD {
93 Ok(Cow::Owned(core::mem::take(&mut self.output)))
94 } else {
95 Ok(Cow::Borrowed(&self.output))
96 }
97 }
98}