use crate::{
metadata::tables::{
declsecurity::DeclSecurityRaw,
types::{CodedIndexType, RowWritable, TableInfoRef},
},
utils::{write_le_at, write_le_at_dyn},
Result,
};
impl RowWritable for DeclSecurityRaw {
fn row_write(
&self,
data: &mut [u8],
offset: &mut usize,
_rid: u32,
sizes: &TableInfoRef,
) -> Result<()> {
write_le_at(data, offset, self.action)?;
let parent_value = sizes.encode_coded_index(
self.parent.tag,
self.parent.row,
CodedIndexType::HasDeclSecurity,
)?;
write_le_at_dyn(
data,
offset,
parent_value,
sizes.coded_index_bits(CodedIndexType::HasDeclSecurity) > 16,
)?;
write_le_at_dyn(data, offset, self.permission_set, sizes.is_large_blob())?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use crate::metadata::tables::{
declsecurity::DeclSecurityRaw,
types::{
CodedIndex, CodedIndexType, RowReadable, RowWritable, TableId, TableInfo, TableRow,
},
};
use crate::metadata::token::Token;
#[test]
fn test_declsecurity_row_size() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::Assembly, 1),
],
false,
false,
false,
));
let expected_size = 2 + 2 + 2; assert_eq!(
<DeclSecurityRaw as TableRow>::row_size(&sizes),
expected_size
);
let sizes_large = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 0x10000),
(TableId::MethodDef, 0x10000),
(TableId::Assembly, 0x10000),
],
true,
true,
true,
));
let expected_size_large = 2 + 4 + 4; assert_eq!(
<DeclSecurityRaw as TableRow>::row_size(&sizes_large),
expected_size_large
);
}
#[test]
fn test_declsecurity_row_write_small() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::Assembly, 1),
],
false,
false,
false,
));
let decl_security = DeclSecurityRaw {
rid: 1,
token: Token::new(0x0E000001),
offset: 0,
action: 0x0101,
parent: CodedIndex::new(TableId::Assembly, 128, CodedIndexType::HasDeclSecurity), permission_set: 0x0303,
};
let mut buffer = vec![0u8; <DeclSecurityRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
decl_security
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x02,
0x02, 0x03, 0x03, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_declsecurity_row_write_large() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 0x10000),
(TableId::MethodDef, 0x10000),
(TableId::Assembly, 0x10000),
],
true,
true,
true,
));
let decl_security = DeclSecurityRaw {
rid: 1,
token: Token::new(0x0E000001),
offset: 0,
action: 0x0101,
parent: CodedIndex::new(TableId::Assembly, 0x808080, CodedIndexType::HasDeclSecurity), permission_set: 0x03030303,
};
let mut buffer = vec![0u8; <DeclSecurityRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
decl_security
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x02, 0x02, 0x02,
0x02, 0x03, 0x03, 0x03, 0x03, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_declsecurity_round_trip() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::Assembly, 1),
],
false,
false,
false,
));
let original = DeclSecurityRaw {
rid: 42,
token: Token::new(0x0E00002A),
offset: 0,
action: 2, parent: CodedIndex::new(TableId::TypeDef, 25, CodedIndexType::HasDeclSecurity), permission_set: 128, };
let mut buffer = vec![0u8; <DeclSecurityRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
original
.row_write(&mut buffer, &mut offset, 42, &sizes)
.unwrap();
let mut read_offset = 0;
let read_back = DeclSecurityRaw::row_read(&buffer, &mut read_offset, 42, &sizes).unwrap();
assert_eq!(original.rid, read_back.rid);
assert_eq!(original.token, read_back.token);
assert_eq!(original.action, read_back.action);
assert_eq!(original.parent, read_back.parent);
assert_eq!(original.permission_set, read_back.permission_set);
}
#[test]
fn test_declsecurity_different_parent_types() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::Assembly, 1),
],
false,
false,
false,
));
let test_cases = vec![
(TableId::TypeDef, 1, 1, 0x100), (TableId::MethodDef, 1, 2, 0x200), (TableId::Assembly, 1, 3, 0x300), (TableId::TypeDef, 50, 4, 0x400), (TableId::MethodDef, 25, 5, 0x500), ];
for (parent_tag, parent_row, action, blob_index) in test_cases {
let decl_security = DeclSecurityRaw {
rid: 1,
token: Token::new(0x0E000001),
offset: 0,
action,
parent: CodedIndex::new(parent_tag, parent_row, CodedIndexType::HasDeclSecurity),
permission_set: blob_index,
};
let mut buffer = vec![0u8; <DeclSecurityRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
decl_security
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let mut read_offset = 0;
let read_back =
DeclSecurityRaw::row_read(&buffer, &mut read_offset, 1, &sizes).unwrap();
assert_eq!(decl_security.action, read_back.action);
assert_eq!(decl_security.parent, read_back.parent);
assert_eq!(decl_security.permission_set, read_back.permission_set);
}
}
#[test]
fn test_declsecurity_security_actions() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::Assembly, 1),
],
false,
false,
false,
));
let action_cases = vec![
(1, "Request"),
(2, "Demand"),
(3, "Assert"),
(4, "Deny"),
(5, "PermitOnly"),
(6, "LinkDemand"),
(7, "InheritanceDemand"),
(8, "RequestMinimum"),
(9, "RequestOptional"),
(10, "RequestRefuse"),
];
for (action_value, _description) in action_cases {
let decl_security = DeclSecurityRaw {
rid: 1,
token: Token::new(0x0E000001),
offset: 0,
action: action_value,
parent: CodedIndex::new(TableId::TypeDef, 1, CodedIndexType::HasDeclSecurity),
permission_set: 100,
};
let mut buffer = vec![0u8; <DeclSecurityRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
decl_security
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let written_action = u16::from_le_bytes([buffer[0], buffer[1]]);
assert_eq!(written_action, action_value);
}
}
#[test]
fn test_declsecurity_edge_cases() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::Assembly, 1),
],
false,
false,
false,
));
let zero_security = DeclSecurityRaw {
rid: 1,
token: Token::new(0x0E000001),
offset: 0,
action: 0,
parent: CodedIndex::new(TableId::TypeDef, 0, CodedIndexType::HasDeclSecurity), permission_set: 0,
};
let mut buffer = vec![0u8; <DeclSecurityRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
zero_security
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
assert_eq!(buffer, expected);
let max_security = DeclSecurityRaw {
rid: 1,
token: Token::new(0x0E000001),
offset: 0,
action: 0xFFFF,
parent: CodedIndex::new(TableId::Assembly, 0x3FFF, CodedIndexType::HasDeclSecurity), permission_set: 0xFFFF,
};
let mut buffer = vec![0u8; <DeclSecurityRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
max_security
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
assert_eq!(buffer.len(), 6); }
#[test]
fn test_declsecurity_permission_scenarios() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::Assembly, 1),
],
false,
false,
false,
));
let permission_cases = vec![
(TableId::Assembly, 1, 2, 1), (TableId::TypeDef, 2, 4, 100), (TableId::MethodDef, 3, 3, 200), (TableId::TypeDef, 4, 5, 300), (TableId::MethodDef, 5, 6, 400), (TableId::Assembly, 1, 1, 500), ];
for (parent_tag, parent_row, action, blob_index) in permission_cases {
let decl_security = DeclSecurityRaw {
rid: 1,
token: Token::new(0x0E000001),
offset: 0,
action,
parent: CodedIndex::new(parent_tag, parent_row, CodedIndexType::HasDeclSecurity),
permission_set: blob_index,
};
let mut buffer = vec![0u8; <DeclSecurityRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
decl_security
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let written_blob = u16::from_le_bytes([buffer[4], buffer[5]]);
assert_eq!(written_blob as u32, blob_index);
}
}
#[test]
fn test_declsecurity_known_binary_format() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 1),
(TableId::MethodDef, 1),
(TableId::Assembly, 1),
],
false,
false,
false,
));
let decl_security = DeclSecurityRaw {
rid: 1,
token: Token::new(0x0E000001),
offset: 0,
action: 0x0101,
parent: CodedIndex::new(TableId::Assembly, 128, CodedIndexType::HasDeclSecurity), permission_set: 0x0303,
};
let mut buffer = vec![0u8; <DeclSecurityRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
decl_security
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x02, 0x02, 0x03, 0x03, ];
assert_eq!(buffer, expected);
}
}