use std::fs::File;
use std::io::prelude::*;
use std::io::Result;
use std::io::{Error, ErrorKind};
use std::io::SeekFrom;
use std::string::FromUtf8Error;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn read_write_test() {
println!("Hello from the PRTGN Development Team");
let text = "Hello from PRTGN Encoding!".to_string();
let og_txt = text.clone();
write("test.prtgn".to_string(), text).unwrap();
let decoded = read("test.prtgn".to_string()).unwrap().to_string();
println!("Original : {:?}", og_txt);
println!("Decoded : {:?}", decoded);
assert_eq!(decoded, og_txt);
println!("Test passed!");
std::fs::remove_file("test.prtgn").unwrap();
}
}
const XOR_KEY: u8 = 0x66;
const FILE_HEADER: &[u8] = b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team | Version 0.2.0 | \x66 ";
pub fn write(filename: String, text: String) -> Result<()> {
{
let mut file = File::create(filename)?;
file.write_all(FILE_HEADER)?;
let encoded_bytes: Vec<u8> = text.as_bytes().iter().map(|byte| byte ^ XOR_KEY).collect();
file.write_all(&encoded_bytes)?;
}
Ok(())
}
pub fn read(filename: String) -> Result<String> {
let mut file = File::open(filename.clone())?;
let mut header_buffer = vec![0u8; FILE_HEADER.len()];
file.read_exact(&mut header_buffer)?;
let older_version = if header_buffer.starts_with(FILE_HEADER) {
"newest"
} else if header_buffer.starts_with(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team \x66 ") {
file.seek(SeekFrom::Start(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team \x66 ".len() as u64))?;
"0.1.3"
} else if header_buffer.starts_with(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team\x01\xFF\x00 ") {
file.seek(SeekFrom::Start(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team\x01\xFF\x00 ".len() as u64))?;
"0.1.2"
} else if header_buffer.starts_with(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team\x01\xFF\x00") {
file.seek(SeekFrom::Start(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team\x01\xFF\x00".len() as u64))?;
"0.1.1"
} else {
return Err(Error::new(ErrorKind::InvalidData, "Not a valid PRTGN encoded file."));
};
if older_version != "newest" {
println!("The version of encoding is outdated. Automatically rewriting the file after read.");
println!("---------------------------------------------");
print!("");
};
let mut encoded_buffer = Vec::new();
file.read_to_end(&mut encoded_buffer)?;
let decoded_byte: Vec<u8> = if older_version == "newest" {
encoded_buffer.iter().map(|byte| byte ^ XOR_KEY).collect()
} else if older_version == "0.1.3" {
encoded_buffer.iter().map(|byte| byte ^ 0x66).collect()
} else if older_version == "0.1.2" {
encoded_buffer.iter().map(|byte| byte ^ 0xA3).collect()
} else if older_version == "0.1.1" {
encoded_buffer.iter().map(|byte| byte ^ 0xA3).collect()
} else {
unreachable!()
};
write(filename, String::from_utf8(decoded_byte.clone()).unwrap())?;
String::from_utf8(decoded_byte).map_err(|e: FromUtf8Error| Error::new(ErrorKind::InvalidData, e.to_string()))
}