1use std::fs::File;
63use std::io::prelude::*;
64use std::io::Result;
65use std::io::{Error, ErrorKind};
66use std::io::SeekFrom;
67use std::string::FromUtf8Error;
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn read_write_test() {
75 println!("Hello from the PRTGN Development Team");
76
77 let text = "Hello from PRTGN Encoding!".to_string();
78 let og_txt = text.clone();
79 write("test.prtgn".to_string(), text).unwrap();
80
81 let decoded = read("test.prtgn".to_string()).unwrap().to_string();
82
83 println!("Original : {:?}", og_txt);
84
85 println!("Decoded : {:?}", decoded);
86 assert_eq!(decoded, og_txt);
87
88 println!("Test passed!");
89
90 std::fs::remove_file("test.prtgn").unwrap();
91 }
92}
93
94const XOR_KEY: u8 = 0x66;
95const FILE_HEADER: &[u8] = b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team | Version 0.2.0 | \x66 ";
96
97
98 pub fn write(filename: String, text: String) -> Result<()> {
110 {
111 let mut file = File::create(filename)?;
112
113 file.write_all(FILE_HEADER)?;
114
115
116 let encoded_bytes: Vec<u8> = text.as_bytes().iter().map(|byte| byte ^ XOR_KEY).collect();
117
118
119 file.write_all(&encoded_bytes)?;
120 }
121
122
123 Ok(())
124 }
125
126 pub fn read(filename: String) -> Result<String> {
140 let mut file = File::open(filename.clone())?;
141
142 let mut header_buffer = vec![0u8; FILE_HEADER.len()];
143 file.read_exact(&mut header_buffer)?;
144
145 let older_version = if header_buffer.starts_with(FILE_HEADER) {
146 "newest"
147 } else if header_buffer.starts_with(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team \x66 ") {
148 file.seek(SeekFrom::Start(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team \x66 ".len() as u64))?;
149 "0.1.3"
150 } else if header_buffer.starts_with(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team\x01\xFF\x00 ") {
151 file.seek(SeekFrom::Start(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team\x01\xFF\x00 ".len() as u64))?;
152 "0.1.2"
153 } else if header_buffer.starts_with(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team\x01\xFF\x00") {
154 file.seek(SeekFrom::Start(b"Encoded with PRTGN | https://github.com/PRTGN-Development-Team\x01\xFF\x00".len() as u64))?;
155 "0.1.1"
156 } else {
157 return Err(Error::new(ErrorKind::InvalidData, "Not a valid PRTGN encoded file."));
158 };
159
160 if older_version != "newest" {
161
162 println!("The version of encoding is outdated. Automatically rewriting the file after read.");
163 println!("---------------------------------------------");
164 print!("");
165
166 };
167
168 let mut encoded_buffer = Vec::new();
169 file.read_to_end(&mut encoded_buffer)?;
170
171
172 let decoded_byte: Vec<u8> = if older_version == "newest" {
173 encoded_buffer.iter().map(|byte| byte ^ XOR_KEY).collect()
174 } else if older_version == "0.1.3" {
175 encoded_buffer.iter().map(|byte| byte ^ 0x66).collect()
176 } else if older_version == "0.1.2" {
177 encoded_buffer.iter().map(|byte| byte ^ 0xA3).collect()
178 } else if older_version == "0.1.1" {
179 encoded_buffer.iter().map(|byte| byte ^ 0xA3).collect()
180 } else {
181 unreachable!()
182 };
183
184 write(filename, String::from_utf8(decoded_byte.clone()).unwrap())?;
185
186 String::from_utf8(decoded_byte).map_err(|e: FromUtf8Error| Error::new(ErrorKind::InvalidData, e.to_string()))
187 }