extern crate getopts; extern crate byteorder; extern crate pbr; use std::env; use std::fs; use std::io::BufReader; use std::io::prelude::*; use std::i32; use std::io::Cursor; use getopts::Options; use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian}; use pbr::{ProgressBar, Units}; fn main() { let args: Vec = env::args().collect(); let program = args[0].clone(); let mut opts = Options::new(); opts.optflag("c", "", "compress file"); opts.optflag("d", "", "decompress file"); opts.optflag("h", "help", "display this help and exit"); let matches = match opts.parse(&args[1..]) { Ok(m) => { m } Err(f) => { panic!(f.to_string()) } }; if matches.opt_present("help") { let brief = format!("Usage: {} [option] INPUT OUTPUT", program); print!("{}", opts.usage(&brief)); return; } if matches.opt_present("c") { let input = &matches.free[0]; let output = &matches.free[1]; compress(&input, &output); } else if matches.opt_present("d") { let input = &matches.free[0]; let output = &matches.free[1]; extract(&input, &output) } } fn compress(input: &String, output: &String) { let mut output_file = fs::File::create(output).unwrap(); let input_file = fs::File::open(input).unwrap(); let n_bytes = input_file.metadata().unwrap().len() as u64; let input_buf = BufReader::new(input_file); let mut i : i32 = 0; let mut pb = ProgressBar::new(n_bytes); pb.set_units(Units::Bytes); for b in input_buf.bytes() { let b = b.unwrap(); for n in 0..i32::MAX { if b == get_byte(n) { i = n; break; } } let mut index : Vec = vec![]; index.write_i32::(i).unwrap(); output_file.write_all(&index).unwrap(); pb.inc(); } } fn extract(input: &String, output: &String) { let mut input_file = fs::File::open(input).unwrap(); let n_bytes = input_file.metadata().unwrap().len() as u64; let mut output_file = fs::File::create(output).unwrap(); let mut buf = vec![0; 4]; let mut pb = ProgressBar::new(n_bytes); pb.set_units(Units::Bytes); loop { let size = input_file.read(&mut buf).unwrap(); if size <= 0 { break; } let mut c = Cursor::new(&buf); let index = c.read_i32::().unwrap(); output_file.write_all(&[get_byte(index)]).unwrap(); pb.add(size as u64); } } fn get_byte(id: i32) -> u8 { let pid : f64 = 4.0 * series(1, id) - 2.0 * series(4, id) - series(5, id) - series(6, id); let mut y : f64 = (pid - (pid as i32) as f64 + 1.0).abs(); y = 16.0 * (y - y.floor()); let first : u8 = y as u8; y = 16.0 * (y - y.floor()); let second : u8 = y as u8; (first << 4) | second } fn series(m: i32, id: i32) -> f64 { const EPS : f64 = 1e-17; let mut ak : f64; let mut s : f64 = 0.0; let mut t : f64; for k in 0..id { ak = (8 * k + m) as f64; t = expm((id - k) as f64, ak); s = s + t / ak; s = s - (s as i32) as f64; } for k in id..id + 101 { ak = (8 * k + m) as f64; t = 16f64.powi(id - k) / ak; if t < EPS { break; } s = s + t; s = s - (s as i32) as f64; } s } fn expm(p: f64, ak: f64) -> f64 { const NTP : usize = 25; let mut tp = vec![1f64; NTP]; let mut i : i32 = 0; let mut p1 : f64 = p; let mut pt : f64; let mut r : f64 = 1.0; for n in 1..NTP { tp[n] = 2.0 * tp[n - 1]; } if ak == 1.0 { return 0.0; } for n in 0..NTP { if tp[n] > p { i = n as i32; break; } } pt = tp[(i - 1) as usize]; for _ in 1..i + 1 { if p1 >= pt { r = 16.0 * r; r = r - ((r / ak) as i32) as f64 * ak; p1 = p1 - pt; } pt = 0.5 * pt; if pt >= 1.0 { r = r * r; r = r - ((r / ak) as i32) as f64 * ak; } } r }