libzstd_bitexact_rs/
decompress.rs1use crate::block::{self, BLOCK_SIZE_MAX, FrameContext};
5use crate::dictionary::Dictionary;
6use crate::error::Error;
7use crate::frame;
8use crate::xxhash::xxh64;
9
10pub(crate) const ZSTD_MAGIC: u32 = 0xFD2F_B528;
11pub(crate) const SKIPPABLE_MAGIC_MASK: u32 = 0xFFFF_FFF0;
12pub(crate) const SKIPPABLE_MAGIC: u32 = 0x184D_2A50;
13
14const MAX_PREALLOC: u64 = 32 << 20;
17
18pub const WINDOW_LOG_MAX: u32 = 31;
23
24#[derive(Clone)]
34pub struct DecodeOptions<'d> {
35 limit: usize,
36 window_log_max: u32,
37 dictionary: Option<&'d Dictionary>,
38}
39
40impl Default for DecodeOptions<'_> {
41 fn default() -> Self {
42 DecodeOptions {
43 limit: usize::MAX,
44 window_log_max: WINDOW_LOG_MAX,
45 dictionary: None,
46 }
47 }
48}
49
50impl<'d> DecodeOptions<'d> {
51 pub fn new() -> Self {
54 Self::default()
55 }
56
57 pub fn limit(mut self, limit: usize) -> Self {
61 self.limit = limit;
62 self
63 }
64
65 pub fn window_log_max(mut self, window_log_max: u32) -> Self {
69 self.window_log_max = window_log_max;
70 self
71 }
72
73 pub fn dictionary(mut self, dictionary: &'d Dictionary) -> Self {
77 self.dictionary = Some(dictionary);
78 self
79 }
80
81 pub(crate) fn limit_value(&self) -> usize {
82 self.limit
83 }
84
85 pub(crate) fn window_log_max_value(&self) -> u32 {
86 self.window_log_max
87 }
88
89 pub(crate) fn dictionary_value(&self) -> Option<&'d Dictionary> {
90 self.dictionary
91 }
92
93 pub fn decompress(&self, src: &[u8]) -> Result<Vec<u8>, Error> {
95 let mut out = Vec::new();
96 let mut input = src;
97 while !input.is_empty() {
98 if input.len() < 4 {
99 return Err(Error::SrcSizeWrong);
100 }
101 let magic = u32::from_le_bytes(input[..4].try_into().unwrap());
102 if magic == ZSTD_MAGIC {
103 input = self.decode_frame(&input[4..], &mut out)?;
104 } else if magic & SKIPPABLE_MAGIC_MASK == SKIPPABLE_MAGIC {
105 if input.len() < 8 {
106 return Err(Error::SrcSizeWrong);
107 }
108 let size = u32::from_le_bytes(input[4..8].try_into().unwrap()) as usize;
109 input = input.get(8 + size..).ok_or(Error::SrcSizeWrong)?;
110 } else {
111 return Err(Error::UnknownMagic(magic));
112 }
113 }
114 Ok(out)
115 }
116
117 fn decode_frame<'a>(&self, src: &'a [u8], out: &mut Vec<u8>) -> Result<&'a [u8], Error> {
120 let header = frame::parse(src, self.window_log_max)?;
121
122 let dict = match (self.dictionary, header.dict_id) {
126 (_, 0) => self.dictionary,
127 (Some(d), id) if d.id() == id => Some(d),
128 (Some(d), id) => {
129 return Err(Error::DictionaryWrong {
130 expected: id,
131 actual: d.id(),
132 });
133 }
134 (None, id) => return Err(Error::DictionaryRequired(id)),
135 };
136 let dict_content = dict.map_or(&[][..], Dictionary::content);
137
138 let frame_base = out.len();
139 if let Some(fcs) = header.content_size {
140 if fcs as u128 + frame_base as u128 > self.limit as u128 {
141 return Err(Error::OutputTooLarge);
142 }
143 out.reserve(fcs.min(MAX_PREALLOC) as usize);
144 }
145 let block_size_max = header.window_size.min(BLOCK_SIZE_MAX as u64) as usize;
146
147 let mut ctx = FrameContext::with_dictionary(dict);
148 let mut input = &src[header.header_len..];
149 loop {
150 let bh = input.get(..3).ok_or(Error::SrcSizeWrong)?;
151 let raw = u32::from(bh[0]) | u32::from(bh[1]) << 8 | u32::from(bh[2]) << 16;
152 input = &input[3..];
153 let last = raw & 1 != 0;
154 let block_type = (raw >> 1) & 3;
155 let size = (raw >> 3) as usize;
156
157 match block_type {
158 0 => {
160 if size > block_size_max {
161 return Err(Error::Corrupted("block size exceeds block size limit"));
162 }
163 let data = input.get(..size).ok_or(Error::SrcSizeWrong)?;
164 if out.len() + size > self.limit {
165 return Err(Error::OutputTooLarge);
166 }
167 out.extend_from_slice(data);
168 input = &input[size..];
169 }
170 1 => {
172 if size > block_size_max {
173 return Err(Error::Corrupted("block size exceeds block size limit"));
174 }
175 let byte = *input.first().ok_or(Error::SrcSizeWrong)?;
176 if out.len() + size > self.limit {
177 return Err(Error::OutputTooLarge);
178 }
179 out.resize(out.len() + size, byte);
180 input = &input[1..];
181 }
182 2 => {
184 if size > block_size_max {
185 return Err(Error::Corrupted("block size exceeds block size limit"));
186 }
187 let data = input.get(..size).ok_or(Error::SrcSizeWrong)?;
188 block::decode_compressed_block(
189 &mut ctx,
190 data,
191 out,
192 frame_base,
193 dict_content,
194 block_size_max,
195 self.limit,
196 )?;
197 input = &input[size..];
198 }
199 _ => return Err(Error::BlockTypeInvalid),
200 }
201
202 if last {
203 break;
204 }
205 }
206
207 if let Some(fcs) = header.content_size {
208 if (out.len() - frame_base) as u64 != fcs {
209 return Err(Error::FrameContentSizeMismatch);
210 }
211 }
212
213 if header.has_checksum {
214 let stored = input.get(..4).ok_or(Error::SrcSizeWrong)?;
215 let expected = u32::from_le_bytes(stored.try_into().unwrap());
216 let actual = xxh64(&out[frame_base..], 0) as u32;
217 if expected != actual {
218 return Err(Error::ChecksumMismatch { expected, actual });
219 }
220 input = &input[4..];
221 }
222
223 Ok(input)
224 }
225}
226
227pub fn decompress(src: &[u8]) -> Result<Vec<u8>, Error> {
234 DecodeOptions::new().decompress(src)
235}
236
237pub fn decompress_with_limit(src: &[u8], limit: usize) -> Result<Vec<u8>, Error> {
241 DecodeOptions::new().limit(limit).decompress(src)
242}