weakauras_codec_lib_compress/
lib.rs1#![forbid(unsafe_code)]
41#![deny(missing_docs)]
42
43mod bitfield;
44pub mod error;
46mod lookup_table;
47mod utils;
48
49pub use error::*;
50
51use self::bitfield::Bitfield;
52use lookup_table::{TableData, build_lookup_table};
53use std::borrow::Cow;
54use utils::{get_code, unescape_code};
55
56pub fn decompress(input: &[u8], max_size: usize) -> Result<Cow<'_, [u8]>, DecompressionError> {
88 let mut iter = input.iter();
89 match iter.next() {
90 Some(1) => return Ok(Cow::from(&input[1..])),
91 Some(3) => {}
92 _ => return Err(DecompressionError::InvalidPrefix),
93 }
94
95 let len = input.len();
96 if len < 5 {
97 return Err(DecompressionError::InputIsTooSmall);
98 }
99
100 let num_symbols = iter
101 .next()
102 .unwrap()
103 .checked_add(1)
104 .ok_or(DecompressionError::InvalidData)?;
105
106 let original_size = iter
107 .by_ref()
108 .take(3)
109 .map(|&byte| usize::from(byte))
110 .enumerate()
111 .fold(0, |acc, (i, byte)| acc + (byte << (i * 8)));
112
113 if original_size == 0 {
114 return Err(DecompressionError::InputIsTooSmall);
115 }
116
117 if original_size > max_size {
118 return Err(DecompressionError::DataExceedsMaxSize);
119 }
120
121 let mut codes = Vec::with_capacity(num_symbols as usize);
122 let mut result = Vec::with_capacity(original_size);
123
124 let mut bitfield = Bitfield::new();
125
126 let mut min_code_len = u8::MAX;
127 let mut max_code_len = u8::MIN;
128
129 for _ in 0..num_symbols {
131 let symbol = bitfield
132 .insert_and_extract_byte(*iter.next().ok_or(DecompressionError::UnexpectedEof)?);
133
134 loop {
135 bitfield
136 .insert(*iter.next().ok_or(DecompressionError::UnexpectedEof)?)
137 .map_err(|_| DecompressionError::InvalidData)?;
138
139 if let Some(v) = get_code(&mut bitfield)? {
140 let (code, code_len) = unescape_code(v.0, v.1);
141 min_code_len = core::cmp::min(min_code_len, code_len);
142 max_code_len = core::cmp::max(max_code_len, code_len);
143
144 codes.push((code, code_len, symbol));
145
146 break;
147 }
148 }
149 }
150 codes.sort_unstable_by(|a, b| a.1.cmp(&b.1).then_with(|| a.0.cmp(&b.0)));
151
152 let lut = build_lookup_table(&codes)?;
154
155 loop {
156 bitfield.fill_from_iterator(&mut iter);
157 let original_len = bitfield.get_len();
158
159 if bitfield.get_len() >= min_code_len {
160 let mut cursor = &lut[(bitfield.peek_byte()) as usize];
161
162 if bitfield.get_len() < cursor.code_length {
163 break;
164 }
165
166 let mut new_bitfield = bitfield;
167 while new_bitfield.get_len() >= cursor.code_length {
168 if cursor.code_length == 0 {
169 return Err(DecompressionError::InvalidData);
170 }
171
172 match cursor.data {
173 TableData::Reference(ref v) => {
174 new_bitfield.discard_bits(cursor.code_length);
175 cursor = &v[(new_bitfield.peek_byte()) as usize];
176 }
177 TableData::Symbol(s) => {
178 result.push(s);
179 if result.len() == original_size {
180 return Ok(Cow::from(result));
181 }
182
183 bitfield = new_bitfield;
184 bitfield.discard_bits(cursor.code_length);
185 break;
186 }
187 }
188 }
189 } else {
190 break;
191 }
192
193 if bitfield.get_len() == original_len {
194 return Err(DecompressionError::InvalidData);
195 }
196 }
197
198 if result.len() == original_size {
199 Ok(Cow::from(result))
200 } else {
201 Err(DecompressionError::InvalidData)
202 }
203}