use std::collections::HashMap;
use crate::{
metadata::{
tablefields::{get_heap_fields, HeapType},
tables::{TableId, TableInfoRef},
},
utils::{read_le_at_dyn, write_le_at_dyn},
};
pub fn patch_row_heap_refs(
table_id: TableId,
row_data: &mut [u8],
table_info: &TableInfoRef,
string_remap: &HashMap<u32, u32>,
blob_remap: &HashMap<u32, u32>,
guid_remap: &HashMap<u32, u32>,
) {
if string_remap.is_empty() && blob_remap.is_empty() && guid_remap.is_empty() {
return;
}
let fields = get_heap_fields(table_id, table_info);
for field in fields {
let remap = match field.heap_type {
HeapType::String => string_remap,
HeapType::Blob => blob_remap,
HeapType::Guid => guid_remap,
};
if remap.is_empty() {
continue;
}
patch_heap_field(row_data, field.offset, field.size, remap);
}
}
fn patch_heap_field(row_data: &mut [u8], offset: usize, size: usize, remap: &HashMap<u32, u32>) {
if offset + size > row_data.len() {
return;
}
let is_large = size == 4;
let mut read_offset = offset;
if let Ok(old_value) = read_le_at_dyn(row_data, &mut read_offset, is_large) {
if let Some(&new_value) = remap.get(&old_value) {
let mut write_offset = offset;
let _ = write_le_at_dyn(row_data, &mut write_offset, new_value, is_large);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_patch_heap_field_small() {
let mut data = vec![0x00, 0x00, 0x64, 0x00, 0xFF, 0xFF]; let mut remap = HashMap::new();
remap.insert(100, 200);
patch_heap_field(&mut data, 2, 2, &remap);
assert_eq!(data[2], 0xC8); assert_eq!(data[3], 0x00);
}
#[test]
fn test_patch_heap_field_large() {
let mut data = vec![0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0xFF, 0xFF];
let mut remap = HashMap::new();
remap.insert(100, 0x12345678);
patch_heap_field(&mut data, 4, 4, &remap);
assert_eq!(data[4], 0x78);
assert_eq!(data[5], 0x56);
assert_eq!(data[6], 0x34);
assert_eq!(data[7], 0x12);
}
#[test]
fn test_patch_heap_field_no_match() {
let original = vec![0x00, 0x00, 0x64, 0x00, 0xFF, 0xFF];
let mut data = original.clone();
let remap = HashMap::new();
patch_heap_field(&mut data, 2, 2, &remap);
assert_eq!(data, original); }
#[test]
fn test_patch_heap_field_out_of_bounds() {
let mut data = vec![0x00, 0x00];
let mut remap = HashMap::new();
remap.insert(100, 200);
patch_heap_field(&mut data, 10, 2, &remap);
}
}