use memflow::prelude::v1::*; use crate::error::Result; pub trait HashData: Copy + Sized + Pod {} impl HashData for T {} pub trait HashKey: Copy + Sized + Pod {} impl HashKey for K {} #[repr(C)] struct HashFixedDataInternal { ui_key: K, next: Pointer64>, data: T, } unsafe impl Pod for HashFixedDataInternal {} #[repr(C)] struct HashBucketDataInternal { data: T, next: Pointer64>, ui_key: K, } unsafe impl Pod for HashBucketDataInternal {} #[repr(C)] struct HashAllocatedData { pad_0000: [u8; 0x18], list: [HashFixedDataInternal; 128], } unsafe impl Pod for HashAllocatedData {} #[repr(C)] struct HashUnallocatedData { next: Pointer64>, unk_1: K, ui_key: K, unk_2: K, block_list: [HashBucketDataInternal; 256], } unsafe impl Pod for HashUnallocatedData {} #[repr(C)] struct HashBucket { pad_0000: [u8; 0x10], allocated_data: Pointer64>, unallocated_data: Pointer64>, } unsafe impl Pod for HashBucket {} #[repr(C)] struct UtlMemoryPool { block_size: u32, blocks_per_blob: u32, grow_mode: u32, blocks_alloc: u32, block_alloc_size: u32, peak_alloc: u32, } #[repr(C)] pub struct UtlTsHash { entry: UtlMemoryPool, buckets: HashBucket, } impl UtlTsHash { pub fn elements(&self, process: &mut IntoProcessInstanceArcBox<'_>) -> Result> { let mut element_ptr = self.buckets.unallocated_data; let min_size = (self.entry.blocks_per_blob as usize).min(self.entry.block_alloc_size as usize); let mut list = Vec::with_capacity(min_size); while !element_ptr.is_null() { let element = element_ptr.read(process)?; for i in 0..min_size { if list.len() >= self.entry.block_alloc_size as usize { return Ok(list); } list.push(element.block_list[i].data); } element_ptr = element.next; } Ok(list) } } unsafe impl Pod for UtlTsHash {}