use crate::{
cilassembly::{changes::ChangeRef, AssemblyChanges},
metadata::tables::{
AssemblyRaw, AssemblyRefRaw, ClassLayoutRaw, CodedIndex, ConstantRaw, CustomAttributeRaw,
DeclSecurityRaw, EventMapRaw, EventRaw, ExportedTypeRaw, FieldLayoutRaw, FieldMarshalRaw,
FieldRaw, FieldRvaRaw, FileRaw, GenericParamConstraintRaw, GenericParamRaw, ImplMapRaw,
InterfaceImplRaw, ManifestResourceRaw, MemberRefRaw, MethodDefRaw, MethodImplRaw,
MethodSemanticsRaw, MethodSpecRaw, ModuleRaw, ModuleRefRaw, NestedClassRaw, ParamRaw,
PropertyMapRaw, PropertyRaw, StandAloneSigRaw, TableId, TypeDefRaw, TypeRefRaw,
TypeSpecRaw,
},
};
#[inline]
pub fn resolve_placeholder(value: u32, changes: &AssemblyChanges) -> u32 {
if ChangeRef::is_placeholder(value) {
if let Some(change_ref) = changes.lookup_by_placeholder(value) {
if let Some(resolved) = change_ref.offset() {
return resolved;
}
}
}
value
}
#[inline]
pub fn resolve_rid_placeholder(value: u32, changes: &AssemblyChanges) -> u32 {
if ChangeRef::is_placeholder(value) {
if let Some(change_ref) = changes.lookup_by_placeholder(value) {
if let Some(token) = change_ref.token() {
return token.row();
}
}
}
value
}
#[inline]
pub fn resolve_coded_index_placeholder(coded_index: &mut CodedIndex, changes: &AssemblyChanges) {
coded_index.row = resolve_rid_placeholder(coded_index.row, changes);
}
pub trait ResolvePlaceholders {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges);
}
impl ResolvePlaceholders for ModuleRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
self.mvid = resolve_placeholder(self.mvid, changes);
self.encid = resolve_placeholder(self.encid, changes);
self.encbaseid = resolve_placeholder(self.encbaseid, changes);
}
}
impl ResolvePlaceholders for TypeRefRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.type_name = resolve_placeholder(self.type_name, changes);
self.type_namespace = resolve_placeholder(self.type_namespace, changes);
resolve_coded_index_placeholder(&mut self.resolution_scope, changes);
}
}
impl ResolvePlaceholders for TypeDefRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.type_name = resolve_placeholder(self.type_name, changes);
self.type_namespace = resolve_placeholder(self.type_namespace, changes);
resolve_coded_index_placeholder(&mut self.extends, changes);
self.field_list = resolve_rid_placeholder(self.field_list, changes);
self.method_list = resolve_rid_placeholder(self.method_list, changes);
}
}
impl ResolvePlaceholders for FieldRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
self.signature = resolve_placeholder(self.signature, changes);
}
}
impl ResolvePlaceholders for MethodDefRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
self.signature = resolve_placeholder(self.signature, changes);
self.param_list = resolve_rid_placeholder(self.param_list, changes);
}
}
impl ResolvePlaceholders for ParamRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
}
}
impl ResolvePlaceholders for InterfaceImplRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.class = resolve_rid_placeholder(self.class, changes);
resolve_coded_index_placeholder(&mut self.interface, changes);
}
}
impl ResolvePlaceholders for MemberRefRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
self.signature = resolve_placeholder(self.signature, changes);
resolve_coded_index_placeholder(&mut self.class, changes);
}
}
impl ResolvePlaceholders for ConstantRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.value = resolve_placeholder(self.value, changes);
resolve_coded_index_placeholder(&mut self.parent, changes);
}
}
impl ResolvePlaceholders for CustomAttributeRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.value = resolve_placeholder(self.value, changes);
resolve_coded_index_placeholder(&mut self.parent, changes);
resolve_coded_index_placeholder(&mut self.constructor, changes);
}
}
impl ResolvePlaceholders for FieldMarshalRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.native_type = resolve_placeholder(self.native_type, changes);
resolve_coded_index_placeholder(&mut self.parent, changes);
}
}
impl ResolvePlaceholders for DeclSecurityRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.permission_set = resolve_placeholder(self.permission_set, changes);
resolve_coded_index_placeholder(&mut self.parent, changes);
}
}
impl ResolvePlaceholders for ClassLayoutRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.parent = resolve_rid_placeholder(self.parent, changes);
}
}
impl ResolvePlaceholders for FieldLayoutRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.field = resolve_rid_placeholder(self.field, changes);
}
}
impl ResolvePlaceholders for StandAloneSigRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.signature = resolve_placeholder(self.signature, changes);
}
}
impl ResolvePlaceholders for EventMapRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.parent = resolve_rid_placeholder(self.parent, changes);
self.event_list = resolve_rid_placeholder(self.event_list, changes);
}
}
impl ResolvePlaceholders for EventRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
resolve_coded_index_placeholder(&mut self.event_type, changes);
}
}
impl ResolvePlaceholders for PropertyMapRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.parent = resolve_rid_placeholder(self.parent, changes);
self.property_list = resolve_rid_placeholder(self.property_list, changes);
}
}
impl ResolvePlaceholders for PropertyRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
self.signature = resolve_placeholder(self.signature, changes);
}
}
impl ResolvePlaceholders for MethodSemanticsRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.method = resolve_rid_placeholder(self.method, changes);
resolve_coded_index_placeholder(&mut self.association, changes);
}
}
impl ResolvePlaceholders for MethodImplRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.class = resolve_rid_placeholder(self.class, changes);
resolve_coded_index_placeholder(&mut self.method_body, changes);
resolve_coded_index_placeholder(&mut self.method_declaration, changes);
}
}
impl ResolvePlaceholders for ModuleRefRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
}
}
impl ResolvePlaceholders for TypeSpecRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.signature = resolve_placeholder(self.signature, changes);
}
}
impl ResolvePlaceholders for ImplMapRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.import_name = resolve_placeholder(self.import_name, changes);
resolve_coded_index_placeholder(&mut self.member_forwarded, changes);
self.import_scope = resolve_rid_placeholder(self.import_scope, changes);
}
}
impl ResolvePlaceholders for FieldRvaRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.field = resolve_rid_placeholder(self.field, changes);
}
}
impl ResolvePlaceholders for AssemblyRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.public_key = resolve_placeholder(self.public_key, changes);
self.name = resolve_placeholder(self.name, changes);
self.culture = resolve_placeholder(self.culture, changes);
}
}
impl ResolvePlaceholders for AssemblyRefRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.public_key_or_token = resolve_placeholder(self.public_key_or_token, changes);
self.hash_value = resolve_placeholder(self.hash_value, changes);
self.name = resolve_placeholder(self.name, changes);
self.culture = resolve_placeholder(self.culture, changes);
}
}
impl ResolvePlaceholders for FileRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
self.hash_value = resolve_placeholder(self.hash_value, changes);
}
}
impl ResolvePlaceholders for ExportedTypeRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
self.namespace = resolve_placeholder(self.namespace, changes);
resolve_coded_index_placeholder(&mut self.implementation, changes);
}
}
impl ResolvePlaceholders for ManifestResourceRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
resolve_coded_index_placeholder(&mut self.implementation, changes);
}
}
impl ResolvePlaceholders for NestedClassRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.nested_class = resolve_rid_placeholder(self.nested_class, changes);
self.enclosing_class = resolve_rid_placeholder(self.enclosing_class, changes);
}
}
impl ResolvePlaceholders for GenericParamRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.name = resolve_placeholder(self.name, changes);
resolve_coded_index_placeholder(&mut self.owner, changes);
}
}
impl ResolvePlaceholders for MethodSpecRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.instantiation = resolve_placeholder(self.instantiation, changes);
resolve_coded_index_placeholder(&mut self.method, changes);
}
}
impl ResolvePlaceholders for GenericParamConstraintRaw {
fn resolve_placeholders(&mut self, changes: &AssemblyChanges) {
self.owner = resolve_rid_placeholder(self.owner, changes);
resolve_coded_index_placeholder(&mut self.constraint, changes);
}
}
pub fn resolve_row_placeholders_by_table(
table_id: TableId,
row: &mut dyn std::any::Any,
changes: &AssemblyChanges,
) {
match table_id {
TableId::Module => {
if let Some(r) = row.downcast_mut::<ModuleRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::TypeRef => {
if let Some(r) = row.downcast_mut::<TypeRefRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::TypeDef => {
if let Some(r) = row.downcast_mut::<TypeDefRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::Field => {
if let Some(r) = row.downcast_mut::<FieldRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::MethodDef => {
if let Some(r) = row.downcast_mut::<MethodDefRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::Param => {
if let Some(r) = row.downcast_mut::<ParamRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::InterfaceImpl => {
if let Some(r) = row.downcast_mut::<InterfaceImplRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::MemberRef => {
if let Some(r) = row.downcast_mut::<MemberRefRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::Constant => {
if let Some(r) = row.downcast_mut::<ConstantRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::CustomAttribute => {
if let Some(r) = row.downcast_mut::<CustomAttributeRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::FieldMarshal => {
if let Some(r) = row.downcast_mut::<FieldMarshalRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::DeclSecurity => {
if let Some(r) = row.downcast_mut::<DeclSecurityRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::ClassLayout => {
if let Some(r) = row.downcast_mut::<ClassLayoutRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::FieldLayout => {
if let Some(r) = row.downcast_mut::<FieldLayoutRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::StandAloneSig => {
if let Some(r) = row.downcast_mut::<StandAloneSigRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::EventMap => {
if let Some(r) = row.downcast_mut::<EventMapRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::Event => {
if let Some(r) = row.downcast_mut::<EventRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::PropertyMap => {
if let Some(r) = row.downcast_mut::<PropertyMapRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::Property => {
if let Some(r) = row.downcast_mut::<PropertyRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::MethodSemantics => {
if let Some(r) = row.downcast_mut::<MethodSemanticsRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::MethodImpl => {
if let Some(r) = row.downcast_mut::<MethodImplRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::ModuleRef => {
if let Some(r) = row.downcast_mut::<ModuleRefRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::TypeSpec => {
if let Some(r) = row.downcast_mut::<TypeSpecRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::ImplMap => {
if let Some(r) = row.downcast_mut::<ImplMapRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::FieldRVA => {
if let Some(r) = row.downcast_mut::<FieldRvaRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::Assembly => {
if let Some(r) = row.downcast_mut::<AssemblyRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::AssemblyRef => {
if let Some(r) = row.downcast_mut::<AssemblyRefRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::File => {
if let Some(r) = row.downcast_mut::<FileRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::ExportedType => {
if let Some(r) = row.downcast_mut::<ExportedTypeRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::ManifestResource => {
if let Some(r) = row.downcast_mut::<ManifestResourceRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::NestedClass => {
if let Some(r) = row.downcast_mut::<NestedClassRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::GenericParam => {
if let Some(r) = row.downcast_mut::<GenericParamRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::MethodSpec => {
if let Some(r) = row.downcast_mut::<MethodSpecRaw>() {
r.resolve_placeholders(changes);
}
}
TableId::GenericParamConstraint => {
if let Some(r) = row.downcast_mut::<GenericParamConstraintRaw>() {
r.resolve_placeholders(changes);
}
}
_ => {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
cilassembly::changes::{AssemblyChanges, HeapChanges},
metadata::tables::{CodedIndex, CodedIndexType},
metadata::token::Token,
};
#[test]
fn test_resolve_placeholder_with_match() {
let mut changes = AssemblyChanges::empty();
let mut string_changes = HeapChanges::<String>::new_strings();
let change_ref = string_changes.append("TestString".to_string());
changes.string_heap_changes = string_changes;
change_ref.resolve_to_offset(0x1234);
let placeholder = change_ref.placeholder();
assert!(ChangeRef::is_placeholder(placeholder));
let resolved = resolve_placeholder(placeholder, &changes);
assert_eq!(resolved, 0x1234);
}
#[test]
fn test_resolve_placeholder_without_match() {
let changes = AssemblyChanges::empty();
let regular_value = 0x5678u32;
assert!(!ChangeRef::is_placeholder(regular_value));
assert_eq!(resolve_placeholder(regular_value, &changes), regular_value);
}
#[test]
fn test_resolve_typedef_placeholders() {
let mut changes = AssemblyChanges::empty();
let mut string_changes = HeapChanges::<String>::new_strings();
let name_ref = string_changes.append("MyClass".to_string());
let ns_ref = string_changes.append("MyNamespace".to_string());
changes.string_heap_changes = string_changes;
name_ref.resolve_to_offset(100);
ns_ref.resolve_to_offset(200);
let mut row = TypeDefRaw {
rid: 1,
token: Token::new(0x02000001),
offset: 0,
flags: 0,
type_name: name_ref.placeholder(),
type_namespace: ns_ref.placeholder(),
extends: CodedIndex::null(CodedIndexType::TypeDefOrRef),
field_list: 1,
method_list: 1,
};
assert!(ChangeRef::is_placeholder(row.type_name));
assert!(ChangeRef::is_placeholder(row.type_namespace));
row.resolve_placeholders(&changes);
assert_eq!(row.type_name, 100);
assert_eq!(row.type_namespace, 200);
}
#[test]
fn test_resolve_rid_placeholder_passthrough() {
let changes = AssemblyChanges::empty();
let regular_rid = 42u32;
assert!(!ChangeRef::is_placeholder(regular_rid));
assert_eq!(resolve_rid_placeholder(regular_rid, &changes), regular_rid);
}
#[test]
fn test_resolve_coded_index_passthrough() {
let changes = AssemblyChanges::empty();
let mut coded_index = CodedIndex::new(TableId::TypeRef, 15, CodedIndexType::TypeDefOrRef);
assert!(!ChangeRef::is_placeholder(coded_index.row));
resolve_coded_index_placeholder(&mut coded_index, &changes);
assert_eq!(coded_index.row, 15);
assert_eq!(coded_index.tag, TableId::TypeRef);
}
#[test]
fn test_resolve_memberref_heap_placeholders() {
let mut changes = AssemblyChanges::empty();
let mut string_changes = HeapChanges::<String>::new_strings();
let name_ref = string_changes.append("TestMethod".to_string());
changes.string_heap_changes = string_changes;
let mut blob_changes = HeapChanges::<Vec<u8>>::new_blobs();
let sig_ref = blob_changes.append(vec![0x00, 0x01, 0x02]);
changes.blob_heap_changes = blob_changes;
name_ref.resolve_to_offset(500);
sig_ref.resolve_to_offset(600);
let mut row = MemberRefRaw {
rid: 1,
token: Token::new(0x0A000001),
offset: 0,
class: CodedIndex::new(TableId::TypeRef, 7, CodedIndexType::MemberRefParent),
name: name_ref.placeholder(),
signature: sig_ref.placeholder(),
};
assert!(ChangeRef::is_placeholder(row.name));
assert!(ChangeRef::is_placeholder(row.signature));
assert!(!ChangeRef::is_placeholder(row.class.row));
row.resolve_placeholders(&changes);
assert_eq!(row.name, 500);
assert_eq!(row.signature, 600);
assert_eq!(row.class.row, 7);
assert_eq!(row.class.tag, TableId::TypeRef);
}
}