1use super::{metadata::index, signature::compressed};
2use crate::utils::hash;
3use scroll::{ctx::StrCtx, Pread, Pwrite, Result};
4use std::collections::HashMap;
5
6pub trait Reader<'a> {
9 type Index;
10 type Value;
11
12 const NAME: &'static str;
13
14 fn new(bytes: &'a [u8]) -> Self;
15
16 fn at_index(&self, idx: Self::Index) -> Result<Self::Value>;
17}
18
19macro_rules! heap_reader {
20 ($name:ident, $heap:literal, $index:ty, $value:ty, |$s:ident, $val:ident| $e:expr) => {
21 pub struct $name<'a> {
22 bytes: &'a [u8],
23 }
24
25 impl<'a> Reader<'a> for $name<'a> {
26 type Index = $index;
27 type Value = $value;
28
29 const NAME: &'static str = $heap;
30
31 fn new(bytes: &'a [u8]) -> $name<'a> {
32 $name {
33 bytes: &bytes,
34 }
35 }
36
37 fn at_index(&$s, $val: Self::Index) -> Result<Self::Value> {
38 $e
39 }
40 }
41
42 impl std::fmt::Debug for $name<'_> {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 f.write_str(stringify!($name))
45 }
46 }
47 };
48}
49
50fn read_bytes(bytes: &[u8], idx: usize) -> Result<&[u8]> {
51 let mut offset = idx;
52
53 let compressed::Unsigned(size) = bytes.gread(&mut offset)?;
54
55 bytes.pread_with(offset, size as usize)
56}
57
58heap_reader!(StringsReader, "#Strings", index::String, &'a str, |self, idx| self
59 .bytes
60 .pread_with(idx.0, StrCtx::Delimiter(0)));
61heap_reader!(BlobReader, "#Blob", index::Blob, &'a [u8], |self, idx| {
62 read_bytes(self.bytes, idx.0)
63});
64heap_reader!(GUIDReader, "#GUID", index::GUID, [u8; 16], |self, idx| {
65 let mut buf = [0_u8; 16];
66 self.bytes
67 .gread_inout_with(&mut ((idx.0 - 1) * 16), &mut buf, scroll::LE)?;
68 Ok(buf)
69});
70heap_reader!(UserStringReader, "#US", usize, Vec<u16>, |self, idx| {
71 let bytes = read_bytes(self.bytes, idx)?;
72
73 let num_utf16 = (bytes.len() - 1) / 2;
74 let offset = &mut 0;
75 let chars = (0..num_utf16)
76 .map(|_| bytes.gread_with::<u16>(offset, scroll::LE))
77 .collect::<Result<_>>()?;
78
79 Ok(chars)
80});
81
82fn write_bytes(bytes: &[u8]) -> Result<Vec<u8>> {
83 let len = bytes.len();
84
85 let mut buf = vec![0_u8; len];
86
87 let len_size = buf.pwrite(compressed::Unsigned(len as u32), 0)?;
88
89 buf.extend(vec![0_u8; len_size]);
90
91 buf.pwrite(bytes, len_size)?;
92
93 Ok(buf)
94}
95
96pub trait Writer {
97 type Index;
98 type Value: ?Sized;
99
100 fn new() -> Self;
101
102 fn write(&mut self, value: &Self::Value) -> Result<Self::Index>;
103
104 fn into_vec(self) -> Vec<u8>;
105}
106
107macro_rules! heap_writer {
108 ($name:ident, ($buf:expr, $map:expr), $index:ty, $value:ty, |$s:ident, $n:ident| $e:expr) => {
109 pub struct $name {
110 buffer: Vec<u8>,
111 index_cache: HashMap<u64, <Self as Writer>::Index>,
112 }
113
114 impl Writer for $name {
115 type Index = $index;
116 type Value = $value;
117
118 fn new() -> Self {
119 $name {
120 buffer: $buf,
121 index_cache: $map,
122 }
123 }
124
125 fn into_vec(self) -> Vec<u8> {
126 self.buffer
127 }
128
129 fn write(&mut $s, $n: &Self::Value) -> Result<Self::Index> {
130 let h = hash($n);
131
132 Ok(match $s.index_cache.get(&h) {
133 Some(&i) => i,
134 None => {
135 let idx = $e;
136 $s.index_cache.insert(h, idx);
137 idx
138 }
139 })
140 }
141 }
142
143 impl std::fmt::Debug for $name {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 f.write_str(stringify!($name))
146 }
147 }
148 };
149}
150
151heap_writer!(
152 StringsWriter,
153 (vec![0], HashMap::from([(hash(""), 0.into())])),
154 index::String,
155 str,
156 |self, value| {
157 let start = self.buffer.len();
158 self.buffer.extend(value.as_bytes());
159 self.buffer.push(0_u8);
160 index::String(start)
161 }
162);
163heap_writer!(
164 BlobWriter,
165 (vec![0], HashMap::from([(hash(&[] as &Self::Value), 0.into())])),
166 index::Blob,
167 [u8],
168 |self, value| {
169 let start = self.buffer.len();
170 self.buffer.extend(write_bytes(value)?);
171 index::Blob(start)
172 }
173);
174heap_writer!(
175 GUIDWriter,
176 (vec![], HashMap::new()),
177 index::GUID,
178 [u8; 16],
179 |self, value| {
180 let start = self.buffer.len();
181 self.buffer.extend(value);
182 index::GUID(((start + 1) / 16) + 1)
183 }
184);
185heap_writer!(
186 UserStringWriter,
187 (vec![0], HashMap::from([(hash(&[] as &Self::Value), 0)])),
188 usize,
189 [u16],
190 |self, value| {
191 let final_byte = value.iter().any(|u| {
192 let [high, low] = u.to_be_bytes();
193 high != 0 || matches!(low, 0x01..=0x08 | 0x0E..=0x1F | 0x27 | 0x2D | 0x7F)
194 }) as u8;
195
196 let start = self.buffer.len();
197 self.buffer.extend(write_bytes(
198 &value
199 .iter()
200 .flat_map(|&u| u.to_le_bytes())
201 .chain(std::iter::once(final_byte))
202 .collect::<Vec<_>>(),
203 )?);
204 start
205 }
206);