use std::fs::File;
use argh::FromArgs;
use std::io::stdin;
use std::path::PathBuf;
use std::io::prelude::*;
use std::num::Wrapping;
use byteorder::{ByteOrder, LittleEndian};
pub enum Bits {
U32,
U8
}
fn default_bits() -> Bits {
Bits::U32
}
fn bits_from_str(_value: &str) -> Result<Bits, String> {
return match _value {
"32" => { Ok(Bits::U32) },
"8" => { Ok(Bits::U8) },
_ => { Err("value of argument 'bits' must be 8 or 32.".parse().unwrap()) }
}
}
#[derive(FromArgs)]
pub struct Args {
#[argh(option, from_str_fn(bits_from_str), default = "default_bits()", short = 'b')]
pub bits: Bits,
#[argh(positional)]
pub paths: Vec<PathBuf>,
}
const BUF_LEN: usize = 4096;
pub fn run(args: Args) -> Result<(), &'static str> {
if args.paths.is_empty() {
return checksum_from_stdin(&args.bits);
} else if args.paths.len() == 1 && args.paths[0].to_str().unwrap() == "-" {
return checksum_from_stdin(&args.bits);
} else {
for path in args.paths {
let mut file = File::open(&path).unwrap();
let mut buffer = [0u8; BUF_LEN];
match args.bits {
Bits::U32 => {
let fsize = file.metadata().unwrap().len();
if fsize % 4 != 0 {
return Err("file length invalid, not a multiple of 4");
}
let mut c32 = Checksum32::new();
loop {
let read_count = file.read(&mut buffer).unwrap();
c32.write(&buffer[..read_count]);
if read_count != BUF_LEN {
break;
}
}
println!("{:08X} {}", c32.sum(), &path.to_str().unwrap())
},
Bits::U8 => {
let mut c8 = Checksum8::new();
loop {
let read_count = file.read(&mut buffer).unwrap();
c8.write(&buffer[..read_count]);
if read_count != BUF_LEN {
break;
}
}
println!("{:02X} {}", c8.sum(), &path.to_str().unwrap())
}
}
}
}
return Ok(());
}
fn checksum_from_stdin(bits: &Bits) -> Result<(), &'static str> {
let mut buf = Vec::new();
match stdin().read_to_end(&mut buf) {
Ok(_) => { }
Err(err) => {panic!("Error: {}", err)}
}
match bits {
Bits::U32 => {
let fsize = buf.len();
if fsize % 4 != 0 {
return Err("file length invalid, not a multiple of 4");
}
let mut c32 = Checksum32::new();
c32.write(&buf[..]);
println!("{:08X} {}", c32.sum(), "-")
},
Bits::U8 => {
let mut c8 = Checksum8::new();
c8.write(&buf[..]);
println!("{:02X} {}", c8.sum(), "-")
}
}
return Ok(());
}
struct Checksum8 {
state: Wrapping<u8>
}
impl Checksum8 {
pub fn new() -> Self {
Checksum8 {
state: Wrapping(0u8)
}
}
pub fn write(&mut self, bytes: &[u8]) {
for x in bytes.iter() {
self.state += x & 0xff;
}
}
pub fn sum(&self) -> u8 {
return self.state.0
}
}
struct Checksum32 {
state: Wrapping<u32>
}
impl Checksum32 {
pub fn new() -> Self {
Checksum32 {
state: Wrapping(0u32)
}
}
pub fn write(&mut self, bytes: &[u8]) {
for x in (0..bytes.len()).step_by(4) {
self.state += LittleEndian::read_u32(&bytes[x..x+4]);
}
}
pub fn sum(&self) -> u32 {
return self.state.0
}
}