rakata_formats/key/
writer.rs1use std::io::{Cursor, Write};
4
5use rakata_core::encode_text;
6
7use super::{
8 binary::{write_u16, write_u32},
9 Key, KeyBinaryError, FILE_ENTRY_SIZE, FILE_HEADER_SIZE, KEY_MAGIC, KEY_TEXT_ENCODING,
10 KEY_VERSION_V10,
11};
12
13#[cfg_attr(
15 feature = "tracing",
16 tracing::instrument(level = "debug", skip(writer, key))
17)]
18pub fn write_key<W: Write>(writer: &mut W, key: &Key) -> Result<(), KeyBinaryError> {
19 let bif_count = u32::try_from(key.bif_entries.len())
20 .map_err(|_| KeyBinaryError::ValueOverflow("bif_count"))?;
21 let key_count = u32::try_from(key.resources.len())
22 .map_err(|_| KeyBinaryError::ValueOverflow("key_count"))?;
23
24 let file_table_offset = u32::try_from(FILE_HEADER_SIZE)
25 .map_err(|_| KeyBinaryError::ValueOverflow("file_table_offset"))?;
26 let file_table_size = key
27 .bif_entries
28 .len()
29 .checked_mul(FILE_ENTRY_SIZE)
30 .ok_or(KeyBinaryError::ValueOverflow("file_table_size"))?;
31
32 let mut encoded_filenames = Vec::with_capacity(key.bif_entries.len());
33 let mut filenames_table_size = 0usize;
34 for (index, bif_entry) in key.bif_entries.iter().enumerate() {
35 if bif_entry.filename.contains('\0') {
36 return Err(KeyBinaryError::FilenameContainsNul {
37 filename: bif_entry.filename.clone(),
38 });
39 }
40 let encoded = encode_text(&bif_entry.filename, KEY_TEXT_ENCODING).map_err(|source| {
41 KeyBinaryError::TextEncoding {
42 context: format!("bif_entries[{index}].filename"),
43 source,
44 }
45 })?;
46
47 let disk_len = encoded
48 .len()
49 .checked_add(1)
50 .ok_or(KeyBinaryError::ValueOverflow("filename_size"))?;
51 if disk_len > usize::from(u16::MAX) {
52 return Err(KeyBinaryError::FilenameTooLong {
53 filename: bif_entry.filename.clone(),
54 len: disk_len,
55 max: usize::from(u16::MAX),
56 });
57 }
58
59 filenames_table_size = filenames_table_size
60 .checked_add(disk_len)
61 .ok_or(KeyBinaryError::ValueOverflow("filenames_table_size"))?;
62 encoded_filenames.push(encoded);
63 }
64
65 let key_table_offset_usize = FILE_HEADER_SIZE
66 .checked_add(file_table_size)
67 .and_then(|offset| offset.checked_add(filenames_table_size))
68 .ok_or(KeyBinaryError::ValueOverflow("key_table_offset"))?;
69 let key_table_offset = u32::try_from(key_table_offset_usize)
70 .map_err(|_| KeyBinaryError::ValueOverflow("key_table_offset"))?;
71
72 writer.write_all(&KEY_MAGIC)?;
73 writer.write_all(&KEY_VERSION_V10)?;
74 write_u32(writer, bif_count)?;
75 write_u32(writer, key_count)?;
76 write_u32(writer, file_table_offset)?;
77 write_u32(writer, key_table_offset)?;
78 write_u32(writer, key.build_year)?;
79 write_u32(writer, key.build_day)?;
80 writer.write_all(&key.reserved)?;
81
82 let mut next_filename_offset = file_table_offset
83 .checked_add(
84 u32::try_from(file_table_size)
85 .map_err(|_| KeyBinaryError::ValueOverflow("file_table_size"))?,
86 )
87 .ok_or(KeyBinaryError::ValueOverflow("filename_offset"))?;
88
89 for (bif_entry, encoded_filename) in key.bif_entries.iter().zip(encoded_filenames.iter()) {
90 let disk_len = encoded_filename
91 .len()
92 .checked_add(1)
93 .ok_or(KeyBinaryError::ValueOverflow("filename_size"))?;
94 write_u32(writer, bif_entry.file_size)?;
95 write_u32(writer, next_filename_offset)?;
96 write_u16(
97 writer,
98 u16::try_from(disk_len).map_err(|_| KeyBinaryError::ValueOverflow("filename_size"))?,
99 )?;
100 write_u16(writer, bif_entry.drives)?;
101
102 next_filename_offset = next_filename_offset
103 .checked_add(
104 u32::try_from(disk_len)
105 .map_err(|_| KeyBinaryError::ValueOverflow("filename_size"))?,
106 )
107 .ok_or(KeyBinaryError::ValueOverflow("filename_offset"))?;
108 }
109
110 for encoded_filename in &encoded_filenames {
111 writer.write_all(encoded_filename)?;
112 writer.write_all(&[0_u8])?;
113 }
114
115 for resource in &key.resources {
116 let resref_bytes = resource.resref.as_str().as_bytes();
119 let mut key_resref = [0_u8; 16];
120 key_resref[..resref_bytes.len()].copy_from_slice(resref_bytes);
121 writer.write_all(&key_resref)?;
122 write_u16(writer, resource.resource_type.raw_id())?;
123 write_u32(writer, resource.resource_id.raw())?;
124 }
125
126 crate::trace_debug!(
127 bif_count = key.bif_entries.len(),
128 resource_count = key.resources.len(),
129 "wrote key to writer"
130 );
131 Ok(())
132}
133
134#[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(key)))]
136pub fn write_key_to_vec(key: &Key) -> Result<Vec<u8>, KeyBinaryError> {
137 let mut cursor = Cursor::new(Vec::new());
138 write_key(&mut cursor, key)?;
139 let bytes = cursor.into_inner();
140 crate::trace_debug!(bytes_len = bytes.len(), "serialized key to vec");
141 Ok(bytes)
142}