#![cfg(test)]
#![cfg(feature="std")]
use std::io::{self, Read, Cursor};
extern crate brotli_decompressor;
static ENCODED: &'static [u8] = b"\x1b\x03)\x00\xa4\xcc\xde\xe2\xb3 vA\x00\x0c";
enum State { First, Second, Third, Fourth }
struct R(State);
impl Read for R {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.0 {
State::First => {
buf[0] = ENCODED[0];
self.0 = State::Second;
return Ok(1);
}
State::Second => {
self.0 = State::Third;
return Err(io::Error::new(io::ErrorKind::WouldBlock, "foo"));
}
State::Third => {
self.0 = State::Fourth;
buf[..ENCODED.len() - 1].copy_from_slice(&ENCODED[1..]);
return Ok(ENCODED[1..].len());
}
State::Fourth => {
return Ok(0);
}
}
}
}
#[test]
fn test_would_block() {
let mut d = brotli_decompressor::Decompressor::new(R(State::First), 8192);
let mut b = [0; 8192];
assert_eq!(d.read(&mut b).unwrap_err().kind(), io::ErrorKind::WouldBlock);
assert!(d.read(&mut b).unwrap() != 0);
println!("{}", String::from_utf8(b.to_vec()).unwrap());
assert!(d.read(&mut b).unwrap() != 0);
assert_eq!(d.read(&mut b).unwrap(), 0);
}
static ENCODED2: &'static [u8] = include_bytes!("ipsum.brotli");
static DECODED: &'static str = include_str!("ipsum.raw");
enum State2 {
First,
Second,
Third,
Fourth,
Fifth,
Sixth,
Seventh,
Eighth,
}
struct R2 {
offset: usize,
len: usize,
state: State2,
}
impl R2 {
fn new() -> R2 {
R2 {
offset: 0,
len: 1,
state: State2::First,
}
}
}
impl Read for R2 {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.state {
State2::First => {
self.state = State2::Second;
let len = self.len;
buf[..len].copy_from_slice(&ENCODED2[self.offset..self.offset+len]);
self.offset += len;
self.len = 100;
return Ok(len);
}
State2::Second => {
self.state = State2::Third;
return Err(io::Error::new(io::ErrorKind::WouldBlock, "foo"));
}
State2::Third => {
self.state = State2::Fourth;
let len = self.len;
buf[..len].copy_from_slice(&ENCODED2[self.offset..self.offset+len]);
self.offset += len;
self.len = 100;
return Ok(len);
}
State2::Fourth => {
self.state = State2::Fifth;
return Err(io::Error::new(io::ErrorKind::WouldBlock, "foo"));
}
State2::Fifth => {
self.state = State2::Sixth;
let len = self.len;
buf[..len].copy_from_slice(&ENCODED2[self.offset..self.offset+len]);
self.offset += len;
self.len = 100;
return Ok(len);
}
State2::Sixth => {
self.state = State2::Seventh;
return Err(io::Error::new(io::ErrorKind::WouldBlock, "foo"));
}
State2::Seventh => {
self.state = State2::Eighth;
buf[..ENCODED2.len() - self.offset].copy_from_slice(&ENCODED2[self.offset..]);
return Ok(ENCODED2.len() - self.offset);
}
State2::Eighth => {
return Ok(0);
}
}
}
}
#[test]
fn would_block_more() {
let mut b = [0; 8192];
let mut bytes = vec![];
let mut d = brotli_decompressor::Decompressor::new(Cursor::new(ENCODED2), 8192);
let read = d.read(&mut b).unwrap();
assert!(read != 0);
bytes.extend_from_slice(&b[0..read]);
assert_eq!(d.read(&mut b).unwrap(), 0);
let reference_decoded = String::from_utf8(bytes).unwrap();
assert_eq!(reference_decoded, DECODED);
let r = R2::new();
let mut d = brotli_decompressor::Decompressor::new(r, 8192);
let mut bytes = vec![];
let mut b = [0; 8192];
assert_eq!(d.read(&mut b).unwrap_err().kind(), io::ErrorKind::WouldBlock);
assert_eq!(d.read(&mut b).unwrap_err().kind(), io::ErrorKind::WouldBlock);
let read = d.read(&mut b).unwrap();
assert!(read != 0);
bytes.extend_from_slice(&b[0..read]);
assert_eq!(d.read(&mut b).unwrap_err().kind(), io::ErrorKind::WouldBlock);
let read = d.read(&mut b).unwrap();
assert!(read != 0);
bytes.extend_from_slice(&b[0..read]);
assert_eq!(d.read(&mut b).unwrap(), 0);
let decoded = String::from_utf8(bytes).unwrap();
assert_eq!(decoded, reference_decoded);
}
#[test]
fn test_padding_2_rejection() {
let valid: &[u8] = &[
0x1b, 0x4a, 0x00, 0x00, 0xc4, 0xf4, 0xa4, 0x69, 0xbd, 0x79, 0x25, 0x2d, 0x22, 0xb4, 0x52,
0xea, 0x83, 0x0d, 0x38, 0x70, 0x68, 0xb2, 0x71, 0xc0, 0x41, 0x76, 0x1e, 0x36, 0xc6, 0xce,
0x13, 0x84, 0xe8, 0x36, 0xf2, 0x2a, 0x0c, 0xe7, 0x89, 0x68, 0x7a, 0x04, 0x49, 0x2f, 0xaa,
0xf7, 0x31, 0xa1, 0x9b, 0x0d, 0x48, 0xb7, 0xf0, 0x1f, 0x48, 0x33, 0x42, 0xa5, 0x9c, 0x31,
0x26, 0x97, 0xa9, 0xc6, 0xbe, 0x67, 0x85, 0x52, 0x02,
];
let mut d = brotli_decompressor::Decompressor::new(Cursor::new(valid), 4096);
let mut decoded = Vec::new();
d.read_to_end(&mut decoded).unwrap();
assert_eq!(
decoded,
b"the quick brown fox jumps over the lazy dog twice for redundancy and length",
);
for &(offset, xor) in &[(13usize, 0x01u8), (23, 0x01), (33, 0x55)] {
let mut corrupted = valid.to_vec();
corrupted[offset] ^= xor;
let mut d = brotli_decompressor::Decompressor::new(Cursor::new(corrupted.clone()), 4096);
let mut sink = Vec::new();
let err = d.read_to_end(&mut sink).map(|_| sink.clone()).err();
let kind = err.as_ref().map(|e| e.kind());
assert_eq!(
kind,
Some(io::ErrorKind::InvalidData),
"decoder must reject padding-bit corruption at offset {} xor {:#x} \
with InvalidData; got {:?}",
offset, xor, err.as_ref().map_or_else(|| format!("Ok({:?})", sink), |e| format!("{:?}", e)),
);
}
}