Skip to main content

outlook_pst/ndb/
root.rs

1//! [ROOT](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-pst/32ce8c94-4757-46c8-a169-3fd21abee584)
2
3use std::fmt::Debug;
4
5use super::{block_ref::*, byte_index::*, read_write::*, *};
6use crate::{AnsiPstFile, PstFile, UnicodePstFile};
7
8/// `fAMapValid`
9///
10/// ### See also
11/// [Root]
12#[repr(u8)]
13#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
14pub enum AmapStatus {
15    /// `INVALID_AMAP`: One or more AMaps in the PST are INVALID
16    #[default]
17    Invalid = 0x00,
18    /// `VALID_AMAP1`: Deprecated. Implementations SHOULD NOT use this value. The AMaps are VALID.
19    Valid1 = 0x01,
20    /// `VALID_AMAP2`: The AMaps are VALID.
21    Valid2 = 0x02,
22}
23
24impl TryFrom<u8> for AmapStatus {
25    type Error = NdbError;
26
27    fn try_from(value: u8) -> Result<Self, Self::Error> {
28        match value {
29            0x00 => Ok(AmapStatus::Invalid),
30            0x01 => Ok(AmapStatus::Valid1),
31            0x02 => Ok(AmapStatus::Valid2),
32            _ => Err(NdbError::InvalidAmapStatus(value)),
33        }
34    }
35}
36
37impl From<AmapStatus> for bool {
38    fn from(status: AmapStatus) -> bool {
39        status != AmapStatus::Invalid
40    }
41}
42
43pub trait Root<Pst>
44where
45    Pst: PstFile,
46{
47    fn file_eof_index(&self) -> &<Pst as PstFile>::ByteIndex;
48    fn amap_last_index(&self) -> &<Pst as PstFile>::ByteIndex;
49    fn amap_free_size(&self) -> &<Pst as PstFile>::ByteIndex;
50    fn pmap_free_size(&self) -> &<Pst as PstFile>::ByteIndex;
51    fn node_btree(&self) -> &<Pst as PstFile>::PageRef;
52    fn block_btree(&self) -> &<Pst as PstFile>::PageRef;
53    fn amap_is_valid(&self) -> AmapStatus;
54}
55
56#[derive(Clone, Debug)]
57pub struct UnicodeRoot {
58    reserved1: u32,
59    file_eof_index: UnicodeByteIndex,
60    amap_last_index: UnicodeByteIndex,
61    amap_free_size: UnicodeByteIndex,
62    pmap_free_size: UnicodeByteIndex,
63    node_btree: UnicodePageRef,
64    block_btree: UnicodePageRef,
65    amap_is_valid: AmapStatus,
66    reserved2: u8,
67    reserved3: u16,
68}
69
70impl UnicodeRoot {
71    pub fn new(
72        file_eof_index: UnicodeByteIndex,
73        amap_last_index: UnicodeByteIndex,
74        amap_free_size: UnicodeByteIndex,
75        pmap_free_size: UnicodeByteIndex,
76        node_btree: UnicodePageRef,
77        block_btree: UnicodePageRef,
78        amap_is_valid: AmapStatus,
79    ) -> Self {
80        Self {
81            reserved1: Default::default(),
82            file_eof_index,
83            amap_last_index,
84            amap_free_size,
85            pmap_free_size,
86            node_btree,
87            block_btree,
88            amap_is_valid,
89            reserved2: Default::default(),
90            reserved3: Default::default(),
91        }
92    }
93}
94
95impl Root<UnicodePstFile> for UnicodeRoot {
96    fn file_eof_index(&self) -> &UnicodeByteIndex {
97        &self.file_eof_index
98    }
99
100    fn amap_last_index(&self) -> &UnicodeByteIndex {
101        &self.amap_last_index
102    }
103
104    fn amap_free_size(&self) -> &UnicodeByteIndex {
105        &self.amap_free_size
106    }
107
108    fn pmap_free_size(&self) -> &UnicodeByteIndex {
109        &self.pmap_free_size
110    }
111
112    fn node_btree(&self) -> &UnicodePageRef {
113        &self.node_btree
114    }
115
116    fn block_btree(&self) -> &UnicodePageRef {
117        &self.block_btree
118    }
119
120    fn amap_is_valid(&self) -> AmapStatus {
121        self.amap_is_valid
122    }
123}
124
125impl RootReadWrite<UnicodePstFile> for UnicodeRoot {
126    fn new(
127        file_eof_index: UnicodeByteIndex,
128        amap_last_index: UnicodeByteIndex,
129        amap_free_size: UnicodeByteIndex,
130        pmap_free_size: UnicodeByteIndex,
131        node_btree: UnicodePageRef,
132        block_btree: UnicodePageRef,
133        amap_is_valid: AmapStatus,
134    ) -> Self {
135        Self::new(
136            file_eof_index,
137            amap_last_index,
138            amap_free_size,
139            pmap_free_size,
140            node_btree,
141            block_btree,
142            amap_is_valid,
143        )
144    }
145
146    fn load_reserved(&mut self, reserved1: u32, reserved2: u8, reserved3: u16) {
147        self.reserved1 = reserved1;
148        self.reserved2 = reserved2;
149        self.reserved3 = reserved3;
150    }
151
152    fn reserved1(&self) -> u32 {
153        self.reserved1
154    }
155
156    fn reserved2(&self) -> u8 {
157        self.reserved2
158    }
159
160    fn reserved3(&self) -> u16 {
161        self.reserved3
162    }
163
164    fn set_amap_status(&mut self, status: AmapStatus) {
165        self.amap_is_valid = status;
166    }
167
168    fn reset_free_size(&mut self, free_bytes: UnicodeByteIndex) -> NdbResult<()> {
169        self.amap_free_size = free_bytes;
170        self.pmap_free_size = 0.into();
171        Ok(())
172    }
173}
174
175#[derive(Clone, Debug)]
176pub struct AnsiRoot {
177    file_eof_index: AnsiByteIndex,
178    amap_last_index: AnsiByteIndex,
179    amap_free_size: AnsiByteIndex,
180    pmap_free_size: AnsiByteIndex,
181    node_btree: AnsiPageRef,
182    block_btree: AnsiPageRef,
183    amap_is_valid: AmapStatus,
184    reserved1: u32,
185    reserved2: u8,
186    reserved3: u16,
187}
188
189impl AnsiRoot {
190    pub fn new(
191        file_eof_index: AnsiByteIndex,
192        amap_last_index: AnsiByteIndex,
193        amap_free_size: AnsiByteIndex,
194        pmap_free_size: AnsiByteIndex,
195        node_btree: AnsiPageRef,
196        block_btree: AnsiPageRef,
197        amap_is_valid: AmapStatus,
198    ) -> Self {
199        Self {
200            reserved1: Default::default(),
201            file_eof_index,
202            amap_last_index,
203            amap_free_size,
204            pmap_free_size,
205            node_btree,
206            block_btree,
207            amap_is_valid,
208            reserved2: Default::default(),
209            reserved3: Default::default(),
210        }
211    }
212}
213
214impl Root<AnsiPstFile> for AnsiRoot {
215    fn file_eof_index(&self) -> &AnsiByteIndex {
216        &self.file_eof_index
217    }
218
219    fn amap_last_index(&self) -> &AnsiByteIndex {
220        &self.amap_last_index
221    }
222
223    fn amap_free_size(&self) -> &AnsiByteIndex {
224        &self.amap_free_size
225    }
226
227    fn pmap_free_size(&self) -> &AnsiByteIndex {
228        &self.pmap_free_size
229    }
230
231    fn node_btree(&self) -> &AnsiPageRef {
232        &self.node_btree
233    }
234
235    fn block_btree(&self) -> &AnsiPageRef {
236        &self.block_btree
237    }
238
239    fn amap_is_valid(&self) -> AmapStatus {
240        self.amap_is_valid
241    }
242}
243
244impl RootReadWrite<AnsiPstFile> for AnsiRoot {
245    fn new(
246        file_eof_index: AnsiByteIndex,
247        amap_last_index: AnsiByteIndex,
248        amap_free_size: AnsiByteIndex,
249        pmap_free_size: AnsiByteIndex,
250        node_btree: AnsiPageRef,
251        block_btree: AnsiPageRef,
252        amap_is_valid: AmapStatus,
253    ) -> Self {
254        Self::new(
255            file_eof_index,
256            amap_last_index,
257            amap_free_size,
258            pmap_free_size,
259            node_btree,
260            block_btree,
261            amap_is_valid,
262        )
263    }
264
265    fn load_reserved(&mut self, reserved1: u32, reserved2: u8, reserved3: u16) {
266        self.reserved1 = reserved1;
267        self.reserved2 = reserved2;
268        self.reserved3 = reserved3;
269    }
270
271    fn reserved1(&self) -> u32 {
272        self.reserved1
273    }
274
275    fn reserved2(&self) -> u8 {
276        self.reserved2
277    }
278
279    fn reserved3(&self) -> u16 {
280        self.reserved3
281    }
282
283    fn set_amap_status(&mut self, status: AmapStatus) {
284        self.amap_is_valid = status;
285    }
286
287    fn reset_free_size(&mut self, free_bytes: AnsiByteIndex) -> NdbResult<()> {
288        self.amap_free_size = free_bytes;
289        self.pmap_free_size = 0.into();
290        Ok(())
291    }
292}