use std::sync::Arc;
use crate::{
file::File,
metadata::{
cor20header::Cor20Header,
streams::Strings,
tables::{
CodedIndex, CodedIndexType, ManifestResource, ManifestResourceAttributes,
ManifestResourceRc, MetadataTable, TableInfoRef, TableRow,
},
token::Token,
typesystem::CilTypeReference,
},
Result,
};
#[derive(Clone, Debug)]
pub struct ManifestResourceRaw {
pub rid: u32,
pub token: Token,
pub offset: usize,
pub offset_field: u32,
pub flags: u32,
pub name: u32,
pub implementation: CodedIndex,
}
impl ManifestResourceRaw {
pub fn to_owned<F>(
&self,
get_ref: F,
file: &File,
cor20: &Cor20Header,
strings: &Strings,
table: &MetadataTable<ManifestResourceRaw>,
) -> Result<ManifestResourceRc>
where
F: Fn(&CodedIndex) -> CilTypeReference,
{
let mut data_offset = self.offset_field as usize;
let mut data_size = 0_usize;
let source = if self.implementation.row == 0 {
let section_start = file.rva_to_offset(cor20.resource_rva as usize)?;
let length_prefix_offset = section_start + self.offset_field as usize;
if let Ok(len_bytes) = file.data_slice(length_prefix_offset, 4) {
data_size =
u32::from_le_bytes([len_bytes[0], len_bytes[1], len_bytes[2], len_bytes[3]])
as usize;
} else {
data_size = if let Some(next_res) = table.get(self.rid + 1) {
(next_res.offset_field as usize - self.offset_field as usize).saturating_sub(4)
} else {
(cor20.resource_size as usize - self.offset_field as usize).saturating_sub(4)
};
}
data_offset = length_prefix_offset + 4;
None
} else {
let implementation = get_ref(&self.implementation);
if matches!(implementation, CilTypeReference::None) {
return Err(malformed_error!(
"Failed to resolve implementation token - {}",
self.implementation.token.value()
));
}
Some(implementation)
};
Ok(Arc::new(ManifestResource {
rid: self.rid,
token: self.token,
offset: self.offset,
data_offset,
data_size,
flags: ManifestResourceAttributes::from_bits_truncate(self.flags),
name: strings.get(self.name as usize)?.to_string(),
source,
}))
}
pub fn apply(&self) -> Result<()> {
Ok(())
}
}
impl TableRow for ManifestResourceRaw {
#[rustfmt::skip]
fn row_size(sizes: &TableInfoRef) -> u32 {
u32::from(
4 +
4 +
sizes.str_bytes() +
sizes.coded_index_bytes(CodedIndexType::Implementation)
)
}
}