Skip to main content

outlook_pst/ltp/
prop_context.rs

1//! ## [Property Context (PC)](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-pst/294c83c6-ff92-42f5-b6b6-876c29fa9737)
2
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4use core::mem;
5use std::{
6    cell::RefCell,
7    collections::BTreeMap,
8    fmt::{Debug, Display},
9    io::{self, Cursor, Read, Write},
10};
11
12use super::{heap::*, prop_type::*, read_write::*, tree::*, *};
13use crate::{
14    ndb::{
15        block::{DataBlockCache, DataTree, IntermediateTreeBlock, SubNodeTree},
16        block_id::BlockId,
17        block_ref::BlockRef,
18        header::NdbCryptMethod,
19        node_id::{NodeId, NodeIdType},
20        page::{
21            AnsiBlockBTree, AnsiNodeBTreeEntry, BlockBTreeEntry, NodeBTreeEntry, RootBTree,
22            UnicodeBlockBTree, UnicodeNodeBTreeEntry,
23        },
24        read_write::*,
25    },
26    AnsiPstFile, PstFile, PstFileReadWriteBlockBTree, PstReader, UnicodePstFile,
27};
28
29#[derive(Copy, Clone)]
30pub enum PropertyValueRecord {
31    Small(u32),
32    Heap(HeapId),
33    Node(NodeId),
34}
35
36impl PropertyValueRecord {
37    pub fn small_value(&self, prop_type: PropertyType) -> Option<PropertyValue> {
38        match (self, prop_type) {
39            (PropertyValueRecord::Small(value), PropertyType::Integer16) => {
40                Some(PropertyValue::Integer16((*value & 0xFFFF) as i16))
41            }
42            (PropertyValueRecord::Small(value), PropertyType::Integer32) => {
43                Some(PropertyValue::Integer32(*value as i32))
44            }
45            (PropertyValueRecord::Small(value), PropertyType::Floating32) => {
46                Some(PropertyValue::Floating32(f32::from_bits(*value)))
47            }
48            (PropertyValueRecord::Small(value), PropertyType::ErrorCode) => {
49                Some(PropertyValue::ErrorCode(*value as i32))
50            }
51            (PropertyValueRecord::Small(value), PropertyType::Boolean) => {
52                Some(PropertyValue::Boolean(*value & 0xFF != 0))
53            }
54            _ => None,
55        }
56    }
57}
58
59impl Debug for PropertyValueRecord {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        match self {
62            PropertyValueRecord::Small(value) => write!(f, "Small(0x{value:08X})"),
63            PropertyValueRecord::Heap(heap_id) => write!(f, "{heap_id:?}"),
64            PropertyValueRecord::Node(node_id) => write!(f, "{node_id:?}"),
65        }
66    }
67}
68
69impl From<PropertyValueRecord> for u32 {
70    fn from(value: PropertyValueRecord) -> Self {
71        match value {
72            PropertyValueRecord::Small(value) => value,
73            PropertyValueRecord::Heap(heap_id) => u32::from(heap_id),
74            PropertyValueRecord::Node(node_id) => u32::from(node_id),
75        }
76    }
77}
78
79pub type PropertyTreeRecordKey = u16;
80
81impl HeapTreeEntryKey for PropertyTreeRecordKey {
82    const SIZE: u8 = 2;
83}
84
85impl HeapNodePageReadWrite for PropertyTreeRecordKey {
86    fn read(f: &mut dyn Read) -> io::Result<Self> {
87        f.read_u16::<LittleEndian>()
88    }
89
90    fn write(&self, f: &mut dyn Write) -> io::Result<()> {
91        f.write_u16::<LittleEndian>(*self)
92    }
93}
94
95#[derive(Clone, Copy, Debug)]
96pub struct PropertyTreeRecordValue {
97    prop_type: PropertyType,
98    value: PropertyValueRecord,
99}
100
101impl PropertyTreeRecordValue {
102    pub fn new(prop_type: PropertyType, value: PropertyValueRecord) -> Self {
103        Self { prop_type, value }
104    }
105
106    pub fn prop_type(&self) -> PropertyType {
107        self.prop_type
108    }
109
110    pub fn value(&self) -> PropertyValueRecord {
111        self.value
112    }
113}
114
115impl HeapTreeEntryValue for PropertyTreeRecordValue {
116    const SIZE: u8 = 6;
117}
118
119impl HeapNodePageReadWrite for PropertyTreeRecordValue {
120    fn read(f: &mut dyn Read) -> io::Result<Self> {
121        // wPropType
122        let prop_type = f.read_u16::<LittleEndian>()?;
123        let prop_type = PropertyType::try_from(prop_type)?;
124
125        // dwValueHnid
126        let value = f.read_u32::<LittleEndian>()?;
127        let value = match prop_type {
128            PropertyType::Null => PropertyValueRecord::Small(0),
129
130            PropertyType::Integer16 => PropertyValueRecord::Small(value & 0xFFFF),
131
132            PropertyType::Integer32 | PropertyType::Floating32 | PropertyType::ErrorCode => {
133                PropertyValueRecord::Small(value)
134            }
135
136            PropertyType::Boolean => PropertyValueRecord::Small(value & 0xFF),
137
138            PropertyType::Floating64
139            | PropertyType::Currency
140            | PropertyType::FloatingTime
141            | PropertyType::Integer64
142            | PropertyType::Time
143            | PropertyType::Guid
144            | PropertyType::Object => PropertyValueRecord::Heap(HeapId::from(value)),
145
146            _ => match NodeId::from(value).id_type() {
147                Ok(NodeIdType::HeapNode) => PropertyValueRecord::Heap(HeapId::from(value)),
148                _ => PropertyValueRecord::Node(NodeId::from(value)),
149            },
150        };
151
152        Ok(Self { prop_type, value })
153    }
154
155    fn write(&self, f: &mut dyn Write) -> io::Result<()> {
156        f.write_u16::<LittleEndian>(u16::from(self.prop_type))?;
157        f.write_u32::<LittleEndian>(u32::from(self.value))
158    }
159}
160
161/// [PC BTH Record](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-pst/7daab6f5-ce65-437e-80d5-1b1be4088bd3)
162#[derive(Clone, Copy)]
163pub struct PropertyTreeRecord {
164    key: PropertyTreeRecordKey,
165    data: PropertyTreeRecordValue,
166}
167
168impl PropertyTreeRecord {
169    pub fn new(prop_id: u16, prop_type: PropertyType, value: PropertyValueRecord) -> Self {
170        Self {
171            key: prop_id,
172            data: PropertyTreeRecordValue::new(prop_type, value),
173        }
174    }
175
176    pub fn prop_id(&self) -> u16 {
177        self.key
178    }
179
180    pub fn prop_type(&self) -> PropertyType {
181        self.data.prop_type()
182    }
183
184    pub fn value(&self) -> PropertyValueRecord {
185        self.data.value()
186    }
187}
188
189impl PropertyTreeRecordReadWrite for PropertyTreeRecord {
190    fn read(f: &mut dyn Read) -> io::Result<Self> {
191        let key = f.read_u16::<LittleEndian>()?;
192        let data = PropertyTreeRecordValue::read(f)?;
193
194        Ok(Self { key, data })
195    }
196
197    fn write(&self, f: &mut dyn Write) -> io::Result<()> {
198        f.write_u16::<LittleEndian>(self.key)?;
199        self.data.write(f)
200    }
201}
202
203#[derive(Clone, Default)]
204pub struct String8Value {
205    buffer: Vec<u8>,
206}
207
208impl String8Value {
209    pub fn buffer(&self) -> &[u8] {
210        &self.buffer
211    }
212}
213
214impl Display for String8Value {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        let buffer: Vec<_> = self.buffer.iter().map(|&b| u16::from(b)).collect();
217        let value = String::from_utf16_lossy(&buffer);
218        write!(f, "{value}")
219    }
220}
221
222impl Debug for String8Value {
223    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224        let value = self.to_string();
225        write!(f, "String8Value {{ {value:?} }}")
226    }
227}
228
229#[derive(Clone, Default)]
230pub struct UnicodeValue {
231    buffer: Vec<u16>,
232}
233
234impl UnicodeValue {
235    pub fn buffer(&self) -> &[u16] {
236        &self.buffer
237    }
238}
239
240impl Display for UnicodeValue {
241    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242        let value = String::from_utf16_lossy(&self.buffer);
243        write!(f, "{value}")
244    }
245}
246
247impl Debug for UnicodeValue {
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        let value = self.to_string();
250        write!(f, "UnicodeValue {{ {value:?} }}")
251    }
252}
253
254#[derive(Clone, Copy, Default)]
255pub struct GuidValue {
256    data1: u32,
257    data2: u16,
258    data3: u16,
259    data4: [u8; 8],
260}
261
262impl GuidValue {
263    pub const fn new(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self {
264        Self {
265            data1,
266            data2,
267            data3,
268            data4,
269        }
270    }
271
272    pub fn data1(&self) -> u32 {
273        self.data1
274    }
275
276    pub fn data2(&self) -> u16 {
277        self.data2
278    }
279
280    pub fn data3(&self) -> u16 {
281        self.data3
282    }
283
284    pub fn data4(&self) -> &[u8; 8] {
285        &self.data4
286    }
287}
288
289impl Debug for GuidValue {
290    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
291        write!(
292            f,
293            "GuidValue {{ {:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X} }}",
294            self.data1,
295            self.data2,
296            self.data3,
297            self.data4[0],
298            self.data4[1],
299            self.data4[2],
300            self.data4[3],
301            self.data4[4],
302            self.data4[5],
303            self.data4[6],
304            self.data4[7]
305        )
306    }
307}
308
309#[derive(Clone, Default)]
310pub struct BinaryValue {
311    buffer: Vec<u8>,
312}
313
314impl BinaryValue {
315    pub fn new(buffer: Vec<u8>) -> Self {
316        Self { buffer }
317    }
318
319    pub fn buffer(&self) -> &[u8] {
320        &self.buffer
321    }
322}
323
324impl Debug for BinaryValue {
325    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
326        let value = self
327            .buffer
328            .iter()
329            .map(|ch| format!("{ch:02X}"))
330            .collect::<Vec<_>>()
331            .join("-");
332        write!(f, "BinaryValue {{ {value} }}")
333    }
334}
335
336#[derive(Clone, Copy, Default)]
337pub struct ObjectValue {
338    node_id: NodeId,
339    size: u32,
340}
341
342impl ObjectValue {
343    pub fn node(&self) -> NodeId {
344        self.node_id
345    }
346
347    pub fn size(&self) -> u32 {
348        self.size
349    }
350}
351
352impl Debug for ObjectValue {
353    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
354        write!(
355            f,
356            "ObjectValue {{ {:?}, size: 0x{:X} }}",
357            self.node_id, self.size
358        )
359    }
360}
361
362#[derive(Clone, Default, Debug)]
363pub enum PropertyValue {
364    /// `PtypNull`: None: This property is a placeholder.
365    #[default]
366    Null,
367    /// `PtypInteger16`: 2 bytes; a 16-bit integer
368    Integer16(i16),
369    /// `PtypInteger32`: 4 bytes; a 32-bit integer
370    Integer32(i32),
371    /// `PtypFloating32`: 4 bytes; a 32-bit floating-point number
372    Floating32(f32),
373    /// `PtypFloating64`: 8 bytes; a 64-bit floating-point number
374    Floating64(f64),
375    /// `PtypCurrency`: 8 bytes; a 64-bit signed, scaled integer representation of a decimal
376    /// currency value, with four places to the right of the decimal point
377    Currency(i64),
378    /// `PtypFloatingTime`: 8 bytes; a 64-bit floating point number in which the whole number part
379    /// represents the number of days since December 30, 1899, and the fractional part represents
380    /// the fraction of a day since midnight
381    FloatingTime(f64),
382    /// `PtypErrorCode`: 4 bytes; a 32-bit integer encoding error information as specified in
383    /// section [2.4.1](https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcdata/c9dc2fb0-73ca-4cc2-bdee-cc6ffb9b70eb).
384    ErrorCode(i32),
385    /// `PtypBoolean`: 1 byte; restricted to 1 or 0
386    Boolean(bool),
387    /// `PtypInteger64`: 8 bytes; a 64-bit integer
388    Integer64(i64),
389    /// `PtypString8`: Variable size; a string of multibyte characters in externally specified
390    /// encoding with terminating null character (single 0 byte).
391    String8(String8Value),
392    /// `PtypString`: Variable size; a string of Unicode characters in UTF-16LE format encoding
393    /// with terminating null character (0x0000).
394    Unicode(UnicodeValue),
395    /// `PtypTime`: 8 bytes; a 64-bit integer representing the number of 100-nanosecond intervals
396    /// since January 1, 1601
397    Time(i64),
398    /// `PtypGuid`: 16 bytes; a GUID with Data1, Data2, and Data3 fields in little-endian format
399    Guid(GuidValue),
400    /// `PtypBinary`: Variable size; a COUNT field followed by that many bytes.
401    Binary(BinaryValue),
402    /// `PtypObject`: The property value is a Component Object Model (COM) object, as specified in
403    /// section [2.11.1.5](https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcdata/5a024c95-2264-4832-9840-d6260c9c2cdb).
404    Object(ObjectValue),
405
406    /// `PtypMultipleInteger16`: Variable size; a COUNT field followed by that many
407    /// [PropertyValue::Integer16] values.
408    MultipleInteger16(Vec<i16>),
409    /// `PtypMultipleInteger32`: Variable size; a COUNT field followed by that many
410    /// [PropertyValue::Integer32] values.
411    MultipleInteger32(Vec<i32>),
412    /// `PtypMultipleFloating32`: Variable size; a COUNT field followed by that many
413    /// [PropertyValue::Floating32] values.
414    MultipleFloating32(Vec<f32>),
415    /// `PtypFloating64`: Variable size; a COUNT field followed by that many
416    /// [PropertyValue::Floating64] values.
417    MultipleFloating64(Vec<f64>),
418    /// `PtypMultipleCurrency`: Variable size; a COUNT field followed by that many
419    /// [PropertyValue::Currency] values.
420    MultipleCurrency(Vec<i64>),
421    /// `PtypMultipleFloatingTime`: Variable size; a COUNT field followed by that many
422    /// [PropertyValue::FloatingTime] values.
423    MultipleFloatingTime(Vec<f64>),
424    /// `PtypMultipleInteger64`: Variable size; a COUNT field followed by that many
425    /// [PropertyValue::Integer64] values.
426    MultipleInteger64(Vec<i64>),
427    /// `PtypMultipleString8`: Variable size; a COUNT field followed by that many
428    /// [PropertyValue::String8] values.
429    MultipleString8(Vec<String8Value>),
430    /// `PtypMultipleString`: Variable size; a COUNT field followed by that many
431    /// [PropertyValue::Unicode] values.
432    MultipleUnicode(Vec<UnicodeValue>),
433    /// `PtypMultipleTime`: Variable size; a COUNT field followed by that many
434    /// [PropertyValue::Time] values.
435    MultipleTime(Vec<i64>),
436    /// `PtypMultipleGuid`: Variable size; a COUNT field followed by that many
437    /// [PropertyValue::Guid] values.
438    MultipleGuid(Vec<GuidValue>),
439    /// `PtypMultipleBinary`: Variable size; a COUNT field followed by that many
440    /// [PropertyValue::Binary] values.
441    MultipleBinary(Vec<BinaryValue>),
442}
443
444impl From<&PropertyValue> for PropertyType {
445    fn from(value: &PropertyValue) -> Self {
446        match value {
447            PropertyValue::Null => PropertyType::Null,
448            PropertyValue::Integer16(_) => PropertyType::Integer16,
449            PropertyValue::Integer32(_) => PropertyType::Integer32,
450            PropertyValue::Floating32(_) => PropertyType::Floating32,
451            PropertyValue::Floating64(_) => PropertyType::Floating64,
452            PropertyValue::Currency(_) => PropertyType::Currency,
453            PropertyValue::FloatingTime(_) => PropertyType::FloatingTime,
454            PropertyValue::ErrorCode(_) => PropertyType::ErrorCode,
455            PropertyValue::Boolean(_) => PropertyType::Boolean,
456            PropertyValue::Integer64(_) => PropertyType::Integer64,
457            PropertyValue::String8(_) => PropertyType::String8,
458            PropertyValue::Unicode(_) => PropertyType::Unicode,
459            PropertyValue::Time(_) => PropertyType::Time,
460            PropertyValue::Guid(_) => PropertyType::Guid,
461            PropertyValue::Binary(_) => PropertyType::Binary,
462            PropertyValue::Object(_) => PropertyType::Object,
463            PropertyValue::MultipleInteger16(_) => PropertyType::MultipleInteger16,
464            PropertyValue::MultipleInteger32(_) => PropertyType::MultipleInteger32,
465            PropertyValue::MultipleFloating32(_) => PropertyType::MultipleFloating32,
466            PropertyValue::MultipleFloating64(_) => PropertyType::MultipleFloating64,
467            PropertyValue::MultipleCurrency(_) => PropertyType::MultipleCurrency,
468            PropertyValue::MultipleFloatingTime(_) => PropertyType::MultipleFloatingTime,
469            PropertyValue::MultipleInteger64(_) => PropertyType::MultipleInteger64,
470            PropertyValue::MultipleString8(_) => PropertyType::MultipleString8,
471            PropertyValue::MultipleUnicode(_) => PropertyType::MultipleUnicode,
472            PropertyValue::MultipleTime(_) => PropertyType::MultipleTime,
473            PropertyValue::MultipleGuid(_) => PropertyType::MultipleGuid,
474            PropertyValue::MultipleBinary(_) => PropertyType::MultipleBinary,
475        }
476    }
477}
478
479impl PropertyValueReadWrite for PropertyValue {
480    fn read(f: &mut dyn Read, prop_type: PropertyType) -> io::Result<Self> {
481        match prop_type {
482            PropertyType::Floating64 => {
483                let value = f.read_f64::<LittleEndian>()?;
484                Ok(Self::Floating64(value))
485            }
486
487            PropertyType::Currency => {
488                let value = f.read_i64::<LittleEndian>()?;
489                Ok(Self::Currency(value))
490            }
491
492            PropertyType::FloatingTime => {
493                let value = f.read_f64::<LittleEndian>()?;
494                Ok(Self::FloatingTime(value))
495            }
496
497            PropertyType::Integer64 => {
498                let value = f.read_i64::<LittleEndian>()?;
499                Ok(Self::Integer64(value))
500            }
501
502            PropertyType::String8 => {
503                let mut buffer = Vec::new();
504                f.read_to_end(&mut buffer)?;
505                if let Some(end) = buffer.iter().position(|&b| b == 0) {
506                    buffer.truncate(end);
507                }
508                Ok(Self::String8(String8Value { buffer }))
509            }
510
511            PropertyType::Unicode => {
512                let mut buffer = Vec::new();
513                while let Ok(ch) = f.read_u16::<LittleEndian>() {
514                    if ch == 0 {
515                        break;
516                    }
517                    buffer.push(ch);
518                }
519                Ok(Self::Unicode(UnicodeValue { buffer }))
520            }
521
522            PropertyType::Time => {
523                let value = f.read_i64::<LittleEndian>()?;
524                Ok(Self::Time(value))
525            }
526
527            PropertyType::Guid => {
528                let data1 = f.read_u32::<LittleEndian>()?;
529                let data2 = f.read_u16::<LittleEndian>()?;
530                let data3 = f.read_u16::<LittleEndian>()?;
531                let mut data4 = [0; 8];
532                f.read_exact(&mut data4)?;
533                Ok(Self::Guid(GuidValue {
534                    data1,
535                    data2,
536                    data3,
537                    data4,
538                }))
539            }
540
541            PropertyType::Binary => {
542                let mut buffer = Vec::new();
543                f.read_to_end(&mut buffer)?;
544                Ok(Self::Binary(BinaryValue { buffer }))
545            }
546
547            PropertyType::Object => {
548                let node_id = NodeId::read(f)?;
549                let size = f.read_u32::<LittleEndian>()?;
550                Ok(Self::Object(ObjectValue { node_id, size }))
551            }
552
553            PropertyType::MultipleInteger16 => {
554                let mut values = Vec::new();
555                while let Ok(value) = f.read_i16::<LittleEndian>() {
556                    values.push(value);
557                }
558                Ok(Self::MultipleInteger16(values))
559            }
560
561            PropertyType::MultipleInteger32 => {
562                let mut values = Vec::new();
563                while let Ok(value) = f.read_i32::<LittleEndian>() {
564                    values.push(value);
565                }
566                Ok(Self::MultipleInteger32(values))
567            }
568
569            PropertyType::MultipleFloating32 => {
570                let mut values = Vec::new();
571                while let Ok(value) = f.read_f32::<LittleEndian>() {
572                    values.push(value);
573                }
574                Ok(Self::MultipleFloating32(values))
575            }
576
577            PropertyType::MultipleFloating64 => {
578                let mut values = Vec::new();
579                while let Ok(value) = f.read_f64::<LittleEndian>() {
580                    values.push(value);
581                }
582                Ok(Self::MultipleFloating64(values))
583            }
584
585            PropertyType::MultipleCurrency => {
586                let mut values = Vec::new();
587                while let Ok(value) = f.read_i64::<LittleEndian>() {
588                    values.push(value);
589                }
590                Ok(Self::MultipleCurrency(values))
591            }
592
593            PropertyType::MultipleFloatingTime => {
594                let mut values = Vec::new();
595                while let Ok(value) = f.read_f64::<LittleEndian>() {
596                    values.push(value);
597                }
598                Ok(Self::MultipleFloatingTime(values))
599            }
600
601            PropertyType::MultipleInteger64 => {
602                let mut values = Vec::new();
603                while let Ok(value) = f.read_i64::<LittleEndian>() {
604                    values.push(value);
605                }
606                Ok(Self::MultipleInteger64(values))
607            }
608
609            PropertyType::MultipleString8 => {
610                // ulCount
611                let count = f.read_u32::<LittleEndian>()? as usize;
612
613                // rgulDataOffsets
614                let mut offsets = Vec::with_capacity(count);
615                for _ in 0..count {
616                    offsets.push(f.read_u32::<LittleEndian>()? as usize);
617                }
618
619                // rgDataItems
620                let mut start = (offsets.len() + 1) * mem::size_of::<u32>();
621                let mut values = Vec::with_capacity(offsets.len());
622                for i in 0..offsets.len() {
623                    let next = offsets[i];
624                    if next != start {
625                        return Err(LtpError::InvalidMultiValuePropertyOffset(next).into());
626                    }
627
628                    let mut buffer = if i < offsets.len() - 1 {
629                        let next = offsets[i + 1];
630                        if next < start {
631                            return Err(LtpError::InvalidMultiValuePropertyOffset(next).into());
632                        }
633
634                        if next > start {
635                            let mut buffer = vec![0; next - start];
636                            start = next;
637                            f.read_exact(&mut buffer)?;
638                            buffer
639                        } else {
640                            Default::default()
641                        }
642                    } else {
643                        let mut buffer = Vec::new();
644                        f.read_to_end(&mut buffer)?;
645                        buffer
646                    };
647
648                    if let Some(end) = buffer.iter().position(|&b| b == 0) {
649                        buffer.truncate(end);
650                    }
651
652                    values.push(String8Value { buffer });
653                }
654
655                Ok(Self::MultipleString8(values))
656            }
657
658            PropertyType::MultipleUnicode => {
659                // ulCount
660                let count = f.read_u32::<LittleEndian>()? as usize;
661
662                // rgulDataOffsets
663                let mut offsets = Vec::with_capacity(count);
664                for _ in 0..count {
665                    offsets.push(f.read_u32::<LittleEndian>()? as usize);
666                }
667
668                // rgDataItems
669                let mut start = (offsets.len() + 1) * mem::size_of::<u32>();
670                let mut values = Vec::with_capacity(offsets.len());
671                for i in 0..offsets.len() {
672                    let next = offsets[i];
673                    if next != start {
674                        return Err(LtpError::InvalidMultiValuePropertyOffset(next).into());
675                    }
676
677                    let mut buffer = Vec::new();
678                    if i < offsets.len() - 1 {
679                        let next = offsets[i + 1];
680                        if next < start {
681                            return Err(LtpError::InvalidMultiValuePropertyOffset(next).into());
682                        }
683
684                        while start < next {
685                            let ch = f.read_u16::<LittleEndian>()?;
686                            buffer.push(ch);
687                            start += mem::size_of::<u16>();
688                        }
689                    } else {
690                        while let Ok(ch) = f.read_u16::<LittleEndian>() {
691                            buffer.push(ch);
692                        }
693                    };
694
695                    if let Some(end) = buffer.iter().position(|&ch| ch == 0) {
696                        buffer.truncate(end);
697                    }
698
699                    values.push(UnicodeValue { buffer });
700                }
701
702                Ok(Self::MultipleUnicode(values))
703            }
704
705            PropertyType::MultipleTime => {
706                let mut values = Vec::new();
707                while let Ok(value) = f.read_i64::<LittleEndian>() {
708                    values.push(value);
709                }
710                Ok(Self::MultipleTime(values))
711            }
712
713            PropertyType::MultipleGuid => {
714                let count = f.read_u32::<LittleEndian>()? as usize;
715                let mut values = Vec::with_capacity(count);
716                for _ in 0..count {
717                    let data1 = f.read_u32::<LittleEndian>()?;
718                    let data2 = f.read_u16::<LittleEndian>()?;
719                    let data3 = f.read_u16::<LittleEndian>()?;
720                    let mut data4 = [0; 8];
721                    f.read_exact(&mut data4)?;
722                    values.push(GuidValue {
723                        data1,
724                        data2,
725                        data3,
726                        data4,
727                    });
728                }
729
730                Ok(Self::MultipleGuid(values))
731            }
732
733            PropertyType::MultipleBinary => {
734                // ulCount
735                let count = f.read_u32::<LittleEndian>()? as usize;
736
737                // rgulDataOffsets
738                let mut offsets = Vec::with_capacity(count);
739                for _ in 0..count {
740                    offsets.push(f.read_u32::<LittleEndian>()? as usize);
741                }
742
743                // rgDataItems
744                let mut start = (offsets.len() + 1) * mem::size_of::<u32>();
745                let mut values = Vec::with_capacity(offsets.len());
746                for i in 0..offsets.len() {
747                    let next = offsets[i];
748                    if next != start {
749                        return Err(LtpError::InvalidMultiValuePropertyOffset(next).into());
750                    }
751
752                    let buffer = if i < offsets.len() - 1 {
753                        let next = offsets[i + 1];
754                        if next < start {
755                            return Err(LtpError::InvalidMultiValuePropertyOffset(next).into());
756                        }
757
758                        if next > start {
759                            let mut buffer = vec![0; next - start];
760                            start = next;
761                            f.read_exact(&mut buffer)?;
762                            buffer
763                        } else {
764                            Default::default()
765                        }
766                    } else {
767                        let mut buffer = Vec::new();
768                        f.read_to_end(&mut buffer)?;
769                        buffer
770                    };
771
772                    values.push(BinaryValue { buffer });
773                }
774
775                Ok(Self::MultipleBinary(values))
776            }
777
778            _ => Err(LtpError::InvalidVariableLengthPropertyType(prop_type).into()),
779        }
780    }
781
782    fn write(&self, f: &mut dyn Write) -> io::Result<()> {
783        match self {
784            Self::Floating64(value) => f.write_f64::<LittleEndian>(*value),
785
786            Self::Currency(value) => f.write_i64::<LittleEndian>(*value),
787
788            Self::FloatingTime(value) => f.write_f64::<LittleEndian>(*value),
789
790            Self::Integer64(value) => f.write_i64::<LittleEndian>(*value),
791
792            Self::String8(value) => f.write_all(value.buffer()),
793
794            Self::Unicode(value) => {
795                for ch in value.buffer() {
796                    f.write_u16::<LittleEndian>(*ch)?;
797                }
798                Ok(())
799            }
800
801            Self::Time(value) => f.write_i64::<LittleEndian>(*value),
802
803            Self::Guid(value) => {
804                f.write_u32::<LittleEndian>(value.data1)?;
805                f.write_u16::<LittleEndian>(value.data2)?;
806                f.write_u16::<LittleEndian>(value.data3)?;
807                f.write_all(&value.data4)
808            }
809
810            Self::Binary(value) => f.write_all(value.buffer()),
811
812            Self::Object(value) => {
813                value.node_id.write(f)?;
814                f.write_u32::<LittleEndian>(value.size)
815            }
816
817            Self::MultipleInteger16(values) => {
818                for value in values {
819                    f.write_i16::<LittleEndian>(*value)?;
820                }
821                Ok(())
822            }
823
824            Self::MultipleInteger32(values) => {
825                for value in values {
826                    f.write_i32::<LittleEndian>(*value)?;
827                }
828                Ok(())
829            }
830
831            Self::MultipleFloating32(values) => {
832                for value in values {
833                    f.write_f32::<LittleEndian>(*value)?;
834                }
835                Ok(())
836            }
837
838            Self::MultipleFloating64(values) => {
839                for value in values {
840                    f.write_f64::<LittleEndian>(*value)?;
841                }
842                Ok(())
843            }
844
845            Self::MultipleCurrency(values) => {
846                for value in values {
847                    f.write_i64::<LittleEndian>(*value)?;
848                }
849                Ok(())
850            }
851
852            Self::MultipleFloatingTime(values) => {
853                for value in values {
854                    f.write_f64::<LittleEndian>(*value)?;
855                }
856                Ok(())
857            }
858
859            Self::MultipleInteger64(values) => {
860                for value in values {
861                    f.write_i64::<LittleEndian>(*value)?;
862                }
863                Ok(())
864            }
865
866            Self::MultipleString8(values) => {
867                // ulCount
868                let count = u32::try_from(values.len())
869                    .map_err(|_| LtpError::InvalidMultiValuePropertyCount(values.len()))?;
870                f.write_u32::<LittleEndian>(count)?;
871
872                // rgulDataOffsets
873                let mut start = (values.len() + 1) * mem::size_of::<u32>();
874                for value in values {
875                    let offset = u32::try_from(start)
876                        .map_err(|_| LtpError::InvalidMultiValuePropertyOffset(start))?;
877                    f.write_u32::<LittleEndian>(offset)?;
878                    start += value.buffer().len();
879                }
880
881                // rgDataItems
882                for value in values {
883                    f.write_all(value.buffer())?;
884                }
885
886                Ok(())
887            }
888
889            Self::MultipleUnicode(values) => {
890                // ulCount
891                let count = u32::try_from(values.len())
892                    .map_err(|_| LtpError::InvalidMultiValuePropertyCount(values.len()))?;
893                f.write_u32::<LittleEndian>(count)?;
894
895                // rgulDataOffsets
896                let mut start = (values.len() + 1) * mem::size_of::<u32>();
897                for value in values {
898                    let offset = u32::try_from(start)
899                        .map_err(|_| LtpError::InvalidMultiValuePropertyOffset(start))?;
900                    f.write_u32::<LittleEndian>(offset)?;
901                    start += mem::size_of_val(value.buffer());
902                }
903
904                // rgDataItems
905                for value in values {
906                    for ch in value.buffer() {
907                        f.write_u16::<LittleEndian>(*ch)?;
908                    }
909                }
910
911                Ok(())
912            }
913
914            Self::MultipleTime(values) => {
915                for value in values {
916                    f.write_i64::<LittleEndian>(*value)?;
917                }
918                Ok(())
919            }
920
921            Self::MultipleGuid(values) => {
922                for value in values {
923                    f.write_u32::<LittleEndian>(value.data1)?;
924                    f.write_u16::<LittleEndian>(value.data2)?;
925                    f.write_u16::<LittleEndian>(value.data3)?;
926                    f.write_all(&value.data4)?;
927                }
928                Ok(())
929            }
930
931            Self::MultipleBinary(values) => {
932                // ulCount
933                let count = u32::try_from(values.len())
934                    .map_err(|_| LtpError::InvalidMultiValuePropertyCount(values.len()))?;
935                f.write_u32::<LittleEndian>(count)?;
936
937                // rgulDataOffsets
938                let mut start = (values.len() + 1) * mem::size_of::<u32>();
939                for value in values {
940                    let offset = u32::try_from(start)
941                        .map_err(|_| LtpError::InvalidMultiValuePropertyOffset(start))?;
942                    f.write_u32::<LittleEndian>(offset)?;
943                    start += value.buffer().len();
944                }
945
946                // rgDataItems
947                for value in values {
948                    f.write_all(value.buffer())?;
949                }
950
951                Ok(())
952            }
953
954            _ => Err(LtpError::InvalidVariableLengthPropertyType(self.into()).into()),
955        }
956    }
957}
958
959pub type PropertyTree = dyn HeapTree<Key = PropertyTreeRecordKey, Value = PropertyTreeRecordValue>;
960
961pub trait PropertyContext {
962    fn tree(&self) -> &PropertyTree;
963    fn properties(&self) -> io::Result<BTreeMap<PropertyTreeRecordKey, PropertyTreeRecordValue>>;
964}
965
966struct PropertyContextInner<Pst>
967where
968    Pst: PstFile,
969{
970    node: <Pst as PstFile>::NodeBTreeEntry,
971    tree: <Pst as PstFile>::PropertyTree,
972    block_cache: RefCell<DataBlockCache<Pst>>,
973}
974
975impl<Pst> PropertyContextInner<Pst>
976where
977    Pst: PstFile,
978    <Pst as PstFile>::BlockId: BlockId<Index = <Pst as PstFile>::BTreeKey> + BlockIdReadWrite,
979    <Pst as PstFile>::ByteIndex: ByteIndexReadWrite,
980    <Pst as PstFile>::BlockRef: BlockRefReadWrite,
981    <Pst as PstFile>::PageTrailer: PageTrailerReadWrite,
982    <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
983    <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
984    <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
985    <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
986        RootBTreeIntermediatePageReadWrite<
987            Pst,
988            <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
989            <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
990        >,
991    <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
992        RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
993    <Pst as PstFile>::BlockTrailer: BlockTrailerReadWrite,
994    <Pst as PstFile>::DataTreeBlock: IntermediateTreeBlockReadWrite,
995    <<Pst as PstFile>::DataTreeBlock as IntermediateTreeBlock>::Entry:
996        IntermediateTreeEntryReadWrite,
997    <Pst as PstFile>::DataBlock: BlockReadWrite + Clone,
998    <Pst as PstFile>::SubNodeTreeBlockHeader: IntermediateTreeHeaderReadWrite,
999    <Pst as PstFile>::SubNodeTreeBlock: IntermediateTreeBlockReadWrite,
1000    <<Pst as PstFile>::SubNodeTreeBlock as IntermediateTreeBlock>::Entry:
1001        IntermediateTreeEntryReadWrite,
1002    <Pst as PstFile>::SubNodeBlock: IntermediateTreeBlockReadWrite,
1003    <<Pst as PstFile>::SubNodeBlock as IntermediateTreeBlock>::Entry:
1004        IntermediateTreeEntryReadWrite,
1005{
1006    fn new(node: <Pst as PstFile>::NodeBTreeEntry, tree: <Pst as PstFile>::PropertyTree) -> Self {
1007        Self {
1008            node,
1009            tree,
1010            block_cache: Default::default(),
1011        }
1012    }
1013
1014    fn properties(&self) -> io::Result<BTreeMap<PropertyTreeRecordKey, PropertyTreeRecordValue>> {
1015        Ok(self
1016            .tree
1017            .entries()?
1018            .into_iter()
1019            .map(|entry| {
1020                (
1021                    entry.key(),
1022                    PropertyTreeRecordValue::new(entry.data().prop_type(), entry.data().value()),
1023                )
1024            })
1025            .collect())
1026    }
1027
1028    fn read_property<R: PstReader>(
1029        &self,
1030        f: &mut R,
1031        encoding: NdbCryptMethod,
1032        block_btree: &PstFileReadWriteBlockBTree<Pst>,
1033        page_cache: &mut RootBTreePageCache<<Pst as PstFile>::BlockBTree>,
1034        value: PropertyTreeRecordValue,
1035    ) -> io::Result<PropertyValue> {
1036        match value.value() {
1037            PropertyValueRecord::Heap(heap_id) => {
1038                if u32::from(heap_id) == 0 {
1039                    return Ok(PropertyValue::Null);
1040                }
1041
1042                let data = self.tree.heap().find_entry(heap_id)?;
1043                let mut cursor = Cursor::new(data);
1044                PropertyValueReadWrite::read(&mut cursor, value.prop_type())
1045            }
1046            PropertyValueRecord::Node(sub_node_id) => {
1047                let sub_node =
1048                    self.node
1049                        .sub_node()
1050                        .ok_or(LtpError::PropertySubNodeValueNotFound(u32::from(
1051                            sub_node_id,
1052                        )))?;
1053                let block = block_btree.find_entry(f, sub_node.search_key(), page_cache)?;
1054                let sub_node_tree = SubNodeTree::<Pst>::read(f, &block)?;
1055                let block = sub_node_tree.find_entry(f, block_btree, sub_node_id, page_cache)?;
1056                let block = block_btree.find_entry(f, block.search_key(), page_cache)?;
1057                let mut block_cache = self.block_cache.borrow_mut();
1058                let data_tree = match block_cache.remove(&block.block().block()) {
1059                    Some(data_tree) => data_tree,
1060                    None => DataTree::read(f, encoding, &block)?,
1061                };
1062                let mut data = vec![];
1063                let result = data_tree
1064                    .reader(f, encoding, block_btree, page_cache, &mut block_cache)
1065                    .and_then(|mut r| r.read_to_end(&mut data));
1066                block_cache.insert(block.block().block(), data_tree);
1067                let _ = result?;
1068                let mut cursor = Cursor::new(data);
1069                PropertyValueReadWrite::read(&mut cursor, value.prop_type())
1070            }
1071            small => small
1072                .small_value(value.prop_type())
1073                .ok_or(LtpError::InvalidSmallPropertyType(value.prop_type()).into()),
1074        }
1075    }
1076}
1077
1078pub struct UnicodePropertyContext {
1079    inner: PropertyContextInner<UnicodePstFile>,
1080}
1081
1082impl UnicodePropertyContext {
1083    pub fn new(
1084        node: UnicodeNodeBTreeEntry,
1085        tree: <UnicodePstFile as PstFile>::PropertyTree,
1086    ) -> Self {
1087        <Self as PropertyContextReadWrite<UnicodePstFile>>::new(node, tree)
1088    }
1089
1090    pub fn read_property<R: PstReader>(
1091        &self,
1092        f: &mut R,
1093        encoding: NdbCryptMethod,
1094        block_btree: &UnicodeBlockBTree,
1095        page_cache: &mut RootBTreePageCache<UnicodeBlockBTree>,
1096        value: PropertyTreeRecordValue,
1097    ) -> io::Result<PropertyValue> {
1098        <Self as PropertyContextReadWrite<UnicodePstFile>>::read_property(
1099            self,
1100            f,
1101            encoding,
1102            block_btree,
1103            page_cache,
1104            value,
1105        )
1106    }
1107}
1108
1109impl PropertyContext for UnicodePropertyContext {
1110    fn tree(&self) -> &PropertyTree {
1111        &self.inner.tree
1112    }
1113
1114    fn properties(&self) -> io::Result<BTreeMap<PropertyTreeRecordKey, PropertyTreeRecordValue>> {
1115        self.inner.properties()
1116    }
1117}
1118
1119impl PropertyContextReadWrite<UnicodePstFile> for UnicodePropertyContext {
1120    fn new(node: UnicodeNodeBTreeEntry, tree: <UnicodePstFile as PstFile>::PropertyTree) -> Self {
1121        let inner = PropertyContextInner::new(node, tree);
1122        Self { inner }
1123    }
1124
1125    fn read_property<R: PstReader>(
1126        &self,
1127        f: &mut R,
1128        encoding: NdbCryptMethod,
1129        block_btree: &UnicodeBlockBTree,
1130        page_cache: &mut RootBTreePageCache<UnicodeBlockBTree>,
1131        value: PropertyTreeRecordValue,
1132    ) -> io::Result<PropertyValue> {
1133        self.inner
1134            .read_property(f, encoding, block_btree, page_cache, value)
1135    }
1136}
1137
1138pub struct AnsiPropertyContext {
1139    inner: PropertyContextInner<AnsiPstFile>,
1140}
1141
1142impl AnsiPropertyContext {
1143    pub fn new(node: AnsiNodeBTreeEntry, tree: <AnsiPstFile as PstFile>::PropertyTree) -> Self {
1144        <Self as PropertyContextReadWrite<AnsiPstFile>>::new(node, tree)
1145    }
1146
1147    pub fn read_property<R: PstReader>(
1148        &self,
1149        f: &mut R,
1150        encoding: NdbCryptMethod,
1151        block_btree: &AnsiBlockBTree,
1152        page_cache: &mut RootBTreePageCache<AnsiBlockBTree>,
1153        value: PropertyTreeRecordValue,
1154    ) -> io::Result<PropertyValue> {
1155        <Self as PropertyContextReadWrite<AnsiPstFile>>::read_property(
1156            self,
1157            f,
1158            encoding,
1159            block_btree,
1160            page_cache,
1161            value,
1162        )
1163    }
1164}
1165
1166impl PropertyContext for AnsiPropertyContext {
1167    fn tree(&self) -> &PropertyTree {
1168        &self.inner.tree
1169    }
1170
1171    fn properties(&self) -> io::Result<BTreeMap<PropertyTreeRecordKey, PropertyTreeRecordValue>> {
1172        self.inner.properties()
1173    }
1174}
1175
1176impl PropertyContextReadWrite<AnsiPstFile> for AnsiPropertyContext {
1177    fn new(node: AnsiNodeBTreeEntry, tree: <AnsiPstFile as PstFile>::PropertyTree) -> Self {
1178        let inner = PropertyContextInner::new(node, tree);
1179        Self { inner }
1180    }
1181
1182    fn read_property<R: PstReader>(
1183        &self,
1184        f: &mut R,
1185        encoding: NdbCryptMethod,
1186        block_btree: &AnsiBlockBTree,
1187        page_cache: &mut RootBTreePageCache<AnsiBlockBTree>,
1188        value: PropertyTreeRecordValue,
1189    ) -> io::Result<PropertyValue> {
1190        self.inner
1191            .read_property(f, encoding, block_btree, page_cache, value)
1192    }
1193}