use crate::ole::ppt::records::PptRecord;
use crate::ole::consts::PptRecordType;
use super::ptr_holder::PersistPtrHolder;
use std::collections::HashMap;
#[derive(Debug, Clone, Default)]
pub struct PersistMapping {
mappings: HashMap<u32, u32>,
}
impl PersistMapping {
#[inline]
pub fn new() -> Self {
Self::default()
}
pub fn build_from_records(records: &[PptRecord]) -> Self {
let ptr_holder_count = records.iter()
.filter(|r| r.record_type == PptRecordType::PersistPtrHolder)
.count();
let mut mappings = HashMap::with_capacity(ptr_holder_count * 10);
records.iter()
.filter(|r| r.record_type == PptRecordType::PersistPtrHolder)
.filter_map(|r| PersistPtrHolder::parse(r).ok())
.for_each(|holder| {
mappings.extend(holder.slide_locations().iter().map(|(&k, &v)| (k, v)));
});
Self { mappings }
}
#[inline]
pub fn get_offset(&self, persist_id: u32) -> Option<u32> {
self.mappings.get(&persist_id).copied()
}
pub fn get_persist_ids(&self) -> Vec<u32> {
let mut ids: Vec<u32> = self.mappings.keys().copied().collect();
ids.sort_unstable();
ids
}
pub fn iter(&self) -> impl Iterator<Item = (&u32, &u32)> {
self.mappings.iter()
}
#[inline]
pub fn len(&self) -> usize {
self.mappings.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.mappings.is_empty()
}
#[inline]
pub fn add_mapping(&mut self, persist_id: u32, offset: u32) {
self.mappings.insert(persist_id, offset);
}
#[inline]
pub fn mappings(&self) -> &HashMap<u32, u32> {
&self.mappings
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_persist_mapping_from_records() {
let mut data1 = Vec::new();
data1.extend_from_slice(&0x00200000u32.to_le_bytes()); data1.extend_from_slice(&1000u32.to_le_bytes());
data1.extend_from_slice(&2000u32.to_le_bytes());
let record1 = PptRecord {
record_type: PptRecordType::PersistPtrHolder,
record_type_raw: 6001,
version: 0,
instance: 0,
data_length: data1.len() as u32,
data: data1,
children: vec![],
};
let mut data2 = Vec::new();
data2.extend_from_slice(&0x00100000u32.to_le_bytes()); data2.extend_from_slice(&1500u32.to_le_bytes());
let record2 = PptRecord {
record_type: PptRecordType::PersistPtrHolder,
record_type_raw: 6001,
version: 0,
instance: 0,
data_length: data2.len() as u32,
data: data2,
children: vec![],
};
let records = vec![record1, record2];
let mapping = PersistMapping::build_from_records(&records);
assert_eq!(mapping.get_offset(0), Some(1500));
assert_eq!(mapping.get_offset(1), Some(2000));
}
}