use crate::error::{PDFError, Result};
use crate::objects::Stream;
use crate::utils::hex2bytes;
use flate2::read::ZlibDecoder;
use std::io::Read;
fn ascii_85_decode(buf: &[u8]) -> Vec<u8> {
static ASCII_85_LOOKUP: [u8; 5] = [
1, 1, 2, 3, 4
];
let mut bytes = Vec::new();
let l = buf.len();
let mut t = [0u8; 5];
let mut w = 0;
for i in 0..l {
let b = buf[i];
if b == b'z' {
bytes.extend_from_slice([0u8; 4].as_slice());
continue;
}
if b == b'\n' || b == b'\r' || b == b'\t' || b == b' ' {
continue;
}
t[4 - w] = b - 33;
w += 1;
if w == 5 || i == l - 1 {
let mut value = 0u32;
for (i, v) in t.iter_mut().enumerate() {
value = value + (*v as u32) * 85u32.pow((i) as u32);
}
let k = value.to_be_bytes();
bytes.extend_from_slice(&k[0..ASCII_85_LOOKUP[w - 1] as usize]);
w = 0;
t.fill(0);
}
}
bytes
}
fn decode_stream_xx_decode(filter: &str, buf: &[u8]) -> Result<Vec<u8>> {
let bytes = match filter {
"FlateDecode" => {
let mut zlib_decoder = ZlibDecoder::new(buf);
let mut flate_bytes = Vec::new();
zlib_decoder.read_to_end(&mut flate_bytes)?;
flate_bytes
}
"ASCIIHexDecode" => hex2bytes(buf),
"ASCII85Decode" => ascii_85_decode(buf),
_ => return Err(PDFError::NotSupportFilter(filter.to_string()))
};
Ok(bytes)
}
pub(crate) fn decode_stream(stream: &Stream) -> Result<Vec<u8>> {
let filters = stream.get_filters();
let len = filters.len();
let mut bytes = Vec::new();
for i in (0..len).rev() {
let filter = &filters[i];
let slice = if bytes.is_empty() {
stream.as_slice()
} else {
bytes.as_slice()
};
bytes = decode_stream_xx_decode(filter, &slice)?;
}
Ok(bytes)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ascii_85_decode() {
let bytes = ascii_85_decode(b"z");
assert_eq!(bytes, [0u8; 4]);
let bytes = ascii_85_decode(b"z\n");
assert_eq!(bytes, [0u8; 4]);
let bytes = ascii_85_decode(b"87cURDn");
assert_eq!(bytes, b"Hello");
}
}