use std::io;
use std::io::BufRead;
use std::io::Read;
use std::iter;
use adler32::RollingAdler32;
use byteorder::LittleEndian;
use byteorder::ReadBytesExt;
use ::misc::*;
pub struct AdlerRead <Source: BufRead> {
source: Source,
adler: RollingAdler32,
byte_count: usize,
}
pub fn adler_verify_hash <
Source: BufRead,
PrefixFunction: Fn () -> String,
> (
prefix_function: PrefixFunction,
adler_read: & mut AdlerRead <Source>,
) -> Result <(), String> {
let calculated_hash =
adler_read.hash ();
let expected_hash =
io_result_with_prefix (
|| format! (
"{}Error reading adler32 checksum: ",
prefix_function ()),
adler_read.read_u32::<LittleEndian> (),
) ?;
if calculated_hash != expected_hash {
return Err (
format! (
"{}Adler32 hash calculated {} but expected {}, at position \
0x{:x}",
prefix_function (),
calculated_hash,
expected_hash,
adler_read.byte_count - 4));
}
Ok (())
}
pub fn adler_verify_hash_and_eof <
Source: BufRead,
PrefixFunction: Fn () -> String,
> (
prefix_function: PrefixFunction,
mut adler_read: AdlerRead <Source>,
) -> Result <(), String> {
adler_verify_hash (
& prefix_function,
& mut adler_read,
) ?;
let mut byte_buffer: [u8; 1] = [0u8; 1];
let bytes_read =
io_result_with_prefix (
|| format! (
"{}Error checking for end of file: ",
& prefix_function ()),
adler_read.read (
& mut byte_buffer),
) ?;
if bytes_read != 0 {
return Err (
format! (
"{}Extra data at end of file",
prefix_function ()));
}
Ok (())
}
impl <Source: BufRead> AdlerRead <Source> {
pub fn new (
source: Source,
) -> AdlerRead <Source> {
AdlerRead {
source: source,
adler: RollingAdler32::new (),
byte_count: 0,
}
}
pub fn hash (& self) -> u32 {
self.adler.hash ()
}
pub fn update (
& mut self,
data: & [u8],
) {
self.adler.update_buffer (
data);
self.byte_count +=
data.len ();
}
}
impl <Source: BufRead> Read for AdlerRead <Source> {
fn read (
& mut self,
buffer: & mut [u8],
) -> Result <usize, io::Error> {
match self.source.read (
buffer) {
Ok (read_size) => {
self.adler.update_buffer (
& buffer [0 .. read_size]);
self.byte_count +=
read_size;
Ok (read_size)
},
Err (error) =>
Err (error),
}
}
}
impl <Source: BufRead> BufRead for AdlerRead <Source> {
fn fill_buf (
& mut self,
) -> Result <& [u8], io::Error> {
self.source.fill_buf ()
}
fn consume (
& mut self,
amount: usize,
) {
let mut buffer: Vec <u8> =
iter::repeat (0u8)
.take (amount)
.collect ();
self.source.read_exact (
& mut buffer,
).unwrap ();
self.adler.update_buffer (
& buffer);
self.byte_count +=
amount;
}
}