use deku::prelude::*;
#[derive(DekuRead, DekuWrite, Default, Debug, Clone, PartialEq)]
#[deku(bits = 3, endian = "big", type = "u8")]
pub enum ActionCondition {
#[default]
#[deku(id = "0")]
List,
#[deku(id = "1")]
Read,
#[deku(id = "2")]
Write,
#[deku(id = "3")]
WriteFlush,
}
#[derive(DekuRead, DekuWrite, Default, Debug, Clone, PartialEq)]
#[deku(bits = 2, type = "u8")]
pub enum StorageClass {
#[default]
#[deku(id = "0")]
Transient,
#[deku(id = "1")]
Volatile,
#[deku(id = "2")]
Restorable,
#[deku(id = "3")]
Permanent,
}
#[derive(DekuRead, DekuWrite, Default, Debug, Clone, PartialEq)]
pub struct UserPermissions {
#[deku(bits = 1)]
pub read: bool,
#[deku(bits = 1)]
pub write: bool,
#[deku(bits = 1)]
pub executable: bool,
}
#[derive(DekuRead, DekuWrite, Default, Debug, Clone, PartialEq)]
pub struct FilePermissions {
#[deku(bits = 1)]
pub encrypted: bool,
#[deku(bits = 1)]
pub executable: bool,
pub user: UserPermissions,
pub guest: UserPermissions,
}
#[derive(DekuRead, DekuWrite, Default, Debug, Clone, PartialEq)]
pub struct FileProperties {
#[deku(bits = 1)]
pub enabled: bool,
pub condition: ActionCondition,
#[deku(pad_bits_before = "2")]
pub storage_class: StorageClass,
}
#[derive(DekuRead, DekuWrite, Default, Debug, Clone, PartialEq)]
pub struct FileHeader {
pub permissions: FilePermissions,
pub properties: FileProperties,
pub alp_command_file_id: u8,
pub interface_file_id: u8,
#[deku(endian = "big")]
pub file_size: u32,
#[deku(endian = "big")]
pub allocated_size: u32,
}
#[cfg(test)]
mod test {
use super::*;
use hex_literal::hex;
#[test]
fn test_file_permissions() {
let permissions = FilePermissions {
encrypted: true,
executable: false,
user: UserPermissions {
read: true,
write: true,
executable: true,
},
guest: UserPermissions {
read: false,
write: false,
executable: false,
},
};
let expected = hex!("B8");
assert_eq!(permissions.to_bytes().unwrap(), expected);
assert_eq!(
FilePermissions::from_bytes((&expected, 0)).unwrap().1,
permissions
);
}
#[test]
fn test_file_header() {
let header = FileHeader {
permissions: FilePermissions {
encrypted: true,
executable: false,
user: UserPermissions {
read: true,
write: true,
executable: true,
},
guest: UserPermissions {
read: false,
write: false,
executable: false,
},
},
properties: FileProperties {
enabled: false,
condition: ActionCondition::Read,
storage_class: StorageClass::Permanent,
},
alp_command_file_id: 1,
interface_file_id: 2,
file_size: 0xDEAD_BEEF,
allocated_size: 0xBAAD_FACE,
};
let expected = hex!("B8 13 01 02 DEADBEEF BAADFACE");
assert_eq!(header.to_bytes().unwrap(), expected);
assert_eq!(FileHeader::from_bytes((&expected, 0)).unwrap().1, header);
}
}