1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4use std::{
5 cell::RefCell,
6 collections::BTreeMap,
7 fmt::Debug,
8 io::{self, Cursor, Read, Write},
9 marker::PhantomData,
10 rc::Rc,
11};
12
13use super::{heap::*, prop_context::*, prop_type::*, read_write::*, tree::*, *};
14use crate::{
15 messaging::{
16 read_write::StoreReadWrite,
17 store::{AnsiStore, UnicodeStore},
18 },
19 ndb::{
20 block::{Block, DataBlockCache, DataTree, IntermediateTreeBlock, SubNodeTree},
21 block_id::BlockId,
22 block_ref::BlockRef,
23 header::Header,
24 node_id::{NodeId, NodeIdType},
25 page::{
26 AnsiNodeBTreeEntry, BlockBTreeEntry, NodeBTreeEntry, RootBTree, UnicodeNodeBTreeEntry,
27 },
28 read_write::*,
29 root::Root,
30 },
31 AnsiPstFile, PstFile, PstFileLock, UnicodePstFile,
32};
33
34pub const LTP_ROW_ID_PROP_ID: u16 = 0x67F2;
35pub const LTP_ROW_VERSION_PROP_ID: u16 = 0x67F3;
36
37pub const fn existence_bitmap_size(column_count: usize) -> usize {
38 column_count / 8 + if column_count % 8 == 0 { 0 } else { 1 }
39}
40
41pub const fn check_existence_bitmap(column: usize, existence_bitmap: &[u8]) -> LtpResult<bool> {
42 if column >= existence_bitmap.len() * 8 {
43 return Err(LtpError::InvalidTableContextColumnCount(column));
44 }
45 Ok(existence_bitmap[column / 8] & (1_u8 << (7 - (column % 8))) != 0)
46}
47
48#[derive(Clone, Default, Debug)]
50pub struct TableContextInfo {
51 end_4byte_values: u16,
52 end_2byte_values: u16,
53 end_1byte_values: u16,
54 end_existence_bitmap: u16,
55 row_index: HeapId,
56 rows: Option<NodeId>,
57 _deprecated_index: u32,
58 columns: Vec<TableColumnDescriptor>,
59}
60
61impl TableContextInfo {
62 pub fn new(
63 end_4byte_values: u16,
64 end_2byte_values: u16,
65 end_1byte_values: u16,
66 end_existence_bitmap: u16,
67 row_index: HeapId,
68 rows: Option<NodeId>,
69 columns: Vec<TableColumnDescriptor>,
70 ) -> LtpResult<Self> {
71 if columns.len() > 0xFF {
72 return Err(LtpError::InvalidTableContextColumnCount(columns.len()));
73 }
74
75 if end_4byte_values % 4 != 0 {
76 return Err(LtpError::InvalidTableContext4ByteOffset(end_4byte_values));
77 }
78
79 if end_2byte_values % 2 != 0 || end_2byte_values < end_4byte_values {
80 return Err(LtpError::InvalidTableContext2ByteOffset(end_2byte_values));
81 }
82
83 if end_1byte_values < end_2byte_values {
84 return Err(LtpError::InvalidTableContext1ByteOffset(end_1byte_values));
85 }
86
87 if end_existence_bitmap < end_1byte_values
88 || (end_existence_bitmap - end_1byte_values) as usize
89 != existence_bitmap_size(columns.len())
90 {
91 return Err(LtpError::InvalidTableContextBitmaskOffset(
92 end_existence_bitmap,
93 ));
94 }
95
96 for column in columns.iter() {
97 match (column.prop_type(), column.prop_id()) {
98 (PropertyType::Integer32, LTP_ROW_ID_PROP_ID) => {
99 match (column.offset(), column.existence_bitmap_index()) {
100 (0, 0) => {}
101 _ => {
102 return Err(LtpError::InvalidTableContextRowIdColumn(
103 column.prop_id(),
104 column.prop_type(),
105 ));
106 }
107 }
108 }
109 (PropertyType::Integer32, LTP_ROW_VERSION_PROP_ID) => {
110 match (column.offset(), column.existence_bitmap_index()) {
111 (4, 1) => {}
112 _ => {
113 return Err(LtpError::InvalidTableContextRowIdColumn(
114 column.prop_id(),
115 column.prop_type(),
116 ));
117 }
118 }
119 }
120 _ => {}
121 }
122
123 match column.prop_type() {
124 PropertyType::Integer16
125 | PropertyType::Integer32
126 | PropertyType::Floating32
127 | PropertyType::Floating64
128 | PropertyType::Currency
129 | PropertyType::FloatingTime
130 | PropertyType::ErrorCode
131 | PropertyType::Boolean
132 | PropertyType::Integer64
133 | PropertyType::String8
134 | PropertyType::Unicode
135 | PropertyType::Time
136 | PropertyType::Guid
137 | PropertyType::Binary
138 | PropertyType::Object
139 | PropertyType::MultipleInteger16
140 | PropertyType::MultipleInteger32
141 | PropertyType::MultipleFloating32
142 | PropertyType::MultipleFloating64
143 | PropertyType::MultipleCurrency
144 | PropertyType::MultipleFloatingTime
145 | PropertyType::MultipleInteger64
146 | PropertyType::MultipleString8
147 | PropertyType::MultipleUnicode
148 | PropertyType::MultipleTime
149 | PropertyType::MultipleGuid
150 | PropertyType::MultipleBinary => {}
151 prop_type => {
152 return Err(LtpError::InvalidTableColumnPropertyType(prop_type));
153 }
154 }
155
156 match (column.prop_type(), column.offset()) {
157 (PropertyType::Boolean, offset)
158 if offset >= end_2byte_values && offset < end_1byte_values => {}
159 (PropertyType::Integer16, offset)
160 if offset % 2 == 0
161 && offset >= end_4byte_values
162 && offset + 2 <= end_2byte_values => {}
163 (
164 PropertyType::Integer32
165 | PropertyType::Floating32
166 | PropertyType::ErrorCode
167 | PropertyType::String8
168 | PropertyType::Unicode
169 | PropertyType::Guid
170 | PropertyType::Binary
171 | PropertyType::Object
172 | PropertyType::MultipleInteger16
173 | PropertyType::MultipleInteger32
174 | PropertyType::MultipleFloating32
175 | PropertyType::MultipleFloating64
176 | PropertyType::MultipleCurrency
177 | PropertyType::MultipleFloatingTime
178 | PropertyType::MultipleInteger64
179 | PropertyType::MultipleString8
180 | PropertyType::MultipleUnicode
181 | PropertyType::MultipleTime
182 | PropertyType::MultipleGuid
183 | PropertyType::MultipleBinary,
184 offset,
185 ) if offset % 4 == 0 && offset + 4 <= end_4byte_values => {}
186 (
187 PropertyType::Floating64
188 | PropertyType::Currency
189 | PropertyType::FloatingTime
190 | PropertyType::Integer64
191 | PropertyType::Time,
192 offset,
193 ) if offset % 4 == 0 && offset + 8 <= end_4byte_values => {}
194 (_, offset) => {
195 return Err(LtpError::InvalidTableColumnOffset(offset));
196 }
197 }
198
199 match (column.prop_type(), column.size()) {
200 (PropertyType::Boolean, 1) => {}
201 (PropertyType::Integer16, 2) => {}
202 (
203 PropertyType::Integer32
204 | PropertyType::Floating32
205 | PropertyType::ErrorCode
206 | PropertyType::String8
207 | PropertyType::Unicode
208 | PropertyType::Guid
209 | PropertyType::Binary
210 | PropertyType::Object
211 | PropertyType::MultipleInteger16
212 | PropertyType::MultipleInteger32
213 | PropertyType::MultipleFloating32
214 | PropertyType::MultipleFloating64
215 | PropertyType::MultipleCurrency
216 | PropertyType::MultipleFloatingTime
217 | PropertyType::MultipleInteger64
218 | PropertyType::MultipleString8
219 | PropertyType::MultipleUnicode
220 | PropertyType::MultipleTime
221 | PropertyType::MultipleGuid
222 | PropertyType::MultipleBinary,
223 4,
224 ) => {}
225 (
226 PropertyType::Floating64
227 | PropertyType::Currency
228 | PropertyType::FloatingTime
229 | PropertyType::Integer64
230 | PropertyType::Time,
231 8,
232 ) => {}
233 (_, size) => {
234 return Err(LtpError::InvalidTableColumnSize(size));
235 }
236 }
237
238 if usize::from(column.existence_bitmap_index()) > columns.len() {
239 return Err(LtpError::InvalidTableColumnBitmaskOffset(
240 column.existence_bitmap_index(),
241 ));
242 }
243 }
244
245 Ok(Self {
246 end_4byte_values,
247 end_2byte_values,
248 end_1byte_values,
249 end_existence_bitmap,
250 row_index,
251 rows,
252 _deprecated_index: 0,
253 columns,
254 })
255 }
256
257 pub fn end_4byte_values(&self) -> u16 {
258 self.end_4byte_values
259 }
260
261 pub fn end_2byte_values(&self) -> u16 {
262 self.end_2byte_values
263 }
264
265 pub fn end_1byte_values(&self) -> u16 {
266 self.end_1byte_values
267 }
268
269 pub fn end_existence_bitmap(&self) -> u16 {
270 self.end_existence_bitmap
271 }
272
273 pub fn columns(&self) -> &[TableColumnDescriptor] {
274 &self.columns
275 }
276}
277
278impl TableContextInfoReadWrite for TableContextInfo {
279 fn read(f: &mut dyn Read) -> io::Result<Self> {
280 let signature = HeapNodeType::try_from(f.read_u8()?)?;
282 if signature != HeapNodeType::Table {
283 return Err(LtpError::InvalidTableContextHeapTreeNodeType(signature).into());
284 }
285
286 let column_count = f.read_u8()?;
288
289 let end_4byte_values = f.read_u16::<LittleEndian>()?;
291 let end_2byte_values = f.read_u16::<LittleEndian>()?;
292 let end_1byte_values = f.read_u16::<LittleEndian>()?;
293 let end_existence_bitmap = f.read_u16::<LittleEndian>()?;
294
295 let row_index = HeapId::read(f)?;
297
298 let rows = NodeId::read(f)?;
300 let rows = if u32::from(rows) == 0 {
301 None
302 } else {
303 Some(rows)
304 };
305
306 let _deprecated_index = f.read_u32::<LittleEndian>()?;
308
309 let mut columns = Vec::with_capacity(usize::from(column_count));
311 for _ in 0..column_count {
312 columns.push(TableColumnDescriptor::read(f)?);
313 }
314
315 Ok(Self {
316 _deprecated_index,
317 ..Self::new(
318 end_4byte_values,
319 end_2byte_values,
320 end_1byte_values,
321 end_existence_bitmap,
322 row_index,
323 rows,
324 columns,
325 )?
326 })
327 }
328
329 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
330 if self.columns.len() > 0xFF {
331 return Err(LtpError::InvalidTableContextColumnCount(self.columns.len()).into());
332 }
333
334 f.write_u8(HeapNodeType::Table as u8)?;
336
337 f.write_u8(self.columns.len() as u8)?;
339
340 f.write_u16::<LittleEndian>(self.end_4byte_values)?;
342 f.write_u16::<LittleEndian>(self.end_2byte_values)?;
343 f.write_u16::<LittleEndian>(self.end_1byte_values)?;
344 f.write_u16::<LittleEndian>(self.end_existence_bitmap)?;
345
346 self.row_index.write(f)?;
348
349 self.rows.unwrap_or_default().write(f)?;
351
352 f.write_u32::<LittleEndian>(self._deprecated_index)?;
354
355 for column in &self.columns {
357 column.write(f)?;
358 }
359
360 Ok(())
361 }
362}
363
364#[derive(Clone, Copy, Default, Debug)]
366pub struct TableColumnDescriptor {
367 prop_type: PropertyType,
368 prop_id: u16,
369 offset: u16,
370 size: u8,
371 existence_bitmap_index: u8,
372}
373
374impl TableColumnDescriptor {
375 pub fn new(
376 prop_type: PropertyType,
377 prop_id: u16,
378 offset: u16,
379 size: u8,
380 existence_bitmap_index: u8,
381 ) -> Self {
382 Self {
383 prop_type,
384 prop_id,
385 offset,
386 size,
387 existence_bitmap_index,
388 }
389 }
390
391 pub fn prop_type(&self) -> PropertyType {
392 self.prop_type
393 }
394
395 pub fn prop_id(&self) -> u16 {
396 self.prop_id
397 }
398
399 pub fn offset(&self) -> u16 {
400 self.offset
401 }
402
403 pub fn size(&self) -> u8 {
404 self.size
405 }
406
407 pub fn existence_bitmap_index(&self) -> u8 {
408 self.existence_bitmap_index
409 }
410}
411
412impl TableColumnDescriptorReadWrite for TableColumnDescriptor {
413 fn read(f: &mut dyn Read) -> io::Result<Self> {
414 let prop_type = PropertyType::try_from(f.read_u16::<LittleEndian>()?)?;
415 let prop_id = f.read_u16::<LittleEndian>()?;
416 let offset = f.read_u16::<LittleEndian>()?;
417 let size = f.read_u8()?;
418 let existence_bitmap_index = f.read_u8()?;
419
420 Ok(Self {
421 prop_type,
422 prop_id,
423 offset,
424 size,
425 existence_bitmap_index,
426 })
427 }
428
429 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
430 f.write_u16::<LittleEndian>(self.prop_type as u16)?;
431 f.write_u16::<LittleEndian>(self.prop_id)?;
432 f.write_u16::<LittleEndian>(self.offset)?;
433 f.write_u8(self.size)?;
434 f.write_u8(self.existence_bitmap_index)?;
435
436 Ok(())
437 }
438}
439
440#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Debug)]
441pub struct TableRowId {
442 id: u32,
443}
444
445impl TableRowId {
446 pub fn new(id: u32) -> Self {
447 Self { id }
448 }
449}
450
451impl From<TableRowId> for u32 {
452 fn from(value: TableRowId) -> Self {
453 value.id
454 }
455}
456
457impl HeapTreeEntryKey for TableRowId {
458 const SIZE: u8 = 4;
459}
460
461impl HeapNodePageReadWrite for TableRowId {
462 fn read(f: &mut dyn Read) -> io::Result<Self> {
463 let id = f.read_u32::<LittleEndian>()?;
464 Ok(Self { id })
465 }
466
467 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
468 f.write_u32::<LittleEndian>(self.id)
469 }
470}
471
472trait TableRowIndex<Pst>: HeapTreeEntryValue + HeapNodePageReadWrite + Copy
473where
474 Pst: PstFile,
475 u32: From<Self>,
476{
477 type Index: Copy;
478}
479
480#[derive(Clone, Copy, Default, Debug)]
481pub struct UnicodeTableRowIndex {
482 index: u32,
483}
484
485impl TableRowIndex<UnicodePstFile> for UnicodeTableRowIndex {
486 type Index = u32;
487}
488
489impl From<UnicodeTableRowIndex> for u32 {
490 fn from(value: UnicodeTableRowIndex) -> Self {
491 value.index
492 }
493}
494
495impl HeapTreeEntryValue for UnicodeTableRowIndex {
496 const SIZE: u8 = 4;
497}
498
499impl HeapNodePageReadWrite for UnicodeTableRowIndex {
500 fn read(f: &mut dyn Read) -> io::Result<Self> {
501 let index = f.read_u32::<LittleEndian>()?;
502 Ok(Self { index })
503 }
504
505 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
506 f.write_u32::<LittleEndian>(self.index)
507 }
508}
509
510#[derive(Clone, Copy, Default, Debug)]
511pub struct AnsiTableRowIndex {
512 index: u16,
513}
514
515impl TableRowIndex<AnsiPstFile> for AnsiTableRowIndex {
516 type Index = u16;
517}
518
519impl From<AnsiTableRowIndex> for u32 {
520 fn from(value: AnsiTableRowIndex) -> Self {
521 u32::from(value.index)
522 }
523}
524
525impl HeapTreeEntryValue for AnsiTableRowIndex {
526 const SIZE: u8 = 2;
527}
528
529impl HeapNodePageReadWrite for AnsiTableRowIndex {
530 fn read(f: &mut dyn Read) -> io::Result<Self> {
531 let index = f.read_u16::<LittleEndian>()?;
532 Ok(Self { index })
533 }
534
535 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
536 f.write_u16::<LittleEndian>(self.index)
537 }
538}
539
540trait TableRowIndexTree<Pst>: HeapTreeReadWrite<Pst, Key = TableRowId, Value = Self::RowIndex>
541where
542 Pst: PstFile,
543 u32: From<Self::RowIndex>,
544{
545 type RowIndex: TableRowIndex<Pst>;
546}
547
548pub type UnicodeTableRowIdRecord = HeapTreeLeafEntry<TableRowId, UnicodeTableRowIndex>;
550
551pub type AnsiTableRowIdRecord = HeapTreeLeafEntry<TableRowId, AnsiTableRowIndex>;
553
554#[derive(Clone, Debug)]
555pub enum TableRowColumnValue {
556 Small(PropertyValue),
557 Heap(HeapId),
558 Node(NodeId),
559}
560
561pub struct TableRowData {
563 id: TableRowId,
564 unique: u32,
565 align_4byte: Vec<u8>,
566 align_2byte: Vec<u8>,
567 align_1byte: Vec<u8>,
568 existence_bitmap: Vec<u8>,
569}
570
571impl TableRowData {
572 pub fn new(
573 id: TableRowId,
574 unique: u32,
575 align_4byte: Vec<u8>,
576 align_2byte: Vec<u8>,
577 align_1byte: Vec<u8>,
578 existence_bitmap: Vec<u8>,
579 ) -> Self {
580 Self {
581 id,
582 unique,
583 align_4byte,
584 align_2byte,
585 align_1byte,
586 existence_bitmap,
587 }
588 }
589
590 pub fn id(&self) -> TableRowId {
591 self.id
592 }
593
594 pub fn unique(&self) -> u32 {
595 self.unique
596 }
597
598 pub fn columns(
599 &self,
600 context: &TableContextInfo,
601 ) -> io::Result<Vec<Option<TableRowColumnValue>>> {
602 context
603 .columns()
604 .iter()
605 .map(|column| {
606 let existence_bit = column.existence_bitmap_index() as usize;
607 if !check_existence_bitmap(existence_bit, &self.existence_bitmap)? {
608 return Ok(None);
609 }
610
611 match (column.prop_type(), column.offset(), column.size()) {
612 (PropertyType::Null, _, 0) => Ok(None),
613 (PropertyType::Integer16, offset, 2) => {
614 let mut cursor = self.read_2byte_offset(context, offset)?;
615 let value = cursor.read_i16::<LittleEndian>()?;
616 Ok(Some(TableRowColumnValue::Small(PropertyValue::Integer16(
617 value,
618 ))))
619 }
620 (PropertyType::Integer32, 0, 4) => Ok(Some(TableRowColumnValue::Small(
621 PropertyValue::Integer32(u32::from(self.id) as i32),
622 ))),
623 (PropertyType::Integer32, 4, 4) => Ok(Some(TableRowColumnValue::Small(
624 PropertyValue::Integer32(self.unique as i32),
625 ))),
626 (PropertyType::Integer32, offset, 4) => {
627 let mut cursor = self.read_4byte_offset(offset)?;
628 let value = cursor.read_i32::<LittleEndian>()?;
629 Ok(Some(TableRowColumnValue::Small(PropertyValue::Integer32(
630 value,
631 ))))
632 }
633 (PropertyType::Floating32, offset, 4) => {
634 let mut cursor = self.read_4byte_offset(offset)?;
635 let value = cursor.read_f32::<LittleEndian>()?;
636 Ok(Some(TableRowColumnValue::Small(PropertyValue::Floating32(
637 value,
638 ))))
639 }
640 (PropertyType::Floating64, offset, 8) => {
641 let mut cursor = self.read_8byte_offset(offset)?;
642 let value = cursor.read_f64::<LittleEndian>()?;
643 Ok(Some(TableRowColumnValue::Small(PropertyValue::Floating64(
644 value,
645 ))))
646 }
647 (PropertyType::Currency, offset, 8) => {
648 let mut cursor = self.read_8byte_offset(offset)?;
649 let value = cursor.read_i64::<LittleEndian>()?;
650 Ok(Some(TableRowColumnValue::Small(PropertyValue::Currency(
651 value,
652 ))))
653 }
654 (PropertyType::FloatingTime, offset, 8) => {
655 let mut cursor = self.read_8byte_offset(offset)?;
656 let value = cursor.read_f64::<LittleEndian>()?;
657 Ok(Some(TableRowColumnValue::Small(
658 PropertyValue::FloatingTime(value),
659 )))
660 }
661 (PropertyType::ErrorCode, offset, 4) => {
662 let mut cursor = self.read_4byte_offset(offset)?;
663 let value = cursor.read_i32::<LittleEndian>()?;
664 Ok(Some(TableRowColumnValue::Small(PropertyValue::ErrorCode(
665 value,
666 ))))
667 }
668 (PropertyType::Boolean, offset, 1) => {
669 let value = self.read_1byte_offset(context, offset)?;
670 Ok(Some(TableRowColumnValue::Small(PropertyValue::Boolean(
671 match value {
672 0x00 => false,
673 0x01 => true,
674 _ => {
675 return Err(
676 LtpError::InvalidTableColumnBooleanValue(value).into()
677 )
678 }
679 },
680 ))))
681 }
682 (PropertyType::Integer64, offset, 8) => {
683 let mut cursor = self.read_8byte_offset(offset)?;
684 let value = cursor.read_i64::<LittleEndian>()?;
685 Ok(Some(TableRowColumnValue::Small(PropertyValue::Integer64(
686 value,
687 ))))
688 }
689 (PropertyType::Time, offset, 8) => {
690 let mut cursor = self.read_8byte_offset(offset)?;
691 let value = cursor.read_i64::<LittleEndian>()?;
692 Ok(Some(TableRowColumnValue::Small(PropertyValue::Time(value))))
693 }
694 (
695 PropertyType::String8
696 | PropertyType::Unicode
697 | PropertyType::Guid
698 | PropertyType::Binary
699 | PropertyType::Object
700 | PropertyType::MultipleInteger16
701 | PropertyType::MultipleInteger32
702 | PropertyType::MultipleFloating32
703 | PropertyType::MultipleFloating64
704 | PropertyType::MultipleCurrency
705 | PropertyType::MultipleFloatingTime
706 | PropertyType::MultipleInteger64
707 | PropertyType::MultipleString8
708 | PropertyType::MultipleUnicode
709 | PropertyType::MultipleTime
710 | PropertyType::MultipleGuid
711 | PropertyType::MultipleBinary,
712 offset,
713 4,
714 ) => {
715 let mut cursor = self.read_4byte_offset(offset)?;
716 let node_id = NodeId::from(cursor.read_u32::<LittleEndian>()?);
717 let value = match node_id.id_type() {
718 Ok(NodeIdType::HeapNode) => {
719 TableRowColumnValue::Heap(HeapId::from(u32::from(node_id)))
720 }
721 _ => TableRowColumnValue::Node(node_id),
722 };
723 Ok(Some(value))
724 }
725 (_, _, size) => Err(LtpError::InvalidTableColumnSize(size).into()),
726 }
727 })
728 .collect()
729 }
730
731 fn read_1byte_offset(&self, context: &TableContextInfo, offset: u16) -> LtpResult<u8> {
732 if offset < context.end_2byte_values() {
733 return Err(LtpError::InvalidTableColumnOffset(offset));
734 }
735 let offset_1byte = (offset - context.end_2byte_values()) as usize;
736 if offset_1byte >= self.align_1byte.len() {
737 return Err(LtpError::InvalidTableColumnOffset(offset));
738 }
739 Ok(self.align_1byte[offset_1byte])
740 }
741
742 fn read_2byte_offset(&self, context: &TableContextInfo, offset: u16) -> LtpResult<&[u8]> {
743 if offset < context.end_4byte_values() {
744 return Err(LtpError::InvalidTableColumnOffset(offset));
745 }
746 let offset_2byte = (offset - context.end_4byte_values()) as usize;
747 if offset_2byte + 2 > self.align_2byte.len() {
748 return Err(LtpError::InvalidTableColumnOffset(offset));
749 }
750 Ok(&self.align_2byte[offset_2byte..offset_2byte + 2])
751 }
752
753 fn read_4byte_offset(&self, offset: u16) -> LtpResult<&[u8]> {
754 if offset < 8 {
755 return Err(LtpError::InvalidTableColumnOffset(offset));
756 }
757 let offset_4byte = (offset - 8) as usize;
758 if offset_4byte + 4 > self.align_4byte.len() {
759 return Err(LtpError::InvalidTableColumnOffset(offset));
760 }
761 Ok(&self.align_4byte[offset_4byte..offset_4byte + 4])
762 }
763
764 fn read_8byte_offset(&self, offset: u16) -> LtpResult<&[u8]> {
765 if offset < 8 {
766 return Err(LtpError::InvalidTableColumnOffset(offset));
767 }
768 let offset_4byte = (offset - 8) as usize;
769 if offset_4byte + 8 > self.align_4byte.len() {
770 return Err(LtpError::InvalidTableColumnOffset(offset));
771 }
772 Ok(&self.align_4byte[offset_4byte..offset_4byte + 8])
773 }
774}
775
776impl TableRowReadWrite for TableRowData {
777 fn read(f: &mut dyn Read, context: &TableContextInfo) -> io::Result<Self> {
778 let id = TableRowId {
780 id: f.read_u32::<LittleEndian>()?,
781 };
782
783 let unique = f.read_u32::<LittleEndian>()?;
785 let mut align_4byte = vec![0; context.end_4byte_values() as usize - 8];
786 f.read_exact(align_4byte.as_mut_slice())?;
787
788 let mut align_2byte =
790 vec![0; (context.end_2byte_values() - context.end_4byte_values()) as usize];
791 f.read_exact(align_2byte.as_mut_slice())?;
792
793 let mut align_1byte =
795 vec![0; (context.end_1byte_values() - context.end_2byte_values()) as usize];
796 f.read_exact(align_1byte.as_mut_slice())?;
797
798 let mut existence_bitmap = vec![0; existence_bitmap_size(context.columns().len())];
800 f.read_exact(existence_bitmap.as_mut_slice())?;
801
802 Ok(Self::new(
803 id,
804 unique,
805 align_4byte,
806 align_2byte,
807 align_1byte,
808 existence_bitmap,
809 ))
810 }
811
812 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
813 f.write_u32::<LittleEndian>(u32::from(self.id))?;
814 f.write_u32::<LittleEndian>(self.unique)?;
815 f.write_all(&self.align_4byte)?;
816 f.write_all(&self.align_2byte)?;
817 f.write_all(&self.align_1byte)?;
818 f.write_all(&self.existence_bitmap)
819 }
820}
821
822pub trait TableContext {
823 fn context(&self) -> &TableContextInfo;
824 fn rows_matrix<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = &'a TableRowData>>;
825 fn find_row(&self, id: TableRowId) -> LtpResult<&TableRowData>;
826 fn read_column(
827 &self,
828 value: &TableRowColumnValue,
829 prop_type: PropertyType,
830 ) -> io::Result<PropertyValue>;
831}
832
833struct TableContextInner<Pst, RowIndex, RowIndexTree>
834where
835 Pst: PstFile,
836 RowIndex: TableRowIndex<Pst>,
837 RowIndexTree: TableRowIndexTree<Pst, RowIndex = RowIndex>,
838 u32: From<RowIndex>,
839{
840 store: Rc<<Pst as PstFile>::Store>,
841 node: <Pst as PstFile>::NodeBTreeEntry,
842 context: TableContextInfo,
843 heap: <Pst as PstFile>::HeapNode,
844 row_index: BTreeMap<TableRowId, RowIndex>,
845 rows: Vec<TableRowData>,
846 block_cache: RefCell<DataBlockCache<Pst>>,
847 _phantom: PhantomData<RowIndexTree>,
848}
849
850impl<Pst, RowIndex, RowIndexTree> TableContextInner<Pst, RowIndex, RowIndexTree>
851where
852 Pst: PstFile + PstFileLock<Pst>,
853 <Pst as PstFile>::BlockId: BlockId<Index = <Pst as PstFile>::BTreeKey> + BlockIdReadWrite,
854 <Pst as PstFile>::ByteIndex: ByteIndexReadWrite,
855 <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
856 <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
857 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
858 <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
859 RootBTreeIntermediatePageReadWrite<
860 Pst,
861 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
862 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
863 >,
864 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
865 RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
866 <Pst as PstFile>::BlockTrailer: BlockTrailerReadWrite,
867 <Pst as PstFile>::DataTreeBlock: IntermediateTreeBlockReadWrite,
868 <<Pst as PstFile>::DataTreeBlock as IntermediateTreeBlock>::Entry:
869 IntermediateTreeEntryReadWrite,
870 <Pst as PstFile>::DataBlock: BlockReadWrite + Clone,
871 <Pst as PstFile>::SubNodeTreeBlockHeader: IntermediateTreeHeaderReadWrite,
872 <Pst as PstFile>::SubNodeTreeBlock: IntermediateTreeBlockReadWrite,
873 <<Pst as PstFile>::SubNodeTreeBlock as IntermediateTreeBlock>::Entry:
874 IntermediateTreeEntryReadWrite,
875 <Pst as PstFile>::SubNodeBlock: IntermediateTreeBlockReadWrite,
876 <<Pst as PstFile>::SubNodeBlock as IntermediateTreeBlock>::Entry:
877 IntermediateTreeEntryReadWrite,
878 <Pst as PstFile>::HeapNode: HeapNodeReadWrite<Pst> + From<RowIndexTree>,
879 <Pst as PstFile>::Store: StoreReadWrite<Pst>,
880 RowIndex: TableRowIndex<Pst>,
881 RowIndexTree: TableRowIndexTree<Pst, RowIndex = RowIndex>,
882 u32: From<RowIndex>,
883{
884 fn read(
885 store: Rc<<Pst as PstFile>::Store>,
886 node: <Pst as PstFile>::NodeBTreeEntry,
887 ) -> io::Result<Self> {
888 let mut file = store
889 .pst()
890 .reader()
891 .lock()
892 .map_err(|_| LtpError::FailedToLockFile)?;
893 let file = &mut *file;
894
895 let header = store.pst().header();
896 let encoding = header.crypt_method();
897 let mut page_cache = store.pst().block_cache();
898 let block_btree = <<Pst as PstFile>::BlockBTree as RootBTreeReadWrite>::read(
899 file,
900 *header.root().block_btree(),
901 )?;
902
903 let data = node.data();
904 let heap = <<Pst as PstFile>::HeapNode as HeapNodeReadWrite<Pst>>::read(
905 file,
906 &block_btree,
907 &mut page_cache,
908 encoding,
909 data.search_key(),
910 )?;
911 let header = HeapNode::header(&heap)?;
912 let mut block_cache: DataBlockCache<Pst> = Default::default();
913
914 let mut cursor = Cursor::new(heap.find_entry(header.user_root())?);
915 let context = TableContextInfo::read(&mut cursor)?;
916
917 let rows = if let Some(rows) = context.rows {
918 match rows.id_type() {
919 Ok(NodeIdType::HeapNode) => {
920 let rows: u32 = rows.into();
921 vec![heap.find_entry(HeapId::from(rows))?.to_vec()]
922 }
923 _ => {
924 let sub_node = node
925 .sub_node()
926 .ok_or(LtpError::PropertySubNodeValueNotFound(rows.into()))?;
927 let block =
928 block_btree.find_entry(file, sub_node.search_key(), &mut page_cache)?;
929 let sub_node_tree = SubNodeTree::<Pst>::read(file, &block)?;
930 let block =
931 sub_node_tree.find_entry(file, &block_btree, rows, &mut page_cache)?;
932 let block =
933 block_btree.find_entry(file, block.search_key(), &mut page_cache)?;
934 let data_tree = match block_cache.remove(&block.block().block()) {
935 Some(data_tree) => data_tree,
936 None => DataTree::read(file, encoding, &block)?,
937 };
938 let result = data_tree
939 .blocks(
940 file,
941 encoding,
942 &block_btree,
943 &mut page_cache,
944 &mut block_cache,
945 )
946 .map(|blocks| {
947 blocks
948 .map(|block| block.data().to_vec())
949 .collect::<Vec<_>>()
950 });
951 block_cache.insert(block.block().block(), data_tree);
952 result?
953 }
954 }
955 .into_iter()
956 .map(|data| {
957 let row_count = data.len() / context.end_existence_bitmap() as usize;
958 let mut cursor = Cursor::new(data);
959 let mut rows = Vec::with_capacity(row_count);
960 for _ in 0..row_count {
961 let row = TableRowData::read(&mut cursor, &context)?;
962 rows.push(row);
963 }
964 Ok(rows)
965 })
966 .collect::<io::Result<Vec<_>>>()?
967 .into_iter()
968 .flatten()
969 .collect()
970 } else {
971 Default::default()
972 };
973
974 let row_index_tree = RowIndexTree::new(heap, context.row_index);
975 let row_index = row_index_tree
976 .entries()?
977 .into_iter()
978 .map(|entry| (entry.key(), entry.data()))
979 .collect();
980 let heap = row_index_tree.into();
981
982 Ok(Self {
983 store: store.clone(),
984 node,
985 context,
986 heap,
987 row_index,
988 rows,
989 block_cache: RefCell::new(block_cache),
990 _phantom: PhantomData,
991 })
992 }
993
994 fn read_column(
995 &self,
996 value: &TableRowColumnValue,
997 prop_type: PropertyType,
998 ) -> io::Result<PropertyValue> {
999 match value {
1000 TableRowColumnValue::Small(small) => Ok(small.clone()),
1001 TableRowColumnValue::Heap(heap_id) => {
1002 let data = self.heap.find_entry(*heap_id)?;
1003 let mut cursor = Cursor::new(data);
1004 PropertyValueReadWrite::read(&mut cursor, prop_type)
1005 }
1006 TableRowColumnValue::Node(sub_node_id) => {
1007 let mut file = self
1008 .store
1009 .pst()
1010 .reader()
1011 .lock()
1012 .map_err(|_| LtpError::FailedToLockFile)?;
1013 let file = &mut *file;
1014
1015 let encoding = self.store.pst().header().crypt_method();
1016 let block_btree = self.store.block_btree();
1017 let mut page_cache = self.store.pst().block_cache();
1018
1019 let sub_node =
1020 self.node
1021 .sub_node()
1022 .ok_or(LtpError::PropertySubNodeValueNotFound(
1023 (*sub_node_id).into(),
1024 ))?;
1025 let block = block_btree.find_entry(file, sub_node.search_key(), &mut page_cache)?;
1026 let sub_node_tree = SubNodeTree::<Pst>::read(file, &block)?;
1027 let block =
1028 sub_node_tree.find_entry(file, block_btree, *sub_node_id, &mut page_cache)?;
1029 let block = block_btree.find_entry(file, block.search_key(), &mut page_cache)?;
1030 let mut block_cache = self.block_cache.borrow_mut();
1031 let data_tree = match block_cache.remove(&block.block().block()) {
1032 Some(data_tree) => data_tree,
1033 None => DataTree::read(file, encoding, &block)?,
1034 };
1035 let result = data_tree
1036 .reader(
1037 file,
1038 encoding,
1039 block_btree,
1040 &mut page_cache,
1041 &mut block_cache,
1042 )
1043 .and_then(|mut r| PropertyValueReadWrite::read(&mut r, prop_type));
1044 block_cache.insert(block.block().block(), data_tree);
1045 result
1046 }
1047 }
1048 }
1049}
1050
1051type UnicodeRowIndexTree = UnicodeHeapTree<TableRowId, UnicodeTableRowIndex>;
1052
1053impl TableRowIndexTree<UnicodePstFile> for UnicodeRowIndexTree {
1054 type RowIndex = UnicodeTableRowIndex;
1055}
1056
1057pub struct UnicodeTableContext {
1058 inner: TableContextInner<UnicodePstFile, UnicodeTableRowIndex, UnicodeRowIndexTree>,
1059}
1060
1061impl UnicodeTableContext {
1062 pub fn read(
1063 store: Rc<UnicodeStore>,
1064 node: UnicodeNodeBTreeEntry,
1065 ) -> io::Result<Rc<dyn TableContext>> {
1066 <Self as TableContextReadWrite<UnicodePstFile>>::read(store, node)
1067 }
1068}
1069
1070impl TableContext for UnicodeTableContext {
1071 fn context(&self) -> &TableContextInfo {
1072 &self.inner.context
1073 }
1074
1075 fn rows_matrix<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = &'a TableRowData>> {
1076 Box::new(self.inner.rows.iter())
1077 }
1078
1079 fn find_row(&self, id: TableRowId) -> LtpResult<&TableRowData> {
1080 let index = self
1081 .inner
1082 .row_index
1083 .get(&id)
1084 .ok_or(LtpError::TableRowIdNotFound(u32::from(id)))?;
1085 Ok(&self.inner.rows[u32::from(*index) as usize])
1086 }
1087
1088 fn read_column(
1089 &self,
1090 value: &TableRowColumnValue,
1091 prop_type: PropertyType,
1092 ) -> io::Result<PropertyValue> {
1093 self.inner.read_column(value, prop_type)
1094 }
1095}
1096
1097impl TableContextReadWrite<UnicodePstFile> for UnicodeTableContext {
1098 fn read(
1099 store: Rc<UnicodeStore>,
1100 node: UnicodeNodeBTreeEntry,
1101 ) -> io::Result<Rc<dyn TableContext>> {
1102 let inner = TableContextInner::read(store, node)?;
1103 Ok(Rc::new(Self { inner }))
1104 }
1105}
1106
1107type AnsiRowIndexTree = AnsiHeapTree<TableRowId, AnsiTableRowIndex>;
1108
1109impl TableRowIndexTree<AnsiPstFile> for AnsiRowIndexTree {
1110 type RowIndex = AnsiTableRowIndex;
1111}
1112
1113pub struct AnsiTableContext {
1114 inner: TableContextInner<AnsiPstFile, AnsiTableRowIndex, AnsiRowIndexTree>,
1115}
1116
1117impl AnsiTableContext {
1118 pub fn read(
1119 store: Rc<AnsiStore>,
1120 node: AnsiNodeBTreeEntry,
1121 ) -> io::Result<Rc<dyn TableContext>> {
1122 <Self as TableContextReadWrite<AnsiPstFile>>::read(store, node)
1123 }
1124}
1125
1126impl TableContext for AnsiTableContext {
1127 fn context(&self) -> &TableContextInfo {
1128 &self.inner.context
1129 }
1130
1131 fn rows_matrix<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = &'a TableRowData>> {
1132 Box::new(self.inner.rows.iter())
1133 }
1134
1135 fn find_row(&self, id: TableRowId) -> LtpResult<&TableRowData> {
1136 let index = self
1137 .inner
1138 .row_index
1139 .get(&id)
1140 .ok_or(LtpError::TableRowIdNotFound(u32::from(id)))?;
1141 Ok(&self.inner.rows[u32::from(*index) as usize])
1142 }
1143
1144 fn read_column(
1145 &self,
1146 value: &TableRowColumnValue,
1147 prop_type: PropertyType,
1148 ) -> io::Result<PropertyValue> {
1149 self.inner.read_column(value, prop_type)
1150 }
1151}
1152
1153impl TableContextReadWrite<AnsiPstFile> for AnsiTableContext {
1154 fn read(store: Rc<AnsiStore>, node: AnsiNodeBTreeEntry) -> io::Result<Rc<dyn TableContext>> {
1155 let inner = TableContextInner::read(store, node)?;
1156 Ok(Rc::new(Self { inner }))
1157 }
1158}