use crate::common::*;
use crate::enums::*;
use crate::RegValue;
use std::convert::TryInto;
use std::ffi::{OsStr, OsString};
use std::io;
use std::os::windows::ffi::OsStringExt;
use std::slice;
use windows_sys::Win32::Foundation;
pub trait FromRegValue: Sized {
fn from_reg_value(val: &RegValue) -> io::Result<Self>;
}
impl FromRegValue for String {
fn from_reg_value(val: &RegValue) -> io::Result<String> {
match val.vtype {
REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
let words = unsafe {
#[allow(clippy::cast_ptr_alignment)]
slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
};
let mut s = String::from_utf16_lossy(words);
while s.ends_with('\u{0}') {
s.pop();
}
if val.vtype == REG_MULTI_SZ {
return Ok(s.replace('\u{0}', "\n"));
}
Ok(s)
}
_ => werr!(Foundation::ERROR_BAD_FILE_TYPE),
}
}
}
impl FromRegValue for Vec<String> {
fn from_reg_value(val: &RegValue) -> io::Result<Vec<String>> {
match val.vtype {
REG_MULTI_SZ => {
let words = unsafe {
slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
};
let mut s = String::from_utf16_lossy(words);
while s.ends_with('\u{0}') {
s.pop();
}
let v: Vec<String> = s.split('\u{0}').map(|x| x.to_owned()).collect();
Ok(v)
}
_ => werr!(Foundation::ERROR_BAD_FILE_TYPE),
}
}
}
impl FromRegValue for OsString {
fn from_reg_value(val: &RegValue) -> io::Result<OsString> {
match val.vtype {
REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
let mut words = unsafe {
#[allow(clippy::cast_ptr_alignment)]
slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
};
while let Some(0) = words.last() {
words = &words[0..words.len() - 1];
}
let s = OsString::from_wide(words);
Ok(s)
}
_ => werr!(Foundation::ERROR_BAD_FILE_TYPE),
}
}
}
impl FromRegValue for Vec<OsString> {
fn from_reg_value(val: &RegValue) -> io::Result<Vec<OsString>> {
match val.vtype {
REG_MULTI_SZ => {
let mut words = unsafe {
slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
};
while let Some(0) = words.last() {
words = &words[0..words.len() - 1];
}
let v: Vec<OsString> = words
.split(|ch| *ch == 0u16)
.map(OsString::from_wide)
.collect();
Ok(v)
}
_ => werr!(Foundation::ERROR_BAD_FILE_TYPE),
}
}
}
macro_rules! try_from_reg_value_int {
($val:expr, $map:expr) => {
$val.bytes
.as_slice()
.try_into()
.map($map)
.map_err(|_| io::Error::from_raw_os_error(Foundation::ERROR_INVALID_DATA as i32))
};
}
impl FromRegValue for u32 {
fn from_reg_value(val: &RegValue) -> io::Result<u32> {
match val.vtype {
REG_DWORD => try_from_reg_value_int!(val, u32::from_ne_bytes),
REG_DWORD_BIG_ENDIAN => try_from_reg_value_int!(val, u32::from_be_bytes),
_ => werr!(Foundation::ERROR_BAD_FILE_TYPE),
}
}
}
impl FromRegValue for u64 {
fn from_reg_value(val: &RegValue) -> io::Result<u64> {
match val.vtype {
REG_QWORD => try_from_reg_value_int!(val, u64::from_ne_bytes),
_ => werr!(Foundation::ERROR_BAD_FILE_TYPE),
}
}
}
pub trait ToRegValue {
fn to_reg_value(&self) -> RegValue;
}
macro_rules! to_reg_value_sz {
($t:ty$(, $l:lifetime)*) => {
impl<$($l,)*> ToRegValue for $t {
fn to_reg_value(&self) -> RegValue {
RegValue {
bytes: v16_to_v8(&to_utf16(self)),
vtype: REG_SZ,
}
}
}
}
}
to_reg_value_sz!(String);
to_reg_value_sz!(&'a str, 'a);
to_reg_value_sz!(OsString);
to_reg_value_sz!(&'a OsStr, 'a);
macro_rules! to_reg_value_multi_sz {
($t:ty$(, $l:lifetime)*) => {
impl<$($l,)*> ToRegValue for Vec<$t> {
fn to_reg_value(&self) -> RegValue {
let mut os_strings = self
.into_iter()
.map(to_utf16)
.collect::<Vec<_>>()
.concat();
os_strings.push(0);
RegValue {
bytes: v16_to_v8(&os_strings),
vtype: REG_MULTI_SZ,
}
}
}
}
}
to_reg_value_multi_sz!(String);
to_reg_value_multi_sz!(&'a str, 'a);
to_reg_value_multi_sz!(OsString);
to_reg_value_multi_sz!(&'a OsStr, 'a);
impl ToRegValue for u32 {
fn to_reg_value(&self) -> RegValue {
let bytes: Vec<u8> =
unsafe { slice::from_raw_parts((self as *const u32) as *const u8, 4).to_vec() };
RegValue {
bytes,
vtype: REG_DWORD,
}
}
}
impl ToRegValue for u64 {
fn to_reg_value(&self) -> RegValue {
let bytes: Vec<u8> =
unsafe { slice::from_raw_parts((self as *const u64) as *const u8, 8).to_vec() };
RegValue {
bytes,
vtype: REG_QWORD,
}
}
}