1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4use std::{
5 collections::{btree_map, BTreeMap, VecDeque},
6 io::{self, Cursor, Read, Seek, SeekFrom, Write},
7 iter,
8};
9use tracing::error;
10
11use super::{block_id::*, block_ref::*, byte_index::*, node_id::*, page::*, read_write::*, *};
12use crate::{AnsiPstFile, PstFile, PstFileReadWriteBlockBTree, PstReader, UnicodePstFile};
13
14pub const MAX_BLOCK_SIZE: u16 = 8192;
15
16pub const fn block_size(size: u16) -> u16 {
17 assert!(size > 0);
18 assert!(size <= MAX_BLOCK_SIZE);
19 size.div_ceil(64) * 64
20}
21
22pub trait BlockTrailer {
24 type BlockId: BlockId;
25
26 fn size(&self) -> u16;
27 fn signature(&self) -> u16;
28 fn crc(&self) -> u32;
29 fn block_id(&self) -> Self::BlockId;
30 fn cyclic_key(&self) -> u32;
31 fn verify_block_id(&self, is_internal: bool) -> NdbResult<()>;
32}
33
34#[derive(Clone, Copy, Default)]
35pub struct UnicodeBlockTrailer {
36 size: u16,
37 signature: u16,
38 crc: u32,
39 block_id: UnicodeBlockId,
40}
41
42impl UnicodeBlockTrailer {
43 pub fn new(size: u16, signature: u16, crc: u32, block_id: UnicodeBlockId) -> NdbResult<Self> {
44 if !(1..=(MAX_BLOCK_SIZE - Self::SIZE)).contains(&size) {
45 return Err(NdbError::InvalidBlockSize(size));
46 }
47
48 Ok(Self {
49 size,
50 block_id,
51 signature,
52 crc,
53 })
54 }
55}
56
57impl BlockTrailer for UnicodeBlockTrailer {
58 type BlockId = UnicodeBlockId;
59
60 fn size(&self) -> u16 {
61 self.size
62 }
63
64 fn signature(&self) -> u16 {
65 self.signature
66 }
67
68 fn crc(&self) -> u32 {
69 self.crc
70 }
71
72 fn block_id(&self) -> UnicodeBlockId {
73 self.block_id
74 }
75
76 fn cyclic_key(&self) -> u32 {
77 self.block_id.search_key() as u32
78 }
79
80 fn verify_block_id(&self, is_internal: bool) -> NdbResult<()> {
81 if self.block_id.is_internal() != is_internal {
82 return Err(NdbError::InvalidUnicodeBlockTrailerId(u64::from(
83 self.block_id,
84 )));
85 }
86 Ok(())
87 }
88}
89
90impl BlockTrailerReadWrite for UnicodeBlockTrailer {
91 const SIZE: u16 = 16;
92
93 fn new(size: u16, signature: u16, crc: u32, block_id: UnicodeBlockId) -> NdbResult<Self> {
94 Self::new(size, signature, crc, block_id)
95 }
96
97 fn read(f: &mut dyn Read) -> io::Result<Self> {
98 let size = f.read_u16::<LittleEndian>()?;
99 if !(1..=(MAX_BLOCK_SIZE - Self::SIZE)).contains(&size) {
100 return Err(NdbError::InvalidBlockSize(size).into());
101 }
102
103 let signature = f.read_u16::<LittleEndian>()?;
104 let crc = f.read_u32::<LittleEndian>()?;
105 let block_id = UnicodeBlockId::read(f)?;
106
107 Ok(Self {
108 size,
109 signature,
110 crc,
111 block_id,
112 })
113 }
114
115 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
116 f.write_u16::<LittleEndian>(self.size)?;
117 f.write_u16::<LittleEndian>(self.signature)?;
118 f.write_u32::<LittleEndian>(self.crc)?;
119 self.block_id.write(f)
120 }
121}
122
123#[derive(Clone, Copy, Default)]
124pub struct AnsiBlockTrailer {
125 size: u16,
126 signature: u16,
127 block_id: AnsiBlockId,
128 crc: u32,
129}
130
131impl AnsiBlockTrailer {
132 pub fn new(size: u16, signature: u16, crc: u32, block_id: AnsiBlockId) -> NdbResult<Self> {
133 if !(1..=(MAX_BLOCK_SIZE - Self::SIZE)).contains(&size) {
134 return Err(NdbError::InvalidBlockSize(size));
135 }
136
137 Ok(Self {
138 size,
139 signature,
140 block_id,
141 crc,
142 })
143 }
144}
145
146impl BlockTrailer for AnsiBlockTrailer {
147 type BlockId = AnsiBlockId;
148
149 fn size(&self) -> u16 {
150 self.size
151 }
152
153 fn signature(&self) -> u16 {
154 self.signature
155 }
156
157 fn crc(&self) -> u32 {
158 self.crc
159 }
160
161 fn block_id(&self) -> AnsiBlockId {
162 self.block_id
163 }
164
165 fn cyclic_key(&self) -> u32 {
166 self.block_id.search_key()
167 }
168
169 fn verify_block_id(&self, is_internal: bool) -> NdbResult<()> {
170 if self.block_id.is_internal() != is_internal {
171 return Err(NdbError::InvalidAnsiBlockTrailerId(u32::from(
172 self.block_id,
173 )));
174 }
175 Ok(())
176 }
177}
178
179impl BlockTrailerReadWrite for AnsiBlockTrailer {
180 const SIZE: u16 = 12;
181
182 fn new(size: u16, signature: u16, crc: u32, block_id: AnsiBlockId) -> NdbResult<Self> {
183 Self::new(size, signature, crc, block_id)
184 }
185
186 fn read(f: &mut dyn Read) -> io::Result<Self> {
187 let size = f.read_u16::<LittleEndian>()?;
188 if !(1..=(MAX_BLOCK_SIZE - Self::SIZE)).contains(&size) {
189 return Err(NdbError::InvalidBlockSize(size).into());
190 }
191
192 let signature = f.read_u16::<LittleEndian>()?;
193 let block_id = AnsiBlockId::read(f)?;
194 let crc = f.read_u32::<LittleEndian>()?;
195
196 Ok(Self {
197 size,
198 signature,
199 block_id,
200 crc,
201 })
202 }
203
204 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
205 f.write_u16::<LittleEndian>(self.size)?;
206 f.write_u16::<LittleEndian>(self.signature)?;
207 self.block_id.write(f)?;
208 f.write_u32::<LittleEndian>(self.crc)
209 }
210}
211
212pub trait Block {
214 type Trailer: BlockTrailer;
215
216 fn encoding(&self) -> NdbCryptMethod;
217 fn data(&self) -> &[u8];
218 fn trailer(&self) -> &Self::Trailer;
219}
220
221#[derive(Clone, Default)]
222pub struct UnicodeDataBlock {
223 encoding: NdbCryptMethod,
224 data: Vec<u8>,
225 trailer: UnicodeBlockTrailer,
226}
227
228impl UnicodeDataBlock {
229 pub fn new(
230 encoding: NdbCryptMethod,
231 data: Vec<u8>,
232 trailer: UnicodeBlockTrailer,
233 ) -> NdbResult<Self> {
234 Ok(Self {
235 data,
236 encoding,
237 trailer,
238 })
239 }
240}
241
242impl Block for UnicodeDataBlock {
243 type Trailer = UnicodeBlockTrailer;
244
245 fn encoding(&self) -> NdbCryptMethod {
246 self.encoding
247 }
248
249 fn data(&self) -> &[u8] {
250 &self.data
251 }
252
253 fn trailer(&self) -> &UnicodeBlockTrailer {
254 &self.trailer
255 }
256}
257
258impl BlockReadWrite for UnicodeDataBlock {
259 fn new(
260 encoding: NdbCryptMethod,
261 data: Vec<u8>,
262 trailer: UnicodeBlockTrailer,
263 ) -> NdbResult<Self> {
264 Self::new(encoding, data, trailer)
265 }
266}
267
268impl From<UnicodeDataBlock> for Vec<u8> {
269 fn from(value: UnicodeDataBlock) -> Self {
270 value.data
271 }
272}
273
274#[derive(Clone, Default)]
275pub struct AnsiDataBlock {
276 encoding: NdbCryptMethod,
277 data: Vec<u8>,
278 trailer: AnsiBlockTrailer,
279}
280
281impl AnsiDataBlock {
282 pub fn new(
283 encoding: NdbCryptMethod,
284 data: Vec<u8>,
285 trailer: AnsiBlockTrailer,
286 ) -> NdbResult<Self> {
287 Ok(Self {
288 data,
289 encoding,
290 trailer,
291 })
292 }
293}
294
295impl Block for AnsiDataBlock {
296 type Trailer = AnsiBlockTrailer;
297
298 fn encoding(&self) -> NdbCryptMethod {
299 self.encoding
300 }
301
302 fn data(&self) -> &[u8] {
303 &self.data
304 }
305
306 fn trailer(&self) -> &AnsiBlockTrailer {
307 &self.trailer
308 }
309}
310
311impl BlockReadWrite for AnsiDataBlock {
312 fn new(encoding: NdbCryptMethod, data: Vec<u8>, trailer: AnsiBlockTrailer) -> NdbResult<Self> {
313 Self::new(encoding, data, trailer)
314 }
315}
316
317impl From<AnsiDataBlock> for Vec<u8> {
318 fn from(value: AnsiDataBlock) -> Self {
319 value.data
320 }
321}
322
323pub trait IntermediateTreeHeader {
324 fn level(&self) -> u8;
325 fn entry_count(&self) -> u16;
326}
327
328pub trait IntermediateTreeEntry {}
329
330pub trait IntermediateTreeBlock {
331 type Header: IntermediateTreeHeader;
332 type Entry: IntermediateTreeEntry;
333 type Trailer: BlockTrailer;
334
335 fn header(&self) -> &Self::Header;
336 fn entries(&self) -> &[Self::Entry];
337 fn trailer(&self) -> &Self::Trailer;
338}
339
340#[derive(Clone, Copy, Default)]
341pub struct DataTreeBlockHeader {
342 level: u8,
343 entry_count: u16,
344 total_size: u32,
345}
346
347impl DataTreeBlockHeader {
348 pub fn new(level: u8, entry_count: u16, total_size: u32) -> Self {
349 Self {
350 level,
351 entry_count,
352 total_size,
353 }
354 }
355
356 pub fn total_size(&self) -> u32 {
357 self.total_size
358 }
359}
360
361impl IntermediateTreeHeader for DataTreeBlockHeader {
362 fn level(&self) -> u8 {
363 self.level
364 }
365
366 fn entry_count(&self) -> u16 {
367 self.entry_count
368 }
369}
370
371impl IntermediateTreeHeaderReadWrite for DataTreeBlockHeader {
372 const HEADER_SIZE: u16 = 8;
373
374 fn read(f: &mut dyn Read) -> io::Result<Self> {
375 let block_type = f.read_u8()?;
376 if block_type != 0x01 {
377 return Err(NdbError::InvalidInternalBlockType(block_type).into());
378 }
379
380 let level = f.read_u8()?;
381 let entry_count = f.read_u16::<LittleEndian>()?;
382 let total_size = f.read_u32::<LittleEndian>()?;
383
384 Ok(Self {
385 level,
386 entry_count,
387 total_size,
388 })
389 }
390
391 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
392 f.write_u8(0x01)?;
393 f.write_u8(self.level)?;
394 f.write_u16::<LittleEndian>(self.entry_count)?;
395 f.write_u32::<LittleEndian>(self.total_size)
396 }
397}
398
399pub trait IntermediateDataTreeEntry<Pst>: IntermediateTreeEntry
400where
401 Pst: PstFile,
402{
403 fn new(block: <Pst as PstFile>::BlockId) -> Self;
404 fn block(&self) -> <Pst as PstFile>::BlockId;
405}
406
407#[derive(Clone, Copy, Default)]
408pub struct UnicodeDataTreeEntry(UnicodeBlockId);
409
410impl IntermediateTreeEntry for UnicodeDataTreeEntry {}
411
412impl IntermediateDataTreeEntry<UnicodePstFile> for UnicodeDataTreeEntry {
413 fn new(block: UnicodeBlockId) -> Self {
414 Self(block)
415 }
416
417 fn block(&self) -> UnicodeBlockId {
418 self.0
419 }
420}
421
422impl IntermediateTreeEntryReadWrite for UnicodeDataTreeEntry {
423 const ENTRY_SIZE: u16 = 8;
424
425 fn read(f: &mut dyn Read) -> io::Result<Self> {
426 Ok(Self(UnicodeBlockId::read(f)?))
427 }
428
429 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
430 self.0.write(f)
431 }
432}
433
434impl From<UnicodeBlockId> for UnicodeDataTreeEntry {
435 fn from(value: UnicodeBlockId) -> Self {
436 Self::new(value)
437 }
438}
439
440impl From<UnicodeDataTreeEntry> for UnicodeBlockId {
441 fn from(value: UnicodeDataTreeEntry) -> Self {
442 value.block()
443 }
444}
445
446#[derive(Clone, Copy, Default)]
447pub struct AnsiDataTreeEntry(AnsiBlockId);
448
449impl IntermediateTreeEntry for AnsiDataTreeEntry {}
450
451impl IntermediateDataTreeEntry<AnsiPstFile> for AnsiDataTreeEntry {
452 fn new(block: AnsiBlockId) -> Self {
453 Self(block)
454 }
455
456 fn block(&self) -> AnsiBlockId {
457 self.0
458 }
459}
460
461impl IntermediateTreeEntryReadWrite for AnsiDataTreeEntry {
462 const ENTRY_SIZE: u16 = 4;
463
464 fn read(f: &mut dyn Read) -> io::Result<Self> {
465 Ok(Self(AnsiBlockId::read(f)?))
466 }
467
468 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
469 self.0.write(f)
470 }
471}
472
473impl From<AnsiBlockId> for AnsiDataTreeEntry {
474 fn from(value: AnsiBlockId) -> Self {
475 Self::new(value)
476 }
477}
478
479impl From<AnsiDataTreeEntry> for AnsiBlockId {
480 fn from(value: AnsiDataTreeEntry) -> Self {
481 value.block()
482 }
483}
484
485struct DataTreeBlockInner<Entry, Trailer>
488where
489 Entry: IntermediateTreeEntry,
490 Trailer: BlockTrailer,
491{
492 header: DataTreeBlockHeader,
493 entries: Vec<Entry>,
494 trailer: Trailer,
495}
496
497impl<Entry, Trailer> DataTreeBlockInner<Entry, Trailer>
498where
499 Entry: IntermediateTreeEntry,
500 Trailer: BlockTrailer,
501{
502 pub fn new(
503 header: DataTreeBlockHeader,
504 entries: Vec<Entry>,
505 trailer: Trailer,
506 ) -> NdbResult<Self> {
507 trailer.verify_block_id(true)?;
508
509 Ok(Self {
510 header,
511 entries,
512 trailer,
513 })
514 }
515}
516
517pub struct UnicodeDataTreeBlock {
518 inner: DataTreeBlockInner<UnicodeDataTreeEntry, UnicodeBlockTrailer>,
519}
520
521impl IntermediateTreeBlock for UnicodeDataTreeBlock {
522 type Header = DataTreeBlockHeader;
523 type Entry = UnicodeDataTreeEntry;
524 type Trailer = UnicodeBlockTrailer;
525
526 fn header(&self) -> &Self::Header {
527 &self.inner.header
528 }
529
530 fn entries(&self) -> &[Self::Entry] {
531 &self.inner.entries
532 }
533
534 fn trailer(&self) -> &Self::Trailer {
535 &self.inner.trailer
536 }
537}
538
539impl IntermediateTreeBlockReadWrite for UnicodeDataTreeBlock {
540 fn new(
541 header: DataTreeBlockHeader,
542 entries: Vec<UnicodeDataTreeEntry>,
543 trailer: UnicodeBlockTrailer,
544 ) -> NdbResult<Self> {
545 Ok(Self {
546 inner: DataTreeBlockInner::new(header, entries, trailer)?,
547 })
548 }
549}
550
551pub struct AnsiDataTreeBlock {
552 inner: DataTreeBlockInner<AnsiDataTreeEntry, AnsiBlockTrailer>,
553}
554
555impl IntermediateTreeBlock for AnsiDataTreeBlock {
556 type Header = DataTreeBlockHeader;
557 type Entry = AnsiDataTreeEntry;
558 type Trailer = AnsiBlockTrailer;
559
560 fn header(&self) -> &Self::Header {
561 &self.inner.header
562 }
563
564 fn entries(&self) -> &[Self::Entry] {
565 &self.inner.entries
566 }
567
568 fn trailer(&self) -> &Self::Trailer {
569 &self.inner.trailer
570 }
571}
572
573impl IntermediateTreeBlockReadWrite for AnsiDataTreeBlock {
574 fn new(
575 header: DataTreeBlockHeader,
576 entries: Vec<AnsiDataTreeEntry>,
577 trailer: AnsiBlockTrailer,
578 ) -> NdbResult<Self> {
579 Ok(Self {
580 inner: DataTreeBlockInner::new(header, entries, trailer)?,
581 })
582 }
583}
584
585pub type DataBlockCache<Pst> = BTreeMap<<Pst as PstFile>::BlockId, DataTree<Pst>>;
586
587pub enum DataTree<Pst>
588where
589 Pst: PstFile,
590{
591 Intermediate(Box<<Pst as PstFile>::DataTreeBlock>),
592 Leaf(Box<<Pst as PstFile>::DataBlock>),
593}
594
595impl<Pst> DataTree<Pst>
596where
597 Pst: PstFile,
598 <Pst as PstFile>::BlockTrailer: BlockTrailerReadWrite,
599 <Pst as PstFile>::DataTreeBlock: IntermediateTreeBlockReadWrite,
600 <<Pst as PstFile>::DataTreeBlock as IntermediateTreeBlock>::Entry:
601 IntermediateTreeEntryReadWrite,
602 <Pst as PstFile>::DataBlock: BlockReadWrite,
603{
604 pub fn read<R>(
605 f: &mut R,
606 encoding: NdbCryptMethod,
607 block: &<Pst as PstFile>::BlockBTreeEntry,
608 ) -> io::Result<Self>
609 where
610 R: PstReader,
611 {
612 f.seek(SeekFrom::Start(block.block().index().index().into()))?;
613
614 let block_size = block_size(
615 block.size() + <<Pst as PstFile>::BlockTrailer as BlockTrailerReadWrite>::SIZE,
616 );
617 let mut data = vec![0; block_size as usize];
618 f.read_exact(&mut data)?;
619 let mut cursor = Cursor::new(data);
620
621 let block = if block.block().block().is_internal() {
622 let header = DataTreeBlockHeader::read(&mut cursor)?;
623 cursor.seek(SeekFrom::Start(0))?;
624 let block = <<Pst as PstFile>::DataTreeBlock as IntermediateTreeBlockReadWrite>::read(
625 &mut cursor,
626 header,
627 block.size(),
628 )?;
629 Self::Intermediate(Box::new(block))
630 } else {
631 let block = <<Pst as PstFile>::DataBlock as BlockReadWrite>::read(
632 &mut cursor,
633 block.size(),
634 encoding,
635 )?;
636 Self::Leaf(Box::new(block))
637 };
638
639 Ok(block)
640 }
641
642 pub fn write<W: Write + Seek>(
643 &self,
644 f: &mut W,
645 block: &<Pst as PstFile>::BlockBTreeEntry,
646 ) -> io::Result<()> {
647 f.seek(SeekFrom::Start(block.block().index().index().into()))?;
648
649 match self {
650 Self::Intermediate(block, ..) => block.write(f),
651 Self::Leaf(block) => block.write(f),
652 }
653 }
654
655 pub fn blocks<'a, R>(
656 &'a self,
657 f: &mut R,
658 encoding: NdbCryptMethod,
659 block_btree: &PstFileReadWriteBlockBTree<Pst>,
660 page_cache: &mut RootBTreePageCache<<Pst as PstFile>::BlockBTree>,
661 block_cache: &'a mut DataBlockCache<Pst>,
662 ) -> io::Result<Box<dyn 'a + Iterator<Item = <Pst as PstFile>::DataBlock>>>
663 where
664 R: PstReader,
665 <Pst as PstFile>::DataBlock: 'a + Clone,
666 <Pst as PstFile>::BlockId: BlockId<Index = <Pst as PstFile>::BTreeKey> + BlockIdReadWrite,
667 <Pst as PstFile>::ByteIndex: ByteIndexReadWrite,
668 <Pst as PstFile>::BlockRef: BlockRefReadWrite,
669 <Pst as PstFile>::PageTrailer: PageTrailerReadWrite,
670 <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
671 <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
672 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
673 <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
674 RootBTreeIntermediatePageReadWrite<
675 Pst,
676 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
677 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
678 >,
679 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
680 RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
681 {
682 match self {
683 Self::Intermediate(block, ..) => {
684 let mut blocks = Vec::with_capacity(block.entries().len());
685 for entry in block.entries() {
686 let data_tree = match block_cache.remove(&entry.block()) {
687 Some(entry) => entry,
688 None => {
689 let data_block = block_btree.find_entry(
690 f,
691 entry.block().search_key(),
692 page_cache,
693 )?;
694 Self::read(&mut *f, encoding, &data_block)?
695 }
696 };
697 let entries = data_tree
698 .blocks(f, encoding, block_btree, page_cache, block_cache)
699 .map(|blocks| blocks.collect::<Vec<_>>());
700 block_cache.insert(entry.block(), data_tree);
701 blocks.push(entries?);
702 }
703 Ok(Box::new(blocks.into_iter().flatten()))
704 }
705 Self::Leaf(block) => Ok(Box::new(Some(block.as_ref()).cloned().into_iter())),
706 }
707 }
708
709 pub fn nth<R>(
710 &self,
711 n: usize,
712 f: &mut R,
713 encoding: NdbCryptMethod,
714 block_btree: &PstFileReadWriteBlockBTree<Pst>,
715 page_cache: &mut RootBTreePageCache<<Pst as PstFile>::BlockBTree>,
716 block_cache: &mut DataBlockCache<Pst>,
717 ) -> io::Result<Option<Vec<u8>>>
718 where
719 R: PstReader,
720 <Pst as PstFile>::BlockId: BlockId<Index = <Pst as PstFile>::BTreeKey> + BlockIdReadWrite,
721 <Pst as PstFile>::ByteIndex: ByteIndexReadWrite,
722 <Pst as PstFile>::BlockRef: BlockRefReadWrite,
723 <Pst as PstFile>::PageTrailer: PageTrailerReadWrite,
724 <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
725 <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
726 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
727 <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
728 RootBTreeIntermediatePageReadWrite<
729 Pst,
730 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
731 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
732 >,
733 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
734 RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
735 {
736 Ok(Some(match self {
737 Self::Intermediate(_) => {
738 let Some(data_block) = self
739 .sub_entries(f, encoding, block_btree, page_cache, block_cache)?
740 .nth(n)
741 else {
742 return Ok(None);
743 };
744
745 let data_tree = match block_cache.entry(data_block.block().block()) {
746 btree_map::Entry::Vacant(entry) => {
747 entry.insert(Self::read(&mut *f, encoding, &data_block)?)
748 }
749 btree_map::Entry::Occupied(entry) => entry.into_mut(),
750 };
751
752 let Self::Leaf(block) = data_tree else {
753 error!(
754 name: "PstInvalidDataTreeIntermediateBlock",
755 "Data tree intermediate block has non-leaf sub-entry"
756 );
757
758 return Err(NdbError::InvalidInternalBlockLevel(0).into());
759 };
760
761 block.data().to_vec()
762 }
763 Self::Leaf(block) => {
764 if n != 0 {
765 return Ok(None);
766 }
767
768 block.data().to_vec()
769 }
770 }))
771 }
772
773 pub fn reader<'a, R>(
774 &self,
775 f: &'a mut R,
776 encoding: NdbCryptMethod,
777 block_btree: &'a PstFileReadWriteBlockBTree<Pst>,
778 page_cache: &mut RootBTreePageCache<<Pst as PstFile>::BlockBTree>,
779 block_cache: &'a mut DataBlockCache<Pst>,
780 ) -> io::Result<Box<dyn 'a + Read>>
781 where
782 Pst: 'a,
783 R: PstReader,
784 <Pst as PstFile>::DataBlock: 'a + Clone,
785 <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
786 <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
787 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
788 <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
789 RootBTreeIntermediatePageReadWrite<
790 Pst,
791 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
792 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
793 >,
794 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
795 RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
796 {
797 let reader: DataTreeReader<'a, Pst, R> =
798 DataTreeReader::new(self, f, encoding, block_btree, page_cache, block_cache)?;
799 let reader: Box<dyn 'a + Read> = Box::new(reader);
800 Ok(reader)
801 }
802
803 fn sub_entries<'a, R>(
804 &self,
805 f: &mut R,
806 encoding: NdbCryptMethod,
807 block_btree: &PstFileReadWriteBlockBTree<Pst>,
808 page_cache: &mut RootBTreePageCache<<Pst as PstFile>::BlockBTree>,
809 block_cache: &'a mut DataBlockCache<Pst>,
810 ) -> io::Result<Box<dyn 'a + Iterator<Item = <Pst as PstFile>::BlockBTreeEntry>>>
811 where
812 R: PstReader,
813 <Pst as PstFile>::BlockBTreeEntry: 'a,
814 <Pst as PstFile>::BlockId: BlockId<Index = <Pst as PstFile>::BTreeKey> + BlockIdReadWrite,
815 <Pst as PstFile>::ByteIndex: ByteIndexReadWrite,
816 <Pst as PstFile>::BlockRef: BlockRefReadWrite,
817 <Pst as PstFile>::PageTrailer: PageTrailerReadWrite,
818 <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
819 <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
820 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
821 <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
822 RootBTreeIntermediatePageReadWrite<
823 Pst,
824 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
825 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
826 >,
827 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
828 RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
829 {
830 match self {
831 Self::Intermediate(block, ..) => {
832 let mut blocks = Vec::with_capacity(block.entries().len());
833 for entry in block.entries() {
834 if entry.block().is_internal() {
835 let data_tree = match block_cache.remove(&entry.block()) {
836 Some(entry) => entry,
837 None => {
838 let data_block = block_btree.find_entry(
839 f,
840 entry.block().search_key(),
841 page_cache,
842 )?;
843 Self::read(&mut *f, encoding, &data_block)?
844 }
845 };
846 let entries = data_tree
847 .sub_entries(f, encoding, block_btree, page_cache, block_cache)
848 .map(|entries| entries.collect::<Vec<_>>());
849 block_cache.insert(entry.block(), data_tree);
850 blocks.push(entries?);
851 } else {
852 let data_block =
853 block_btree.find_entry(f, entry.block().search_key(), page_cache)?;
854 blocks.push(vec![data_block]);
855 }
856 }
857 Ok(Box::new(blocks.into_iter().flatten()))
858 }
859 Self::Leaf(_) => Ok(Box::new(iter::empty())),
860 }
861 }
862}
863
864struct DataTreeCursor<Pst>
865where
866 Pst: PstFile,
867{
868 current: Cursor<Vec<u8>>,
869 next: VecDeque<<Pst as PstFile>::BlockBTreeEntry>,
870}
871
872struct DataTreeReader<'a, Pst, R>
873where
874 Pst: PstFile,
875 R: PstReader,
876{
877 file: &'a mut R,
878 encoding: NdbCryptMethod,
879 cursor: DataTreeCursor<Pst>,
880}
881
882impl<'a, Pst, R> DataTreeReader<'a, Pst, R>
883where
884 Pst: PstFile,
885 R: PstReader,
886{
887 fn new(
888 data_tree: &DataTree<Pst>,
889 file: &'a mut R,
890 encoding: NdbCryptMethod,
891 block_btree: &'a PstFileReadWriteBlockBTree<Pst>,
892 page_cache: &mut RootBTreePageCache<<Pst as PstFile>::BlockBTree>,
893 block_cache: &'a mut DataBlockCache<Pst>,
894 ) -> io::Result<Self>
895 where
896 <Pst as PstFile>::BlockId: BlockId<Index = <Pst as PstFile>::BTreeKey> + BlockIdReadWrite,
897 <Pst as PstFile>::ByteIndex: ByteIndexReadWrite,
898 <Pst as PstFile>::BlockRef: BlockRefReadWrite,
899 <Pst as PstFile>::PageTrailer: PageTrailerReadWrite,
900 <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
901 <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
902 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
903 <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
904 RootBTreeIntermediatePageReadWrite<
905 Pst,
906 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
907 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
908 >,
909 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
910 RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
911 <Pst as PstFile>::BlockTrailer: BlockTrailerReadWrite,
912 <Pst as PstFile>::DataTreeBlock: IntermediateTreeBlockReadWrite,
913 <<Pst as PstFile>::DataTreeBlock as IntermediateTreeBlock>::Entry:
914 IntermediateTreeEntryReadWrite,
915 <Pst as PstFile>::DataBlock: BlockReadWrite,
916 {
917 let cursor = match data_tree {
918 DataTree::Intermediate(_) => {
919 let next = data_tree
920 .sub_entries(file, encoding, block_btree, page_cache, block_cache)?
921 .collect();
922
923 DataTreeCursor {
924 current: Default::default(),
925 next,
926 }
927 }
928 DataTree::Leaf(block) => DataTreeCursor {
929 current: Cursor::new(block.data().to_vec()),
930 next: Default::default(),
931 },
932 };
933
934 Ok(Self {
935 cursor,
936 file,
937 encoding,
938 })
939 }
940}
941
942impl<Pst, R> Read for DataTreeReader<'_, Pst, R>
943where
944 Pst: PstFile,
945 R: PstReader,
946 <Pst as PstFile>::BlockId: BlockId<Index = <Pst as PstFile>::BTreeKey> + BlockIdReadWrite,
947 <Pst as PstFile>::ByteIndex: ByteIndexReadWrite,
948 <Pst as PstFile>::BlockRef: BlockRefReadWrite,
949 <Pst as PstFile>::PageTrailer: PageTrailerReadWrite,
950 <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
951 <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
952 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
953 <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
954 RootBTreeIntermediatePageReadWrite<
955 Pst,
956 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
957 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
958 >,
959 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
960 RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
961 <Pst as PstFile>::BlockTrailer: BlockTrailerReadWrite,
962 <Pst as PstFile>::DataTreeBlock: IntermediateTreeBlockReadWrite,
963 <<Pst as PstFile>::DataTreeBlock as IntermediateTreeBlock>::Entry:
964 IntermediateTreeEntryReadWrite,
965 <Pst as PstFile>::DataBlock: BlockReadWrite,
966{
967 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
968 let mut total_read = self.cursor.current.read(buf)?;
969
970 while total_read < buf.len() {
971 let Some(next) = self.cursor.next.pop_front() else {
972 break;
973 };
974
975 let next: DataTree<Pst> = DataTree::read(self.file, self.encoding, &next)?;
976 let DataTree::Leaf(next) = next else {
977 error!(
978 name: "PstInvalidDataTreeIntermediateBlock",
979 "Data tree intermediate block has non-leaf sub-entry"
980 );
981
982 return Err(NdbError::InvalidInternalBlockLevel(0).into());
983 };
984 self.cursor.current = Cursor::new(next.data().to_vec());
985
986 let buf = &mut buf[total_read..];
987 total_read += self.cursor.current.read(buf)?;
988 }
989
990 Ok(total_read)
991 }
992}
993
994pub type UnicodeDataTree = DataTree<UnicodePstFile>;
995pub type AnsiDataTree = DataTree<AnsiPstFile>;
996
997#[derive(Clone, Copy, Default)]
998struct SubNodeTreeBlockHeader {
999 level: u8,
1000 entry_count: u16,
1001}
1002
1003#[derive(Clone, Copy, Default)]
1004pub struct UnicodeSubNodeTreeBlockHeader(SubNodeTreeBlockHeader);
1005
1006impl UnicodeSubNodeTreeBlockHeader {
1007 pub fn new(level: u8, entry_count: u16) -> Self {
1008 Self(SubNodeTreeBlockHeader { level, entry_count })
1009 }
1010}
1011
1012impl IntermediateTreeHeader for UnicodeSubNodeTreeBlockHeader {
1013 fn level(&self) -> u8 {
1014 self.0.level
1015 }
1016
1017 fn entry_count(&self) -> u16 {
1018 self.0.entry_count
1019 }
1020}
1021
1022impl IntermediateTreeHeaderReadWrite for UnicodeSubNodeTreeBlockHeader {
1023 const HEADER_SIZE: u16 = 8;
1024
1025 fn read(f: &mut dyn Read) -> io::Result<Self> {
1026 let block_type = f.read_u8()?;
1027 if block_type != 0x02 {
1028 return Err(NdbError::InvalidInternalBlockType(block_type).into());
1029 }
1030
1031 let level = f.read_u8()?;
1032 let entry_count = f.read_u16::<LittleEndian>()?;
1033
1034 let padding = f.read_u32::<LittleEndian>()?;
1035 if padding != 0 {
1036 return Err(NdbError::InvalidSubNodeBlockPadding(padding).into());
1037 }
1038
1039 Ok(Self::new(level, entry_count))
1040 }
1041
1042 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
1043 f.write_u8(0x02)?;
1044 f.write_u8(self.level())?;
1045 f.write_u16::<LittleEndian>(self.entry_count())?;
1046 f.write_u32::<LittleEndian>(0)
1047 }
1048}
1049
1050impl SubNodeTreeBlockHeaderReadWrite for UnicodeSubNodeTreeBlockHeader {
1051 fn new(level: u8, entry_count: u16) -> Self {
1052 Self::new(level, entry_count)
1053 }
1054}
1055
1056#[derive(Clone, Copy, Default)]
1057pub struct AnsiSubNodeTreeBlockHeader(SubNodeTreeBlockHeader);
1058
1059impl AnsiSubNodeTreeBlockHeader {
1060 pub fn new(level: u8, entry_count: u16) -> Self {
1061 Self(SubNodeTreeBlockHeader { level, entry_count })
1062 }
1063}
1064
1065impl IntermediateTreeHeader for AnsiSubNodeTreeBlockHeader {
1066 fn level(&self) -> u8 {
1067 self.0.level
1068 }
1069
1070 fn entry_count(&self) -> u16 {
1071 self.0.entry_count
1072 }
1073}
1074
1075impl IntermediateTreeHeaderReadWrite for AnsiSubNodeTreeBlockHeader {
1076 const HEADER_SIZE: u16 = 4;
1077
1078 fn read(f: &mut dyn Read) -> io::Result<Self> {
1079 let block_type = f.read_u8()?;
1080 if block_type != 0x02 {
1081 return Err(NdbError::InvalidInternalBlockType(block_type).into());
1082 }
1083
1084 let level = f.read_u8()?;
1085 let entry_count = f.read_u16::<LittleEndian>()?;
1086
1087 Ok(Self::new(level, entry_count))
1088 }
1089
1090 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
1091 f.write_u8(0x02)?;
1092 f.write_u8(self.level())?;
1093 f.write_u16::<LittleEndian>(self.entry_count())
1094 }
1095}
1096
1097impl SubNodeTreeBlockHeaderReadWrite for AnsiSubNodeTreeBlockHeader {
1098 fn new(level: u8, entry_count: u16) -> Self {
1099 Self::new(level, entry_count)
1100 }
1101}
1102
1103#[derive(Clone, Copy, Default)]
1105pub struct LeafSubNodeTreeEntry<Block>
1106where
1107 Block: BlockId,
1108{
1109 inner: IntermediateSubNodeTreeEntry<Block>,
1110 sub_node: Option<Block>,
1111}
1112
1113impl<Block> LeafSubNodeTreeEntry<Block>
1114where
1115 Block: BlockId,
1116{
1117 pub fn new(node: NodeId, block: Block, sub_node: Option<Block>) -> Self {
1118 Self {
1119 inner: IntermediateSubNodeTreeEntry::new(node, block),
1120 sub_node,
1121 }
1122 }
1123
1124 pub fn node(&self) -> NodeId {
1125 self.inner.node()
1126 }
1127
1128 pub fn block(&self) -> Block {
1129 self.inner.block()
1130 }
1131
1132 pub fn sub_node(&self) -> Option<Block> {
1133 self.sub_node
1134 }
1135}
1136
1137pub type UnicodeLeafSubNodeTreeEntry = LeafSubNodeTreeEntry<UnicodeBlockId>;
1138pub type AnsiLeafSubNodeTreeEntry = LeafSubNodeTreeEntry<AnsiBlockId>;
1139
1140impl IntermediateTreeEntry for UnicodeLeafSubNodeTreeEntry {}
1141
1142impl IntermediateTreeEntryReadWrite for UnicodeLeafSubNodeTreeEntry {
1143 const ENTRY_SIZE: u16 = 24;
1144
1145 fn read(f: &mut dyn Read) -> io::Result<Self> {
1146 let inner = UnicodeIntermediateSubNodeTreeEntry::read(f)?;
1147 let sub_node = UnicodeBlockId::read(f)?;
1148 let sub_node = if sub_node.search_key() != 0 {
1149 Some(sub_node)
1150 } else {
1151 None
1152 };
1153
1154 Ok(Self::new(inner.node(), inner.block(), sub_node))
1155 }
1156
1157 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
1158 self.inner.write(f)?;
1159 self.sub_node.unwrap_or_default().write(f)
1160 }
1161}
1162
1163impl IntermediateTreeEntry for AnsiLeafSubNodeTreeEntry {}
1164
1165impl IntermediateTreeEntryReadWrite for AnsiLeafSubNodeTreeEntry {
1166 const ENTRY_SIZE: u16 = 12;
1167
1168 fn read(f: &mut dyn Read) -> io::Result<Self> {
1169 let inner = AnsiIntermediateSubNodeTreeEntry::read(f)?;
1170 let sub_node = AnsiBlockId::read(f)?;
1171 let sub_node = if sub_node.search_key() != 0 {
1172 Some(sub_node)
1173 } else {
1174 None
1175 };
1176
1177 Ok(Self::new(inner.node(), inner.block(), sub_node))
1178 }
1179
1180 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
1181 self.inner.write(f)?;
1182 self.sub_node.unwrap_or_default().write(f)
1183 }
1184}
1185
1186#[derive(Clone, Copy, Default)]
1188pub struct IntermediateSubNodeTreeEntry<Block>
1189where
1190 Block: BlockId,
1191{
1192 node: NodeId,
1193 block: Block,
1194}
1195
1196impl<Block> IntermediateSubNodeTreeEntry<Block>
1197where
1198 Block: BlockId,
1199{
1200 pub fn new(node: NodeId, block: Block) -> Self {
1201 Self { node, block }
1202 }
1203
1204 pub fn node(&self) -> NodeId {
1205 self.node
1206 }
1207
1208 pub fn block(&self) -> Block {
1209 self.block
1210 }
1211}
1212
1213pub type UnicodeIntermediateSubNodeTreeEntry = IntermediateSubNodeTreeEntry<UnicodeBlockId>;
1214pub type AnsiIntermediateSubNodeTreeEntry = IntermediateSubNodeTreeEntry<AnsiBlockId>;
1215
1216impl IntermediateTreeEntry for UnicodeIntermediateSubNodeTreeEntry {}
1217
1218impl IntermediateTreeEntryReadWrite for UnicodeIntermediateSubNodeTreeEntry {
1219 const ENTRY_SIZE: u16 = 16;
1220
1221 fn read(f: &mut dyn Read) -> io::Result<Self> {
1222 let node = NodeId::from(f.read_u64::<LittleEndian>()? as u32);
1223 let block = UnicodeBlockId::read(f)?;
1224 Ok(Self::new(node, block))
1225 }
1226
1227 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
1228 f.write_u64::<LittleEndian>(u64::from(u32::from(self.node)))?;
1229 self.block.write(f)
1230 }
1231}
1232
1233impl IntermediateTreeEntry for AnsiIntermediateSubNodeTreeEntry {}
1234
1235impl IntermediateTreeEntryReadWrite for AnsiIntermediateSubNodeTreeEntry {
1236 const ENTRY_SIZE: u16 = 8;
1237
1238 fn read(f: &mut dyn Read) -> io::Result<Self> {
1239 let node = NodeId::read(f)?;
1240 let block = AnsiBlockId::read(f)?;
1241 Ok(Self::new(node, block))
1242 }
1243
1244 fn write(&self, f: &mut dyn Write) -> io::Result<()> {
1245 self.node.write(f)?;
1246 self.block.write(f)
1247 }
1248}
1249
1250pub struct SubNodeTreeBlock<Header, Entry, Trailer>
1253where
1254 Header: IntermediateTreeHeader,
1255 Entry: IntermediateTreeEntry,
1256 Trailer: BlockTrailer,
1257{
1258 header: Header,
1259 entries: Vec<Entry>,
1260 trailer: Trailer,
1261}
1262
1263impl<Header, Entry, Trailer> SubNodeTreeBlock<Header, Entry, Trailer>
1264where
1265 Header: IntermediateTreeHeader,
1266 Entry: IntermediateTreeEntry,
1267 Trailer: BlockTrailer,
1268{
1269 pub fn new(header: Header, entries: Vec<Entry>, trailer: Trailer) -> NdbResult<Self> {
1270 trailer.verify_block_id(true)?;
1271
1272 Ok(Self {
1273 header,
1274 entries,
1275 trailer,
1276 })
1277 }
1278}
1279
1280impl<Header, Entry, Trailer> IntermediateTreeBlock for SubNodeTreeBlock<Header, Entry, Trailer>
1281where
1282 Header: IntermediateTreeHeader,
1283 Entry: IntermediateTreeEntry,
1284 Trailer: BlockTrailer,
1285{
1286 type Header = Header;
1287 type Entry = Entry;
1288 type Trailer = Trailer;
1289
1290 fn header(&self) -> &Self::Header {
1291 &self.header
1292 }
1293
1294 fn entries(&self) -> &[Self::Entry] {
1295 &self.entries
1296 }
1297
1298 fn trailer(&self) -> &Trailer {
1299 &self.trailer
1300 }
1301}
1302
1303impl<Header, Entry, Trailer> IntermediateTreeBlockReadWrite
1304 for SubNodeTreeBlock<Header, Entry, Trailer>
1305where
1306 Header: IntermediateTreeHeaderReadWrite,
1307 Entry: IntermediateTreeEntryReadWrite,
1308 Trailer: BlockTrailerReadWrite,
1309{
1310 fn new(header: Header, entries: Vec<Entry>, trailer: Trailer) -> NdbResult<Self> {
1311 Self::new(header, entries, trailer)
1312 }
1313}
1314
1315pub type UnicodeIntermediateSubNodeTreeBlock = SubNodeTreeBlock<
1316 UnicodeSubNodeTreeBlockHeader,
1317 UnicodeIntermediateSubNodeTreeEntry,
1318 UnicodeBlockTrailer,
1319>;
1320pub type AnsiIntermediateSubNodeTreeBlock = SubNodeTreeBlock<
1321 AnsiSubNodeTreeBlockHeader,
1322 AnsiIntermediateSubNodeTreeEntry,
1323 AnsiBlockTrailer,
1324>;
1325
1326pub type UnicodeLeafSubNodeTreeBlock = SubNodeTreeBlock<
1327 UnicodeSubNodeTreeBlockHeader,
1328 UnicodeLeafSubNodeTreeEntry,
1329 UnicodeBlockTrailer,
1330>;
1331pub type AnsiLeafSubNodeTreeBlock =
1332 SubNodeTreeBlock<AnsiSubNodeTreeBlockHeader, AnsiLeafSubNodeTreeEntry, AnsiBlockTrailer>;
1333
1334pub enum SubNodeTree<Pst>
1335where
1336 Pst: PstFile,
1337{
1338 Intermediate(Box<<Pst as PstFile>::SubNodeTreeBlock>),
1339 Leaf(Box<<Pst as PstFile>::SubNodeBlock>),
1340}
1341
1342impl<Pst> SubNodeTree<Pst>
1343where
1344 Pst: PstFile,
1345 <Pst as PstFile>::BlockTrailer: BlockTrailerReadWrite,
1346 <Pst as PstFile>::SubNodeTreeBlockHeader: IntermediateTreeHeaderReadWrite,
1347 <Pst as PstFile>::SubNodeTreeBlock: IntermediateTreeBlockReadWrite,
1348 <<Pst as PstFile>::SubNodeTreeBlock as IntermediateTreeBlock>::Entry:
1349 IntermediateTreeEntryReadWrite,
1350 <Pst as PstFile>::SubNodeBlock: IntermediateTreeBlockReadWrite,
1351 <<Pst as PstFile>::SubNodeBlock as IntermediateTreeBlock>::Entry:
1352 IntermediateTreeEntryReadWrite,
1353{
1354 pub fn read<R: PstReader>(
1355 f: &mut R,
1356 block: &<Pst as PstFile>::BlockBTreeEntry,
1357 ) -> io::Result<Self> {
1358 f.seek(SeekFrom::Start(block.block().index().index().into()))?;
1359
1360 let block_size = block_size(
1361 block.size() + <<Pst as PstFile>::BlockTrailer as BlockTrailerReadWrite>::SIZE,
1362 );
1363 let mut data = vec![0; block_size as usize];
1364 f.read_exact(&mut data)?;
1365 let mut cursor = Cursor::new(data);
1366 let header =
1367 <<Pst as PstFile>::SubNodeTreeBlockHeader as IntermediateTreeHeaderReadWrite>::read(
1368 &mut cursor,
1369 )?;
1370 cursor.seek(SeekFrom::Start(0))?;
1371
1372 if header.level() > 0 {
1373 let block =
1374 <<Pst as PstFile>::SubNodeTreeBlock as IntermediateTreeBlockReadWrite>::read(
1375 &mut cursor,
1376 header,
1377 block.size(),
1378 )?;
1379 Ok(Self::Intermediate(Box::new(block)))
1380 } else {
1381 let block = <<Pst as PstFile>::SubNodeBlock as IntermediateTreeBlockReadWrite>::read(
1382 &mut cursor,
1383 header,
1384 block.size(),
1385 )?;
1386 Ok(Self::Leaf(Box::new(block)))
1387 }
1388 }
1389
1390 pub fn write<W: Write + Seek>(
1391 &self,
1392 f: &mut W,
1393 block: &<Pst as PstFile>::BlockBTreeEntry,
1394 ) -> io::Result<()> {
1395 f.seek(SeekFrom::Start(block.block().index().index().into()))?;
1396
1397 match self {
1398 Self::Intermediate(block) => block.write(f),
1399 Self::Leaf(block) => block.write(f),
1400 }
1401 }
1402
1403 pub fn find_entry<R>(
1404 &self,
1405 f: &mut R,
1406 block_btree: &PstFileReadWriteBlockBTree<Pst>,
1407 node: NodeId,
1408 page_cache: &mut RootBTreePageCache<<Pst as PstFile>::BlockBTree>,
1409 ) -> io::Result<<Pst as PstFile>::BlockId>
1410 where
1411 R: PstReader,
1412 <Pst as PstFile>::BlockId: BlockId<Index = <Pst as PstFile>::BTreeKey> + BlockIdReadWrite,
1413 <Pst as PstFile>::ByteIndex: ByteIndexReadWrite,
1414 <Pst as PstFile>::BlockRef: BlockRefReadWrite,
1415 <Pst as PstFile>::PageTrailer: PageTrailerReadWrite,
1416 <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
1417 <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
1418 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
1419 <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
1420 RootBTreeIntermediatePageReadWrite<
1421 Pst,
1422 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
1423 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
1424 >,
1425 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
1426 RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
1427 {
1428 match self {
1429 Self::Intermediate(block) => {
1430 let entries = block.entries();
1431 let index =
1432 entries.partition_point(|entry| u32::from(entry.node()) <= u32::from(node));
1433 let entry = index
1434 .checked_sub(1)
1435 .and_then(|index| entries.get(index))
1436 .ok_or(NdbError::SubNodeNotFound(node))?;
1437 let block = block_btree.find_entry(f, entry.block().search_key(), page_cache)?;
1438 let page = Self::read(f, &block)?;
1439 page.find_entry(f, block_btree, node, page_cache)
1440 }
1441 Self::Leaf(block) => {
1442 let entry = block
1443 .entries()
1444 .iter()
1445 .find(|entry| u32::from(entry.node()) == u32::from(node))
1446 .map(|entry| entry.block())
1447 .ok_or(NdbError::SubNodeNotFound(node))?;
1448 Ok(entry)
1449 }
1450 }
1451 }
1452
1453 pub fn entries<'a, R>(
1454 &self,
1455 f: &mut R,
1456 block_btree: &PstFileReadWriteBlockBTree<Pst>,
1457 page_cache: &mut RootBTreePageCache<<Pst as PstFile>::BlockBTree>,
1458 ) -> io::Result<Box<dyn 'a + Iterator<Item = LeafSubNodeTreeEntry<<Pst as PstFile>::BlockId>>>>
1459 where
1460 R: PstReader,
1461 <Pst as PstFile>::BlockId:
1462 'a + BlockId<Index = <Pst as PstFile>::BTreeKey> + BlockIdReadWrite,
1463 <Pst as PstFile>::ByteIndex: ByteIndexReadWrite,
1464 <Pst as PstFile>::BlockRef: BlockRefReadWrite,
1465 <Pst as PstFile>::PageTrailer: PageTrailerReadWrite,
1466 <Pst as PstFile>::BTreeKey: BTreePageKeyReadWrite,
1467 <Pst as PstFile>::BlockBTree: RootBTreeReadWrite,
1468 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry: BTreeEntryReadWrite,
1469 <<Pst as PstFile>::BlockBTree as RootBTree>::IntermediatePage:
1470 RootBTreeIntermediatePageReadWrite<
1471 Pst,
1472 <<Pst as PstFile>::BlockBTree as RootBTree>::Entry,
1473 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage,
1474 >,
1475 <<Pst as PstFile>::BlockBTree as RootBTree>::LeafPage:
1476 RootBTreeLeafPageReadWrite<Pst> + BTreePageReadWrite,
1477 {
1478 match self {
1479 Self::Intermediate(block) => {
1480 let entries = block
1481 .entries()
1482 .iter()
1483 .map(|entry| {
1484 let block =
1485 block_btree.find_entry(f, entry.block().search_key(), page_cache)?;
1486 let sub_nodes = Self::read(f, &block)?;
1487 sub_nodes.entries(f, block_btree, page_cache)
1488 })
1489 .collect::<io::Result<Vec<_>>>()?;
1490 Ok(Box::new(entries.into_iter().flatten()))
1491 }
1492 Self::Leaf(block) => {
1493 let entries = block.entries().to_vec();
1494 Ok(Box::new(entries.into_iter()))
1495 }
1496 }
1497 }
1498}
1499
1500pub type UnicodeSubNodeTree = SubNodeTree<UnicodePstFile>;
1501pub type AnsiSubNodeTree = SubNodeTree<AnsiPstFile>;