use std::collections::HashSet;
use crate::{
error::Error,
records::{item::ItemConditions, windows::WindowsVersionRange},
util::{
encoding::{read_ansi_bytes, read_setup_string},
read::Reader,
},
version::Version,
};
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
#[non_exhaustive]
#[allow(missing_docs)]
pub enum DirectoryFlag {
NeverUninstall,
DeleteAfterInstall,
AlwaysUninstall,
SetNtfsCompression,
UnsetNtfsCompression,
}
stable_flag_enum!(DirectoryFlag, {
NeverUninstall => "never_uninstall",
DeleteAfterInstall => "delete_after_install",
AlwaysUninstall => "always_uninstall",
SetNtfsCompression => "set_ntfs_compression",
UnsetNtfsCompression => "unset_ntfs_compression",
});
#[derive(Clone, Debug)]
pub struct DirectoryEntry {
pub name: String,
pub conditions: ItemConditions,
pub legacy_permissions: Vec<u8>,
pub attributes: u32,
pub winver: WindowsVersionRange,
pub permission_index: i16,
pub flags: HashSet<DirectoryFlag>,
pub options_raw: u8,
}
impl DirectoryEntry {
pub(crate) fn read(reader: &mut Reader<'_>, version: &Version) -> Result<Self, Error> {
let name = read_setup_string(reader, version, "Dir.Name")?;
let conditions = ItemConditions::read(reader, version)?;
let legacy_permissions = if version.at_least(4, 0, 11) && !version.at_least(4, 1, 0) {
read_ansi_bytes(reader, "Dir.LegacyPermissions")?
} else {
Vec::new()
};
let attributes = if version.at_least(2, 0, 11) {
reader.u32_le("Dir.Attribs")?
} else {
0
};
let winver = WindowsVersionRange::read(reader, version)?;
let permission_index = if version.at_least(4, 1, 0) {
reader
.array::<2>("Dir.PermissionIndex")
.map(i16::from_le_bytes)?
} else {
-1
};
let bit_count = if version.at_least(5, 2, 0) { 5 } else { 3 };
let raw = reader.set_bytes(bit_count, true, "Dir.Options")?;
let options_raw = raw.first().copied().unwrap_or(0);
let flags = decode_directory_flags(options_raw, version);
Ok(Self {
name,
conditions,
legacy_permissions,
attributes,
winver,
permission_index,
flags,
options_raw,
})
}
}
fn decode_directory_flags(raw: u8, version: &Version) -> HashSet<DirectoryFlag> {
let mut table: Vec<DirectoryFlag> = vec![
DirectoryFlag::NeverUninstall,
DirectoryFlag::DeleteAfterInstall,
DirectoryFlag::AlwaysUninstall,
];
if version.at_least(5, 2, 0) {
table.push(DirectoryFlag::SetNtfsCompression);
table.push(DirectoryFlag::UnsetNtfsCompression);
}
super::decode_packed_flags(&[raw], &table)
}