pub const UNRESTRICTED: &str = "Microsoft.QuietHoursProfile.Unrestricted";
pub const PRIORITY_ONLY: &str = "Microsoft.QuietHoursProfile.PriorityOnly";
const PREFIX: &str = "Microsoft.QuietHoursProfile.";
#[derive(Debug, PartialEq, Eq)]
pub enum ProfileError {
NotFound,
LengthChangeRefused,
}
fn utf16le(s: &str) -> Vec<u8> {
s.encode_utf16().flat_map(|u| u.to_le_bytes()).collect()
}
pub fn locate(blob: &[u8]) -> Option<(usize, usize)> {
let needle = utf16le(PREFIX);
let pos = blob.windows(needle.len()).position(|w| w == needle)?;
let count = *blob.get(pos.checked_sub(1)?)? as usize;
if pos + count * 2 > blob.len() {
return None;
}
Some((pos, count))
}
pub fn read(blob: &[u8]) -> Option<String> {
let (pos, count) = locate(blob)?;
let units: Vec<u16> = (0..count)
.map(|i| u16::from_le_bytes([blob[pos + i * 2], blob[pos + i * 2 + 1]]))
.collect();
Some(String::from_utf16_lossy(&units))
}
const STAMP_TAG: usize = 8;
const STAMP_AT: usize = 10;
const STAMP_LEN: usize = 5;
fn stamp(out: &mut [u8], unix_seconds: u64) {
if out.len() < STAMP_AT + STAMP_LEN || out[STAMP_TAG] != 0x2a || out[STAMP_TAG + 1] != 0x06 {
return;
}
let mut v = unix_seconds;
for i in 0..STAMP_LEN {
let byte = (v & 0x7F) as u8;
v >>= 7;
out[STAMP_AT + i] = if i < STAMP_LEN - 1 { byte | 0x80 } else { byte };
}
}
#[allow(dead_code)]
pub fn read_stamp(blob: &[u8]) -> Option<u64> {
if blob.len() < STAMP_AT + STAMP_LEN || blob[STAMP_TAG] != 0x2a || blob[STAMP_TAG + 1] != 0x06 {
return None;
}
let mut v = 0u64;
for i in 0..STAMP_LEN {
v |= ((blob[STAMP_AT + i] & 0x7F) as u64) << (7 * i);
}
Some(v)
}
pub fn write(blob: &[u8], name: &str, unix_seconds: u64) -> Result<Vec<u8>, ProfileError> {
let (pos, old_count) = locate(blob).ok_or(ProfileError::NotFound)?;
let new_count = name.encode_utf16().count();
if new_count != old_count {
return Err(ProfileError::LengthChangeRefused);
}
let mut out = blob.to_vec();
out[pos..pos + new_count * 2].copy_from_slice(&utf16le(name));
stamp(&mut out, unix_seconds);
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
const REAL_BLOB: [u8; 116] = [
0x43, 0x42, 0x01, 0x00, 0x0a, 0x02, 0x01, 0x00, 0x2a, 0x06, 0x8c, 0x95, 0xfd, 0xc5, 0x06,
0x2a, 0x2b, 0x0e, 0x5e, 0x43, 0x42, 0x01, 0x00, 0xc2, 0x0a, 0x01, 0xd2, 0x14, 0x28, 0x4d,
0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00,
0x74, 0x00, 0x2e, 0x00, 0x51, 0x00, 0x75, 0x00, 0x69, 0x00, 0x65, 0x00, 0x74, 0x00, 0x48,
0x00, 0x6f, 0x00, 0x75, 0x00, 0x72, 0x00, 0x73, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00,
0x66, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x55, 0x00, 0x6e, 0x00, 0x72,
0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x63, 0x00, 0x74, 0x00,
0x65, 0x00, 0x64, 0x00, 0xca, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
];
const PRIORITY: &str = "Microsoft.QuietHoursProfile.PriorityOnly";
const ALARMS: &str = "Microsoft.QuietHoursProfile.AlarmsOnly";
#[test]
fn reads_the_real_blob() {
assert_eq!(locate(&REAL_BLOB), Some((0x1d, 40)));
assert_eq!(read(&REAL_BLOB).as_deref(), Some(UNRESTRICTED));
}
const ORIGINAL_STAMP: u64 = 1_757_366_924;
#[test]
fn same_length_swap_touches_only_the_name_and_stamp() {
let out = write(&REAL_BLOB, PRIORITY, ORIGINAL_STAMP).unwrap();
assert_eq!(out.len(), REAL_BLOB.len(), "length must not change");
assert_eq!(read(&out).as_deref(), Some(PRIORITY));
assert_eq!(out, {
let mut expect = REAL_BLOB.to_vec();
let (pos, count) = locate(&REAL_BLOB).unwrap();
expect[pos..pos + count * 2].copy_from_slice(&utf16le(PRIORITY));
expect
});
}
#[test]
fn round_trip_returns_original_bytes() {
let on = write(&REAL_BLOB, PRIORITY, ORIGINAL_STAMP).unwrap();
let off = write(&on, UNRESTRICTED, ORIGINAL_STAMP).unwrap();
assert_eq!(off, REAL_BLOB, "toggling back must be byte-identical");
}
#[test]
fn the_timestamp_is_refreshed_without_changing_the_length() {
assert_eq!(read_stamp(&REAL_BLOB), Some(ORIGINAL_STAMP));
let now = 1_785_520_746;
let out = write(&REAL_BLOB, PRIORITY, now).unwrap();
assert_eq!(out.len(), REAL_BLOB.len(), "five bytes always suffice");
assert_eq!(read_stamp(&out), Some(now));
assert_eq!(read(&out).as_deref(), Some(PRIORITY));
for t in [0u64, 1, ORIGINAL_STAMP, now, (1u64 << 35) - 1] {
let b = write(&REAL_BLOB, PRIORITY, t).unwrap();
assert_eq!(b.len(), REAL_BLOB.len(), "stamp {t} changed the length");
assert_eq!(read_stamp(&b), Some(t));
}
}
#[test]
fn refuses_to_resize_the_blob() {
assert_eq!(ALARMS.len(), 38);
assert_eq!(
write(&REAL_BLOB, ALARMS, ORIGINAL_STAMP),
Err(ProfileError::LengthChangeRefused)
);
}
#[test]
fn the_two_profiles_we_use_are_interchangeable_in_place() {
assert_eq!(UNRESTRICTED.len(), PRIORITY.len());
}
#[test]
fn rejects_a_truncated_blob_instead_of_panicking() {
for cut in 0..REAL_BLOB.len() {
let truncated = &REAL_BLOB[..cut];
let _ = read(truncated);
let _ = read_stamp(truncated);
let _ = write(truncated, PRIORITY, ORIGINAL_STAMP);
let _ = write(truncated, ALARMS, ORIGINAL_STAMP);
}
}
}