extern crate squash_sys;
#[macro_use]
mod common;
use std::ffi::{CStr, CString};
use std::io::prelude::*;
use std::{env, io, process, ptr};
use squash_sys::*;
const BUFFER_SIZE: usize = 1024 * 1024;
fn main() {
let return_code = real_main();
process::exit(return_code);
}
fn real_main() -> i32 {
let mut stderr = io::stderr();
let mut args = env::args().fuse();
let prog_name = args.next().unwrap();
let (stream_type, codec_name) = match (args.next(), args.next()) {
(Some(stream_type), Some(codec_name)) => {
let stream_type = match &stream_type[..] {
"c" => SquashStreamType::SQUASH_STREAM_COMPRESS,
"d" => SquashStreamType::SQUASH_STREAM_DECOMPRESS,
unknown_mode => {
let _ = writeln!(
stderr,
"Invalid mode '{}': must be 'c' or 'd'",
unknown_mode
);
return 1;
}
};
(stream_type, codec_name)
}
_ => {
let _ = writeln!(stderr, "USAGE: {} (c|d) CODEC", prog_name);
let _ = writeln!(
stderr,
"Input is read from stdin, output is written to stdout"
);
return 1;
}
};
let raw_codec_name = CString::new(codec_name.as_bytes()).unwrap();
let codec = unsafe { squash_get_codec(raw_codec_name.as_ptr()) };
if codec.is_null() {
let _ = writeln!(stderr, "Unable to find algorithm '{}'.", codec_name);
return 1;
}
let mut input = vec![0; BUFFER_SIZE];
let mut output = vec![0; BUFFER_SIZE];
let stream = unsafe { squash_stream_new(codec, stream_type, ptr::null::<u8>()) };
if stream.is_null() {
let _ = writeln!(stderr, "Failed to create stream.");
return 1;
}
defer!(unsafe { squash_object_unref(stream as *mut std::os::raw::c_void) });
let stream = unsafe { &mut *stream };
let stdin = io::stdin();
let mut stdin = stdin.lock();
let stdout = io::stdout();
let mut stdout = stdout.lock();
let mut res: SquashStatus::Type;
loop {
let input_len = stdin.read(&mut input).unwrap();
if input_len == 0 {
break;
}
stream.next_in = input.as_ptr();
stream.avail_in = input_len;
res = SquashStatus::SQUASH_PROCESSING;
while res == SquashStatus::SQUASH_PROCESSING {
stream.next_out = output.as_mut_ptr();
stream.avail_out = BUFFER_SIZE;
res = unsafe { squash_stream_process(stream) };
if res < 0 {
let reason = unsafe { CStr::from_ptr(squash_status_to_string(res)) };
let _ = writeln!(
stderr,
"Processing failed: {} ({})",
reason.to_string_lossy(),
res
);
return 1;
}
let output_size = (stream.next_out as usize) - (output.as_ptr() as usize);
stdout.write_all(&output[..output_size]).unwrap();
}
}
res = SquashStatus::SQUASH_PROCESSING;
while res == SquashStatus::SQUASH_PROCESSING {
stream.next_out = output.as_mut_ptr();
stream.avail_out = BUFFER_SIZE;
res = unsafe { squash_stream_finish(stream) };
if res < 0 {
let reason = unsafe { CStr::from_ptr(squash_status_to_string(res)) };
let _ = writeln!(
stderr,
"Finishing failed {} ({})",
reason.to_string_lossy(),
res
);
return 1;
}
let output_size = (stream.next_out as usize) - (output.as_ptr() as usize);
stdout.write_all(&output[..output_size]).unwrap();
}
return 0;
}