| 331 | } |
| 332 | |
| 333 | fn decode_string(symbols: &[Vec<u8>], encoded: &[u8]) -> Result<Vec<u8>, CodecError> { |
| 334 | let mut out = Vec::with_capacity(encoded.len() * 2); |
| 335 | let mut pos = 0; |
| 336 | |
| 337 | while pos < encoded.len() { |
| 338 | let byte = encoded[pos]; |
| 339 | pos += 1; |
| 340 | |
| 341 | if byte == ESCAPE { |
| 342 | // Next byte is a literal. |
| 343 | if pos >= encoded.len() { |
| 344 | return Err(CodecError::Corrupt { |
| 345 | detail: "FSST escape at end of encoded data".into(), |
| 346 | }); |
| 347 | } |
| 348 | out.push(encoded[pos]); |
| 349 | pos += 1; |
| 350 | } else { |
| 351 | // Symbol index. |
| 352 | let idx = byte as usize; |
| 353 | if idx >= symbols.len() { |
| 354 | return Err(CodecError::Corrupt { |
| 355 | detail: format!( |
| 356 | "FSST symbol index {idx} out of range (max {})", |
| 357 | symbols.len() |
| 358 | ), |
| 359 | }); |
| 360 | } |
| 361 | out.extend_from_slice(&symbols[idx]); |
| 362 | } |
| 363 | } |
| 364 | |
| 365 | Ok(out) |
| 366 | } |
| 367 | |
| 368 | #[cfg(test)] |
| 369 | mod tests { |