/*
This file is responsible for handling config IO.
Since the config is stored in the binary of the program,
a few hacks have to be made to get it to work.
*/
// use crate::helpers::SliceBetween;
use std::env;
use std::fs::{self, File};
use std::io::{self, Write};
/* impl SliceBetween for String {
fn slice_between(&self, start: &str, end: &str) -> Option<&str> {
Some(&self[self.find(start)? + start.len()..self.find(end)? + end.len()])
}
} */
// The reference string cannot be its own constant since it could change the data section,
// and it cannot be used with the concat! macro.
const CONFIG: &'static str = "----CONFIG-REF-START----00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
// Just to be safe (making sure it doesn't go into the data section) I am returning a non-static string
pub fn get_config() -> io::Result<&'static str> {
let mut len = None;
for (i, c) in CONFIG[24 /* length of reference */..].chars().enumerate() {
if c == '0' {
if len.is_none() {
len = Some(i);
}
} else if len.is_some() {
len = None;
}
}
if let Some(i) = len {
return Ok(&CONFIG[24..24 + i]);
}
Err(io::Error::new(
io::ErrorKind::Other,
"Could not locate config.",
))
}
pub fn new_config(config: &str) -> io::Result<()> {
// let mut new = String::new();
// This SHOULDN'T be a const to avoid potentially mixing it with the original reference
if config.len() > 2024 {
return Err(io::Error::new(
io::ErrorKind::Other,
"Config is too large. It must be no more than 2024 bytes.",
));
}
let conf_text = "----CONFIG-REF-START----";
if config.contains(conf_text) {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Config contains invalid string '{}'.", conf_text),
));
}
let exe_loc = env::current_exe()?;
let current = fs::read(&exe_loc)?;
let mut new = Vec::new();
let mut index = None;
for i in 0..current.len() {
// 24 is the length of the ----CONFIG-REF-START---- text
if current[i..i + 24] == *conf_text.as_bytes() {
index = Some(i);
break;
}
}
if let Some(i) = index {
// println!("i: {}", i);
new.extend_from_slice(¤t[0..i]);
let new_out = conf_text.to_owned()
+ config
+ &"0".repeat(2024 /* Number of bytes avaliable to the config */ - config.len());
// println!("New out len: {}", new_out.len());
new.extend_from_slice(new_out.as_bytes());
new.extend_from_slice(¤t[i + 2048..]);
/* if new.len() != current.len() {
panic!()
} */
fs::rename(&exe_loc, exe_loc.to_str().unwrap().to_owned() + ".old")?;
File::create(exe_loc)?.write_all(&new)?;
return Ok(());
}
Err(io::Error::new(
io::ErrorKind::Other,
"Could not locate config.",
))
}