regashii/
etc.rs

1use std::path::Path;
2
3use utf16string::{LittleEndian, WString};
4
5use crate::{error, Format};
6
7const BOM_LE: &str = "\u{feff}";
8const BOM_BE: &str = "\u{ffef}";
9pub const SZ_INVALID_CHARS: &[char] = &['\n', '\r'];
10
11pub fn utf16_bytes_to_str(bytes: Vec<u8>) -> Option<String> {
12    let ws = WString::<LittleEndian>::from_utf16(bytes).ok()?;
13    Some(ws.to_utf8().trim_end_matches('\0').to_string())
14}
15
16pub fn ascii_bytes_to_str(bytes: Vec<u8>) -> Option<String> {
17    Some(String::from_utf8(bytes).ok()?.trim_end_matches('\0').to_string())
18}
19
20pub fn str_to_utf16_bytes(data: &str) -> Vec<u8> {
21    let ws = WString::<LittleEndian>::from(data.trim_end_matches('\0'));
22    let mut bytes = ws.into_bytes();
23    bytes.push(0);
24    bytes.push(0);
25    bytes
26}
27
28pub fn str_to_ascii_bytes(data: &str) -> Vec<u8> {
29    let mut bytes: Vec<_> = data.trim_end_matches('\0').chars().map(|c| c as u8).collect();
30    bytes.push(0);
31    bytes
32}
33
34pub fn read_bytes(bytes: Vec<u8>) -> Option<String> {
35    if let Ok(raw) = String::from_utf8(bytes.clone()) {
36        return Some(raw);
37    }
38
39    if let Ok(raw) = WString::from_utf16le(bytes.clone()) {
40        let utf8 = raw.to_utf8();
41        return Some(utf8.strip_prefix(BOM_LE).map(|x| x.to_string()).unwrap_or(utf8));
42    }
43
44    if let Ok(raw) = WString::from_utf16be(bytes) {
45        let utf8 = raw.to_utf8();
46        return Some(utf8.strip_prefix(BOM_BE).map(|x| x.to_string()).unwrap_or(utf8));
47    }
48
49    None
50}
51
52pub fn write_file<P: AsRef<Path>>(file: P, content: String, format: Format) -> Result<(), error::Write> {
53    match format {
54        Format::Regedit4 | Format::Wine2 => {
55            std::fs::write(file, content)?;
56        }
57        Format::Regedit5 => {
58            let content = format!("{BOM_LE}{content}");
59            let utf16 = WString::<LittleEndian>::from(&content);
60            std::fs::write(file, utf16.as_bytes())?;
61        }
62    }
63
64    Ok(())
65}