1use crate::{MPQParserError, MPQResult};
4
5use super::parser::peek_hex;
6use super::{MPQBlockTableEntry, MPQFileHeader, MPQHashTableEntry, MPQHashType, MPQUserData, MPQ};
7use std::collections::HashMap;
8
9#[derive(Debug)]
11pub struct MPQBuilder {
12 pub archive_header: Option<MPQFileHeader>,
14 pub user_data: Option<MPQUserData>,
20 pub hash_table_entries: Vec<MPQHashTableEntry>,
22 pub block_table_entries: Vec<MPQBlockTableEntry>,
24 pub encryption_table: HashMap<u32, u32>,
26}
27
28impl Default for MPQBuilder {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34impl MPQBuilder {
35 pub fn new() -> Self {
37 Self {
38 archive_header: None,
39 user_data: None,
40 hash_table_entries: vec![],
41 block_table_entries: vec![],
42 encryption_table: MPQ::prepare_encryption_table(),
43 }
44 }
45
46 pub fn with_archive_header(mut self, archive_header: MPQFileHeader) -> Self {
48 self.archive_header = Some(archive_header);
49 self
50 }
51
52 pub fn with_user_data(mut self, user_data: Option<MPQUserData>) -> Self {
54 self.user_data = user_data;
55 self
56 }
57
58 pub fn with_hash_table(mut self, entries: Vec<MPQHashTableEntry>) -> Self {
60 self.hash_table_entries = entries;
61 self
62 }
63
64 pub fn with_block_table(mut self, entries: Vec<MPQBlockTableEntry>) -> Self {
66 self.block_table_entries = entries;
67 self
68 }
69
70 pub fn mpq_string_hash(
72 &self,
73 location: &str,
74 hash_type: MPQHashType,
75 ) -> Result<u32, MPQParserError> {
76 MPQ::mpq_string_hash(&self.encryption_table, location, hash_type)
77 }
78
79 #[tracing::instrument(level = "trace", skip(self, data))]
81 pub fn mpq_data_decrypt<'a>(
82 &'a self,
83 data: &'a [u8],
84 key: u32,
85 ) -> MPQResult<&'a [u8], Vec<u8>> {
86 tracing::trace!("Encrypted: {:?}", peek_hex(data));
87 let (tail, res) = MPQ::mpq_data_decrypt(&self.encryption_table, data, key)?;
88 tracing::trace!("Decrypted: {:?}", peek_hex(&res));
89 Ok((tail, res))
90 }
91
92 pub fn build(self, _orig_input: &[u8]) -> Result<MPQ, MPQParserError> {
94 let archive_header = self
95 .archive_header
96 .ok_or(MPQParserError::MissingArchiveHeader)?;
97 let user_data = self.user_data;
98 let hash_table_entries = self.hash_table_entries;
99 let block_table_entries = self.block_table_entries;
100 let encryption_table = self.encryption_table;
101 Ok(MPQ {
102 archive_header,
103 user_data,
104 hash_table_entries,
105 block_table_entries,
106 encryption_table,
107 })
108 }
109}