pub extern crate byteorder;
extern crate flate2;
use byteorder::LittleEndian;
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::io;
use std::io::BufRead;
pub trait WriteExt {
fn write_u8(&mut self, value: u8) -> io::Result<()>;
fn write_u16(&mut self, value: u16) -> io::Result<()>;
fn write_u32(&mut self, value: u32) -> io::Result<()>;
fn write_i32(&mut self, value: i32) -> io::Result<()>;
}
impl<T> WriteExt for T
where T: io::Write
{
fn write_u8(&mut self, value: u8) -> io::Result<()> {
WriteBytesExt::write_u8(self, value)
}
fn write_u16(&mut self, value: u16) -> io::Result<()> {
WriteBytesExt::write_u16::<LittleEndian>(self, value)
}
fn write_u32(&mut self, value: u32) -> io::Result<()> {
WriteBytesExt::write_u32::<LittleEndian>(self, value)
}
fn write_i32(&mut self, value: i32) -> io::Result<()> {
WriteBytesExt::write_i32::<LittleEndian>(self, value)
}
}
pub trait ReadExt {
fn read_u8(&mut self) -> io::Result<u8>;
fn read_i8(&mut self) -> io::Result<i8>;
fn read_u16(&mut self) -> io::Result<u16>;
fn read_i16(&mut self) -> io::Result<i16>;
fn read_u32(&mut self) -> io::Result<u32>;
fn read_i32(&mut self) -> io::Result<i32>;
fn read_f32(&mut self) -> io::Result<f32>;
fn read_sized_str(&mut self, len: usize) -> io::Result<String>;
fn read_and_decompress(self) -> io::Result<Vec<u8>>;
}
pub trait ReadArrayExt<T: Sized, S: io::Read, E, F: Fn(&mut S) -> Result<T, E>> {
fn read_array(&mut self, count: usize, read_method: F) -> Result<Vec<T>, E>;
}
impl<T, S, E, F> ReadArrayExt<T, S, E, F> for S
where T: Sized,
S: io::Read,
F: Fn(&mut S) -> Result<T, E>
{
fn read_array(&mut self, count: usize, read_method: F) -> Result<Vec<T>, E> {
let mut result: Vec<T> = Vec::new();
for _ in 0..count {
result.push(try!(read_method(self)));
}
Ok(result)
}
}
const DECOMPRESSION_CHUNK_SIZE: usize = 16 * 1024;
impl<T> ReadExt for T
where T: io::Read
{
fn read_u8(&mut self) -> io::Result<u8> {
ReadBytesExt::read_u8(self)
}
fn read_i8(&mut self) -> io::Result<i8> {
ReadBytesExt::read_i8(self)
}
fn read_u16(&mut self) -> io::Result<u16> {
ReadBytesExt::read_u16::<LittleEndian>(self)
}
fn read_i16(&mut self) -> io::Result<i16> {
ReadBytesExt::read_i16::<LittleEndian>(self)
}
fn read_u32(&mut self) -> io::Result<u32> {
ReadBytesExt::read_u32::<LittleEndian>(self)
}
fn read_i32(&mut self) -> io::Result<i32> {
ReadBytesExt::read_i32::<LittleEndian>(self)
}
fn read_f32(&mut self) -> io::Result<f32> {
ReadBytesExt::read_f32::<LittleEndian>(self)
}
fn read_sized_str(&mut self, len: usize) -> io::Result<String> {
let mut buffer = vec![0u8; len];
try!(self.read_exact(&mut buffer));
let mut null_term = buffer.len();
for i in 0..buffer.len() {
if buffer[i] == 0 {
null_term = i;
break;
}
}
buffer.resize(null_term, 0u8);
Ok(try!(String::from_utf8(buffer)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "bad encoding"))))
}
fn read_and_decompress(mut self) -> io::Result<Vec<u8>> {
use flate2::Status;
use flate2::Decompress;
use flate2::Flush;
let mut compressed: Vec<u8> = Vec::new();
try!(self.read_to_end(&mut compressed));
let mut stream = io::Cursor::new(&compressed[..]);
let mut decompressed: Vec<u8> = Vec::new();
let mut buffer = [0u8; DECOMPRESSION_CHUNK_SIZE];
let mut decompressor = Decompress::new(false);
loop {
let last_out = decompressor.total_out();
let last_in = decompressor.total_in();
let (status, end_stream);
{
let input = try!(stream.fill_buf());
end_stream = input.is_empty();
let flush_type = if end_stream { Flush::Finish } else { Flush::None };
status = try!(decompressor.decompress(input, &mut buffer, flush_type)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "failed to decompress")));
}
let read = (decompressor.total_in() - last_in) as usize;
let written = (decompressor.total_out() - last_out) as usize;
decompressed.extend_from_slice(&buffer[0..written]);
stream.consume(read);
match status {
Status::Ok => {}
Status::BufError if !end_stream && written == 0 => continue,
Status::BufError | Status::StreamEnd => break,
}
}
Ok(decompressed)
}
}
#[cfg(test)]
mod tests {
use std::io;
use ::{ReadExt, WriteExt};
#[test]
fn test_read_byte() {
let mut cursor = io::Cursor::new("test".as_bytes());
assert_eq!('t' as u8, ReadExt::read_u8(&mut cursor).unwrap());
assert_eq!('e' as u8, ReadExt::read_u8(&mut cursor).unwrap());
assert_eq!('s' as u8, ReadExt::read_u8(&mut cursor).unwrap());
assert_eq!('t' as u8, ReadExt::read_u8(&mut cursor).unwrap());
assert!(ReadExt::read_u8(&mut cursor).is_err());
}
#[test]
fn test_read_sized_str() {
let data = "test\0\0\0\0".as_bytes();
assert_eq!("test".to_string(),
io::Cursor::new(data).read_sized_str(8).unwrap());
assert_eq!("test".to_string(),
io::Cursor::new(data).read_sized_str(4).unwrap());
assert_eq!("te".to_string(),
io::Cursor::new(data).read_sized_str(2).unwrap());
assert_eq!("".to_string(),
io::Cursor::new(data).read_sized_str(0).unwrap());
assert!(io::Cursor::new(data).read_sized_str(9).is_err());
}
#[test]
fn test_write_u8() {
let buf = vec![];
let mut cursor = ::std::io::Cursor::new(buf);
assert!(cursor.write_u8(147u8).is_ok());
let v = cursor.into_inner();
let mut c = ::std::io::Cursor::new(v);
assert_eq!(147u8, ReadExt::read_u8(&mut c).unwrap());
}
#[test]
fn test_write_u16() {
let buf = vec![];
let mut cursor = ::std::io::Cursor::new(buf);
assert!(cursor.write_u16(147u16).is_ok());
let v = cursor.into_inner();
let mut c = ::std::io::Cursor::new(v);
assert_eq!(147u16, ReadExt::read_u16(&mut c).unwrap());
}
#[test]
fn test_write_u32() {
let buf = vec![];
let mut cursor = ::std::io::Cursor::new(buf);
assert!(cursor.write_u32(147u32).is_ok());
let v = cursor.into_inner();
let mut c = ::std::io::Cursor::new(v);
assert_eq!(147u32, ReadExt::read_u32(&mut c).unwrap());
}
#[test]
fn test_write_i32() {
let buf = vec![];
let mut cursor = ::std::io::Cursor::new(buf);
assert!(cursor.write_i32(147i32).is_ok());
let v = cursor.into_inner();
let mut c = ::std::io::Cursor::new(v);
assert_eq!(147i32, ReadExt::read_i32(&mut c).unwrap());
}
}