use crate::{
metadata::tables::{
manifestresource::ManifestResourceRaw,
types::{CodedIndexType, RowWritable, TableInfoRef},
},
utils::{write_le_at, write_le_at_dyn},
Result,
};
impl RowWritable for ManifestResourceRaw {
fn row_write(
&self,
data: &mut [u8],
offset: &mut usize,
_rid: u32,
sizes: &TableInfoRef,
) -> Result<()> {
write_le_at(data, offset, self.offset_field)?;
write_le_at(data, offset, self.flags)?;
write_le_at_dyn(data, offset, self.name, sizes.is_large_str())?;
let implementation_value = sizes.encode_coded_index(
self.implementation.tag,
self.implementation.row,
CodedIndexType::Implementation,
)?;
write_le_at_dyn(
data,
offset,
implementation_value,
sizes.coded_index_bits(CodedIndexType::Implementation) > 16,
)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use crate::metadata::tables::{
manifestresource::ManifestResourceRaw,
types::{
CodedIndex, CodedIndexType, RowReadable, RowWritable, TableId, TableInfo, TableRow,
},
};
use crate::metadata::token::Token;
#[test]
fn test_manifestresource_row_size() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 100),
(TableId::AssemblyRef, 50),
(TableId::ExportedType, 25),
],
false,
false,
false,
));
let expected_size = 4 + 4 + 2 + 2; assert_eq!(
<ManifestResourceRaw as TableRow>::row_size(&sizes),
expected_size
);
let sizes_large = Arc::new(TableInfo::new_test(
&[
(TableId::File, 0x10000),
(TableId::AssemblyRef, 0x10000),
(TableId::ExportedType, 0x10000),
],
true,
false,
false,
));
let expected_size_large = 4 + 4 + 4 + 4; assert_eq!(
<ManifestResourceRaw as TableRow>::row_size(&sizes_large),
expected_size_large
);
}
#[test]
fn test_manifestresource_row_write_small() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 100),
(TableId::AssemblyRef, 50),
(TableId::ExportedType, 25),
],
false,
false,
false,
));
let manifest_resource = ManifestResourceRaw {
rid: 1,
token: Token::new(0x28000001),
offset: 0,
offset_field: 0x01010101,
flags: 0x02020202,
name: 0x0303,
implementation: CodedIndex::new(TableId::File, 1, CodedIndexType::Implementation), };
let mut buffer = vec![0u8; <ManifestResourceRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
manifest_resource
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x00, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_manifestresource_row_write_large() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 0x10000),
(TableId::AssemblyRef, 0x10000),
(TableId::ExportedType, 0x10000),
],
true,
false,
false,
));
let manifest_resource = ManifestResourceRaw {
rid: 1,
token: Token::new(0x28000001),
offset: 0,
offset_field: 0x01010101,
flags: 0x02020202,
name: 0x03030303,
implementation: CodedIndex::new(TableId::File, 1, CodedIndexType::Implementation), };
let mut buffer = vec![0u8; <ManifestResourceRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
manifest_resource
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x00, 0x00,
0x00, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_manifestresource_round_trip() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 100),
(TableId::AssemblyRef, 50),
(TableId::ExportedType, 25),
],
false,
false,
false,
));
let original = ManifestResourceRaw {
rid: 42,
token: Token::new(0x2800002A),
offset: 0,
offset_field: 0x12345678,
flags: 0x87654321,
name: 256, implementation: CodedIndex::new(
TableId::AssemblyRef,
5,
CodedIndexType::Implementation,
), };
let mut buffer = vec![0u8; <ManifestResourceRaw 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 =
ManifestResourceRaw::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.offset_field, read_back.offset_field);
assert_eq!(original.flags, read_back.flags);
assert_eq!(original.name, read_back.name);
assert_eq!(original.implementation, read_back.implementation);
}
#[test]
fn test_manifestresource_different_implementations() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 100),
(TableId::AssemblyRef, 50),
(TableId::ExportedType, 25),
],
false,
false,
false,
));
let test_cases = vec![
(TableId::File, 1, 100, "External file resource"),
(TableId::AssemblyRef, 2, 200, "External assembly resource"),
(TableId::ExportedType, 3, 300, "Exported type resource"),
(TableId::File, 0, 0, "Embedded resource (special case)"),
];
for (impl_tag, impl_row, offset_field, _description) in test_cases {
let manifest_resource = ManifestResourceRaw {
rid: 1,
token: Token::new(0x28000001),
offset: 0,
offset_field,
flags: 0x00000001, name: 100,
implementation: CodedIndex::new(impl_tag, impl_row, CodedIndexType::Implementation),
};
let mut buffer =
vec![0u8; <ManifestResourceRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
manifest_resource
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let mut read_offset = 0;
let read_back =
ManifestResourceRaw::row_read(&buffer, &mut read_offset, 1, &sizes).unwrap();
assert_eq!(manifest_resource.implementation, read_back.implementation);
assert_eq!(manifest_resource.offset_field, read_back.offset_field);
}
}
#[test]
fn test_manifestresource_resource_attributes() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 100),
(TableId::AssemblyRef, 50),
(TableId::ExportedType, 25),
],
false,
false,
false,
));
let attribute_cases = vec![
(0x00000001, "Public resource"),
(0x00000002, "Private resource"),
(0x00000000, "Default visibility"),
(0x12345678, "Custom attribute combination"),
];
for (flags, _description) in attribute_cases {
let manifest_resource = ManifestResourceRaw {
rid: 1,
token: Token::new(0x28000001),
offset: 0,
offset_field: 1024, flags,
name: 100,
implementation: CodedIndex::new(TableId::File, 0, CodedIndexType::Implementation), };
let mut buffer =
vec![0u8; <ManifestResourceRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
manifest_resource
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let mut read_offset = 0;
let read_back =
ManifestResourceRaw::row_read(&buffer, &mut read_offset, 1, &sizes).unwrap();
assert_eq!(manifest_resource.flags, read_back.flags);
}
}
#[test]
fn test_manifestresource_edge_cases() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 100),
(TableId::AssemblyRef, 50),
(TableId::ExportedType, 25),
],
false,
false,
false,
));
let zero_resource = ManifestResourceRaw {
rid: 1,
token: Token::new(0x28000001),
offset: 0,
offset_field: 0,
flags: 0,
name: 0,
implementation: CodedIndex::new(TableId::File, 0, CodedIndexType::Implementation),
};
let mut buffer = vec![0u8; <ManifestResourceRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
zero_resource
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
assert_eq!(buffer, expected);
let max_resource = ManifestResourceRaw {
rid: 1,
token: Token::new(0x28000001),
offset: 0,
offset_field: 0xFFFFFFFF,
flags: 0xFFFFFFFF,
name: 0xFFFF,
implementation: CodedIndex::new(
TableId::ExportedType,
0x3FFF,
CodedIndexType::Implementation,
), };
let mut buffer = vec![0u8; <ManifestResourceRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
max_resource
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
assert_eq!(buffer.len(), 12); }
#[test]
fn test_manifestresource_heap_sizes() {
let configurations = vec![
(false, 2), (true, 4), ];
for (large_str, expected_str_size) in configurations {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 100),
(TableId::AssemblyRef, 50),
(TableId::ExportedType, 25),
],
large_str,
false,
false,
));
let manifest_resource = ManifestResourceRaw {
rid: 1,
token: Token::new(0x28000001),
offset: 0,
offset_field: 0x12345678,
flags: 0x87654321,
name: 0x12345678,
implementation: CodedIndex::new(TableId::File, 1, CodedIndexType::Implementation),
};
let expected_total_size = 4 + 4 + expected_str_size + 2; assert_eq!(
<ManifestResourceRaw as TableRow>::row_size(&sizes) as usize,
expected_total_size
);
let mut buffer = vec![0u8; expected_total_size];
let mut offset = 0;
manifest_resource
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
assert_eq!(buffer.len(), expected_total_size);
assert_eq!(offset, expected_total_size);
}
}
#[test]
fn test_manifestresource_resource_scenarios() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 100),
(TableId::AssemblyRef, 50),
(TableId::ExportedType, 25),
],
false,
false,
false,
));
let resource_scenarios = vec![
(
1024,
0x00000001,
TableId::File,
0,
"Embedded .resources file",
),
(0, 0x00000001, TableId::File, 1, "External .resources file"),
(
0,
0x00000001,
TableId::AssemblyRef,
2,
"Satellite assembly resource",
),
(
2048,
0x00000002,
TableId::File,
0,
"Private embedded resource",
),
(0, 0x00000001, TableId::File, 3, "Image resource file"),
(
4096,
0x00000001,
TableId::File,
0,
"Configuration data resource",
),
];
for (offset_field, flags, impl_tag, impl_row, _description) in resource_scenarios {
let manifest_resource = ManifestResourceRaw {
rid: 1,
token: Token::new(0x28000001),
offset: 0,
offset_field,
flags,
name: 100,
implementation: CodedIndex::new(impl_tag, impl_row, CodedIndexType::Implementation),
};
let mut buffer =
vec![0u8; <ManifestResourceRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
manifest_resource
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let mut read_offset = 0;
let read_back =
ManifestResourceRaw::row_read(&buffer, &mut read_offset, 1, &sizes).unwrap();
assert_eq!(manifest_resource.offset_field, read_back.offset_field);
assert_eq!(manifest_resource.flags, read_back.flags);
assert_eq!(manifest_resource.implementation, read_back.implementation);
}
}
#[test]
fn test_manifestresource_known_binary_format() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::File, 10),
(TableId::AssemblyRef, 10),
(TableId::ExportedType, 10),
],
false,
false,
false,
));
let manifest_resource = ManifestResourceRaw {
rid: 1,
token: Token::new(0x28000001),
offset: 0,
offset_field: 0x01010101,
flags: 0x02020202,
name: 0x0303,
implementation: CodedIndex::new(TableId::File, 1, CodedIndexType::Implementation), };
let mut buffer = vec![0u8; <ManifestResourceRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
manifest_resource
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x00, ];
assert_eq!(buffer, expected);
}
}