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
.checked_add(self.offset_field as usize)
.ok_or_else(|| {
malformed_error!(
"ManifestResource length-prefix offset overflow: {} + {}",
section_start,
self.offset_field
)
})?;
if let Ok(len_bytes) = file.data_slice(length_prefix_offset, 4) {
let b0 = *len_bytes.first().ok_or(out_of_bounds_error!())?;
let b1 = *len_bytes.get(1).ok_or(out_of_bounds_error!())?;
let b2 = *len_bytes.get(2).ok_or(out_of_bounds_error!())?;
let b3 = *len_bytes.get(3).ok_or(out_of_bounds_error!())?;
data_size = u32::from_le_bytes([b0, b1, b2, b3]) as usize;
} else {
let next_rid = self.rid.checked_add(1).ok_or_else(|| {
malformed_error!(
"ManifestResource rid overflow when computing next rid: {}",
self.rid
)
})?;
data_size = if let Some(next_res) = table.get(next_rid) {
(next_res.offset_field as usize)
.checked_sub(self.offset_field as usize)
.ok_or_else(|| {
malformed_error!(
"ManifestResource offsets out of order: next={} current={}",
next_res.offset_field,
self.offset_field
)
})?
.saturating_sub(4)
} else {
(cor20.resource_size as usize)
.checked_sub(self.offset_field as usize)
.ok_or_else(|| {
malformed_error!(
"ManifestResource offset {} exceeds resource section size {}",
self.offset_field,
cor20.resource_size
)
})?
.saturating_sub(4)
};
}
data_offset = length_prefix_offset.checked_add(4).ok_or_else(|| {
malformed_error!(
"ManifestResource data offset overflow: {} + 4",
length_prefix_offset
)
})?;
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::new(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(
4u8
.saturating_add(4)
.saturating_add(sizes.str_bytes())
.saturating_add(sizes.coded_index_bytes(CodedIndexType::Implementation))
)
}
}