mod rowpatch;
mod streaming;
pub use streaming::{
compute_blob_heap_offsets, compute_guid_heap_offsets, compute_strings_heap_offsets,
compute_userstring_heap_offsets, stream_blob_heap, stream_guid_heap, stream_strings_heap,
stream_userstring_heap,
};
pub(crate) use rowpatch::patch_row_heap_refs;
use std::collections::HashMap;
use crate::{
cilassembly::{changes::AssemblyChanges, writer::context::WriteContext},
CilAssemblyView, Result,
};
#[derive(Debug, Default, Clone)]
pub struct HeapRemapping {
pub strings: HashMap<u32, u32>,
pub blobs: HashMap<u32, u32>,
pub guids: HashMap<u32, u32>,
pub userstrings: HashMap<u32, u32>,
}
impl HeapRemapping {
pub fn new() -> Self {
Self::default()
}
pub fn has_changes(&self) -> bool {
!self.strings.is_empty()
|| !self.blobs.is_empty()
|| !self.guids.is_empty()
|| !self.userstrings.is_empty()
}
pub fn remap_string(&self, offset: u32) -> u32 {
self.strings.get(&offset).copied().unwrap_or(offset)
}
pub fn remap_blob(&self, offset: u32) -> u32 {
self.blobs.get(&offset).copied().unwrap_or(offset)
}
pub fn remap_guid(&self, index: u32) -> u32 {
self.guids.get(&index).copied().unwrap_or(index)
}
pub fn remap_userstring(&self, offset: u32) -> u32 {
self.userstrings.get(&offset).copied().unwrap_or(offset)
}
}
pub fn precompute_heap_offsets(
view: &CilAssemblyView,
ctx: &mut WriteContext,
changes: &AssemblyChanges,
) -> Result<()> {
let empty: &[u8] = &[];
let strings_data = view.strings().map_or(empty, crate::Strings::data);
let blob_data = view.blobs().map_or(empty, crate::Blob::data);
let guid_data = view.guids().map_or(empty, crate::Guid::data);
let us_data = view.userstrings().map_or(empty, crate::UserStrings::data);
let strings_result = compute_strings_heap_offsets(strings_data, &changes.string_heap_changes)?;
let blob_result = compute_blob_heap_offsets(blob_data, &changes.blob_heap_changes)?;
let guid_result = compute_guid_heap_offsets(guid_data, &changes.guid_heap_changes)?;
let us_result = compute_userstring_heap_offsets(us_data, &changes.userstring_heap_changes)?;
ctx.heap_remapping.strings = strings_result.remapping;
ctx.heap_remapping.blobs = blob_result.remapping;
ctx.heap_remapping.guids = guid_result.remapping;
ctx.heap_remapping.userstrings = us_result.remapping;
Ok(())
}