1use 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 let prop_type = f.read_u16::<LittleEndian>()?;
123 let prop_type = PropertyType::try_from(prop_type)?;
124
125 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#[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 #[default]
366 Null,
367 Integer16(i16),
369 Integer32(i32),
371 Floating32(f32),
373 Floating64(f64),
375 Currency(i64),
378 FloatingTime(f64),
382 ErrorCode(i32),
385 Boolean(bool),
387 Integer64(i64),
389 String8(String8Value),
392 Unicode(UnicodeValue),
395 Time(i64),
398 Guid(GuidValue),
400 Binary(BinaryValue),
402 Object(ObjectValue),
405
406 MultipleInteger16(Vec<i16>),
409 MultipleInteger32(Vec<i32>),
412 MultipleFloating32(Vec<f32>),
415 MultipleFloating64(Vec<f64>),
418 MultipleCurrency(Vec<i64>),
421 MultipleFloatingTime(Vec<f64>),
424 MultipleInteger64(Vec<i64>),
427 MultipleString8(Vec<String8Value>),
430 MultipleUnicode(Vec<UnicodeValue>),
433 MultipleTime(Vec<i64>),
436 MultipleGuid(Vec<GuidValue>),
439 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 let count = f.read_u32::<LittleEndian>()? as usize;
612
613 let mut offsets = Vec::with_capacity(count);
615 for _ in 0..count {
616 offsets.push(f.read_u32::<LittleEndian>()? as usize);
617 }
618
619 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 let count = f.read_u32::<LittleEndian>()? as usize;
661
662 let mut offsets = Vec::with_capacity(count);
664 for _ in 0..count {
665 offsets.push(f.read_u32::<LittleEndian>()? as usize);
666 }
667
668 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 let count = f.read_u32::<LittleEndian>()? as usize;
736
737 let mut offsets = Vec::with_capacity(count);
739 for _ in 0..count {
740 offsets.push(f.read_u32::<LittleEndian>()? as usize);
741 }
742
743 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 let count = u32::try_from(values.len())
869 .map_err(|_| LtpError::InvalidMultiValuePropertyCount(values.len()))?;
870 f.write_u32::<LittleEndian>(count)?;
871
872 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 for value in values {
883 f.write_all(value.buffer())?;
884 }
885
886 Ok(())
887 }
888
889 Self::MultipleUnicode(values) => {
890 let count = u32::try_from(values.len())
892 .map_err(|_| LtpError::InvalidMultiValuePropertyCount(values.len()))?;
893 f.write_u32::<LittleEndian>(count)?;
894
895 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 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 let count = u32::try_from(values.len())
934 .map_err(|_| LtpError::InvalidMultiValuePropertyCount(values.len()))?;
935 f.write_u32::<LittleEndian>(count)?;
936
937 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 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}