202 lines
4.1 KiB
Rust
202 lines
4.1 KiB
Rust
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<String> = 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<u8> = vec![];
|
|
|
|
index.write_i32::<LittleEndian>(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::<LittleEndian>().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
|
|
}
|