use super::{Attheme, Color, IndexMap, Wallpaper};
use std::borrow::Borrow;
fn parse_hex(string: &str) -> Option<u8> {
u8::from_str_radix(string, 16).ok()
}
#[allow(clippy::cast_possible_truncation)]
fn parse_color(value: &str) -> Option<Color> {
if let Ok(value) = value.parse::<i32>() {
#[allow(clippy::cast_sign_loss)]
let value = value as u32;
let blue = value as u8;
let green = (value >> 8) as u8;
let red = (value >> (8 * 2)) as u8;
let alpha = (value >> (8 * 3)) as u8;
Some(Color::new(red, green, blue, alpha))
} else if value.starts_with('#') {
if value.len() == 1 + 2 * 3 {
let red = parse_hex(&value[1..3])?;
let green = parse_hex(&value[3..5])?;
let blue = parse_hex(&value[5..7])?;
Some(Color::new(red, green, blue, 255))
} else if value.len() == 1 + 2 * 4 {
let alpha = parse_hex(&value[1..3])?;
let red = parse_hex(&value[3..5])?;
let green = parse_hex(&value[5..7])?;
let blue = parse_hex(&value[7..9])?;
Some(Color::new(red, green, blue, alpha))
} else {
None
}
} else {
None
}
}
pub fn from_bytes(contents: &[u8]) -> Attheme {
let mut variables = IndexMap::new();
let mut wallpaper: Option<Wallpaper> = None;
for (index, line) in contents.split(|x| *x == b'\n').enumerate() {
if let Some(bytes) = &mut wallpaper {
if line.starts_with(b"WPE") {
bytes.pop();
break;
}
bytes.extend_from_slice(line);
bytes.push(b'\n');
continue;
}
if line.starts_with(b"WPS") {
let capacity = contents.len() - index - "\nWPE\n".len();
wallpaper = Some(Vec::with_capacity(capacity));
}
let raw_line = String::from_utf8_lossy(line);
let line = if let Some(index) = raw_line.find("//") {
&raw_line[..index]
} else {
raw_line.borrow()
};
let (variable, value) = if let Some(index) = line.find('=') {
(&line[..index], &line[index + 1..])
} else {
continue;
};
if variable == "wallpaperFileOffset" {
continue;
}
if let Some(value) = parse_color(value) {
variables.insert(variable.to_string(), value);
}
}
Attheme {
variables,
wallpaper,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ignores_invalid_variables() {
use indexmap::indexmap;
let contents = b"foo=#12345678\n\
bar\n\
quux= #123 \n\
spam=eggs";
assert_eq!(
from_bytes(contents),
Attheme {
variables: indexmap! {
String::from("foo") => Color::new(0x34, 0x56, 0x78, 0x12),
},
wallpaper: None,
}
)
}
#[test]
fn does_not_parse_variables_in_wallpaper() {
let contents = b"WPS\n\
foo=#123456\n\
bar=-1\n\
WPE\n";
assert_eq!(
from_bytes(contents),
Attheme {
variables: IndexMap::new(),
wallpaper: Some(
b"foo=#123456\n\
bar=-1"
.to_vec()
),
}
)
}
}