diff --git a/Cargo.toml b/Cargo.toml index e686cc2..9dc7166 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uwucodec" -version = "0.1.0" +version = "0.1.1" edition = "2018" license = "Apache-2.0" authors = ["trivernis "] diff --git a/src/bin/uwudecode.rs b/src/bin/uwudecode.rs index 010ab14..28a6b2d 100644 --- a/src/bin/uwudecode.rs +++ b/src/bin/uwudecode.rs @@ -1,8 +1,9 @@ -use std::fs::{read_to_string, write}; +use std::fs::OpenOptions; use std::io; +use std::io::{BufReader, BufWriter, Write}; use std::path::PathBuf; use structopt::StructOpt; -use uwucodec::decode; +use uwucodec::decode_stream; #[derive(StructOpt, Debug)] #[structopt()] @@ -17,7 +18,14 @@ struct Opt { } fn main() -> io::Result<()> { let opt: Opt = Opt::from_args(); - let encoded_data = read_to_string(opt.input)?; - let data = decode(&encoded_data); - write(opt.output, data) + let input_file = OpenOptions::new().read(true).open(opt.input)?; + let mut input_reader = BufReader::new(input_file); + let output_file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(opt.output)?; + let mut output_writer = BufWriter::new(output_file); + decode_stream(&mut input_reader, &mut output_writer)?; + output_writer.flush() } diff --git a/src/bin/uwuencode.rs b/src/bin/uwuencode.rs index 5413ea7..1085f2c 100644 --- a/src/bin/uwuencode.rs +++ b/src/bin/uwuencode.rs @@ -1,8 +1,9 @@ -use std::fs::{read, write}; +use std::fs::OpenOptions; use std::io; +use std::io::{BufReader, BufWriter, Write}; use std::path::PathBuf; use structopt::StructOpt; -use uwucodec::encode; +use uwucodec::encode_stream; #[derive(StructOpt, Debug)] #[structopt()] @@ -17,7 +18,14 @@ struct Opt { } fn main() -> io::Result<()> { let opt: Opt = Opt::from_args(); - let data = read(opt.input)?; - let encoded_data = encode(&data); - write(opt.output, encoded_data) + let input_file = OpenOptions::new().read(true).open(opt.input)?; + let mut input_reader = BufReader::new(input_file); + let output_file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(opt.output)?; + let mut output_writer = BufWriter::new(output_file); + encode_stream(&mut input_reader, &mut output_writer)?; + output_writer.flush() } diff --git a/src/lib.rs b/src/lib.rs index e3da810..e122b27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ use std::cell::RefCell; use std::collections::HashMap; +use std::io::{BufRead, Read, Write}; static VALUE_MAPPINGS: [&str; 16] = [ "uwu", "owo", "umu", "nya", "omo", "o_o", "q_p", "u_u", "o~o", "UwU", "OwO", "UmU", "OmO", @@ -27,6 +28,19 @@ static VALUE_MAPPINGS: [&str; 16] = [ thread_local! { static WORD_MAP: RefCell> = RefCell::new(get_word_map()); } static SEPARATOR: &str = " "; +/// Encodes bytes from a reader to a sink writer +pub fn encode_stream(src: &mut R, sink: &mut W) -> std::io::Result<()> { + let mut buf = [0u8; 1024]; + while let Ok(num_bytes) = src.read(&mut buf) { + if num_bytes == 0 { + break; + } + sink.write_all(encode(&buf[0..num_bytes]).as_bytes())?; + } + + Ok(()) +} + /// Encodes into the best encoding in existence pub fn encode<'a, I: IntoIterator + 'a>(data: I) -> String { data.into_iter() @@ -43,6 +57,19 @@ fn encode_byte(byte: u8) -> [&'static str; 2] { ] } +/// Decodes a stream of bytes into the raw data +pub fn decode_stream(src: &mut R, sink: &mut W) -> std::io::Result<()> { + let mut buf = String::new(); + while let Ok(num_bytes) = src.read_line(&mut buf) { + if num_bytes == 0 { + break; + } + sink.write_all(&mut decode(&buf))?; + } + + Ok(()) +} + /// Decodes the best encoding in existence back into bytes pub fn decode>(encoded_data: S) -> Vec { let mut data = Vec::new(); @@ -78,7 +105,8 @@ fn get_word_map() -> HashMap<&'static str, u8> { #[cfg(test)] mod tests { - use crate::{decode, encode}; + use crate::{decode, decode_stream, encode, encode_stream}; + use std::io::Cursor; #[test] fn it_encodes() { @@ -87,6 +115,15 @@ mod tests { assert_eq!(encoded, String::from("uwu uwu owo uwu uwu OmO")) } + #[test] + fn it_stream_encodes() { + let data = vec![0u8, 16u8, 12u8]; + let mut output_buf = Vec::new(); + encode_stream(&mut data.as_slice(), &mut output_buf).unwrap(); + let encoded = String::from_utf8(output_buf).unwrap(); + assert_eq!(encoded, String::from("uwu uwu owo uwu uwu OmO")) + } + #[test] fn it_decodes() { let encoded_data = String::from("uwu uwu owo uwu uwu OmO"); @@ -94,6 +131,14 @@ mod tests { assert_eq!(decoded, vec![0u8, 16u8, 12u8]) } + #[test] + fn it_stream_decodes() { + let mut data = Cursor::new(String::from("uwu uwu owo uwu uwu OmO")); + let mut output_buf = Vec::new(); + decode_stream(&mut data, &mut output_buf).unwrap(); + assert_eq!(output_buf, vec![0u8, 16u8, 12u8]) + } + #[test] fn it_encodes_100000() { let data = vec![0u8, 16u8, 12u8];