conf_embed/
lib.rs

1/*
2This file is responsible for handling config IO.
3Since the config is stored in the binary of the program,
4a few hacks have to be made to get it to work.
5*/
6
7// use crate::helpers::SliceBetween;
8use std::env;
9use std::fs::{self, File};
10use std::io::{self, Write};
11
12/* impl SliceBetween for String {
13    fn slice_between(&self, start: &str, end: &str) -> Option<&str> {
14        Some(&self[self.find(start)? + start.len()..self.find(end)? + end.len()])
15    }
16} */
17
18// The reference string cannot be its own constant since it could change the data section,
19// and it cannot be used with the concat! macro.
20
21const CONFIG: &'static str = "----CONFIG-REF-START----00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
22
23// Just to be safe (making sure it doesn't go into the data section) I am returning a non-static string
24pub fn get_config() -> io::Result<&'static str> {
25    let mut len = None;
26    for (i, c) in CONFIG[24 /* length of reference */..].chars().enumerate() {
27        if c == '0' {
28            if len.is_none() {
29                len = Some(i);
30            }
31        } else if len.is_some() {
32            len = None;
33        }
34    }
35
36    if let Some(i) = len {
37        return Ok(&CONFIG[24..24 + i]);
38    }
39
40    Err(io::Error::new(
41        io::ErrorKind::Other,
42        "Could not locate config.",
43    ))
44}
45
46pub fn new_config(config: &str) -> io::Result<()> {
47    // let mut new = String::new();
48    // This SHOULDN'T be a const to avoid potentially mixing it with the original reference
49    if config.len() > 2024 {
50        return Err(io::Error::new(
51            io::ErrorKind::Other,
52            "Config is too large. It must be no more than 2024 bytes.",
53        ));
54    }
55
56    let conf_text = "----CONFIG-REF-START----";
57
58    if config.contains(conf_text) {
59        return Err(io::Error::new(
60            io::ErrorKind::Other,
61            format!("Config contains invalid string '{}'.", conf_text),
62        ));
63    }
64
65    let exe_loc = env::current_exe()?;
66    let current = fs::read(&exe_loc)?;
67    let mut new = Vec::new();
68    let mut index = None;
69    for i in 0..current.len() {
70        // 24 is the length of the ----CONFIG-REF-START---- text
71        if current[i..i + 24] == *conf_text.as_bytes() {
72            index = Some(i);
73            break;
74        }
75    }
76
77    if let Some(i) = index {
78        // println!("i: {}", i);
79        new.extend_from_slice(&current[0..i]);
80        let new_out = conf_text.to_owned()
81            + config
82            + &"0".repeat(2024 /* Number of bytes avaliable to the config */ - config.len());
83        // println!("New out len: {}", new_out.len());
84        new.extend_from_slice(new_out.as_bytes());
85        new.extend_from_slice(&current[i + 2048..]);
86
87        /* if new.len() != current.len() {
88            panic!()
89        } */
90
91        fs::rename(&exe_loc, exe_loc.to_str().unwrap().to_owned() + ".old")?;
92        File::create(exe_loc)?.write_all(&new)?;
93
94        return Ok(());
95    }
96
97    Err(io::Error::new(
98        io::ErrorKind::Other,
99        "Could not locate config.",
100    ))
101}