use std::fs::File;
use std::io::{BufReader, BufWriter, Error, ErrorKind, Read, Result, Write};
fn xor_process(input_path: &str, output_path: &str, password: &str) -> Result<()> {
let mut input_file = BufReader::new(File::open(input_path)?);
let mut output_file = BufWriter::new(File::create(output_path)?);
let password_bytes = password.as_bytes();
if password_bytes.is_empty() {
return Err(Error::new(
ErrorKind::InvalidInput,
"The password cannot be empty",
));
}
let mut buffer = [0u8; 8192]; let mut offset = 0;
loop {
let bytes_read = input_file.read(&mut buffer)?;
if bytes_read == 0 {
break;
}
for i in 0..bytes_read {
buffer[i] ^= password_bytes[(offset + i) % password_bytes.len()];
}
output_file.write_all(&buffer[..bytes_read])?;
offset += bytes_read;
}
Ok(())
}
pub fn encode(input_path: &str, password: &str, output_path: Option<&str>) -> Result<String> {
let output = match output_path {
Some(path) => path.to_string(),
None => format!("{}.rxor", input_path),
};
xor_process(input_path, &output, password)?;
Ok(output)
}
pub fn decode(input_path: &str, password: &str, output_path: Option<&str>) -> Result<String> {
let output = match output_path {
Some(path) => path.to_string(),
None => {
if input_path.ends_with(".rxor") {
input_path.strip_suffix(".rxor").unwrap().to_string()
} else {
input_path.to_string()
}
}
};
xor_process(input_path, &output, password)?;
Ok(output)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::{read, remove_file, write};
#[test]
fn test_encode_decode() {
let input = "test.txt";
let password = "password123";
let original_content = b"Test ReXOR";
write(input, original_content).unwrap();
let encoded = encode(input, password, None).unwrap();
let decoded = decode(&encoded, password, None).unwrap();
let result = read(decoded).unwrap();
assert_eq!(result, original_content);
remove_file(input).unwrap();
remove_file(encoded).unwrap();
}
}