PST File Format SDK v0.4
Loading...
Searching...
No Matches
database.h
Go to the documentation of this file.
1
7
8#ifndef PSTSDK_NDB_DATABASE_H
9#define PSTSDK_NDB_DATABASE_H
10
11#include <fstream>
12#include <memory>
13
14#include "pstsdk/util/btree.h"
15#include "pstsdk/util/errors.h"
17#include "pstsdk/util/util.h"
18
19#include "pstsdk/disk/disk.h"
20
21#include "pstsdk/ndb/node.h"
22#include "pstsdk/ndb/page.h"
24
25namespace pstsdk
26{
27
28class node;
29
30template<typename T>
31class database_impl;
34
42shared_db_ptr open_database(const std::wstring& filename);
50shared_db_ptr open_database(std::shared_ptr<file> file);
63std::shared_ptr<small_pst> open_small_pst(const std::wstring& filename);
71std::shared_ptr<small_pst> open_small_pst(std::shared_ptr<file> file);
79std::shared_ptr<large_pst> open_large_pst(const std::wstring& filename);
87std::shared_ptr<large_pst> open_large_pst(std::shared_ptr<file> file);
88
100template<typename T>
102{
103public:
104
106
108 { return node(this->shared_from_this(), lookup_node_info(nid)); }
112
114
115 std::shared_ptr<bbt_page> read_bbt_root();
116 std::shared_ptr<nbt_page> read_nbt_root();
117 std::shared_ptr<bbt_page> read_bbt_page(const page_info& pi);
118 std::shared_ptr<nbt_page> read_nbt_page(const page_info& pi);
119 std::shared_ptr<nbt_leaf_page> read_nbt_leaf_page(const page_info& pi);
120 std::shared_ptr<bbt_leaf_page> read_bbt_leaf_page(const page_info& pi);
121 std::shared_ptr<nbt_nonleaf_page> read_nbt_nonleaf_page(const page_info& pi);
122 std::shared_ptr<bbt_nonleaf_page> read_bbt_nonleaf_page(const page_info& pi);
124
126
127 std::shared_ptr<block> read_block(const shared_db_ptr& parent, block_id bid)
128 { return read_block(parent, lookup_block_info(bid)); }
129 std::shared_ptr<data_block> read_data_block(const shared_db_ptr& parent, block_id bid)
130 { return read_data_block(parent, lookup_block_info(bid)); }
131 std::shared_ptr<extended_block> read_extended_block(const shared_db_ptr& parent, block_id bid)
133 std::shared_ptr<external_block> read_external_block(const shared_db_ptr& parent, block_id bid)
135 std::shared_ptr<subnode_block> read_subnode_block(const shared_db_ptr& parent, block_id bid)
137 std::shared_ptr<subnode_leaf_block> read_subnode_leaf_block(const shared_db_ptr& parent, block_id bid)
139 std::shared_ptr<subnode_nonleaf_block> read_subnode_nonleaf_block(const shared_db_ptr& parent, block_id bid)
141
142 std::shared_ptr<block> read_block(const shared_db_ptr& parent, const block_info& bi);
143 std::shared_ptr<data_block> read_data_block(const shared_db_ptr& parent, const block_info& bi);
144 std::shared_ptr<extended_block> read_extended_block(const shared_db_ptr& parent, const block_info& bi);
145 std::shared_ptr<external_block> read_external_block(const shared_db_ptr& parent, const block_info& bi);
146 std::shared_ptr<subnode_block> read_subnode_block(const shared_db_ptr& parent, const block_info& bi);
147 std::shared_ptr<subnode_leaf_block> read_subnode_leaf_block(const shared_db_ptr& parent, const block_info& bi);
148 std::shared_ptr<subnode_nonleaf_block> read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi);
150
152 std::shared_ptr<external_block> create_external_block(const shared_db_ptr& parent, size_t size);
153 std::shared_ptr<extended_block> create_extended_block(const shared_db_ptr& parent, std::shared_ptr<external_block>& pblock);
154 std::shared_ptr<extended_block> create_extended_block(const shared_db_ptr& parent, std::shared_ptr<extended_block>& pblock);
155 std::shared_ptr<extended_block> create_extended_block(const shared_db_ptr& parent, size_t size);
156
157 block_id alloc_bid(bool is_internal);
159
160protected:
161 database_impl(); // = delete
166 database_impl(const std::wstring& filename);
167
172 database_impl(std::shared_ptr<file> file);
173
177
182
189 std::vector<byte> read_block_data(const block_info& bi);
197 std::vector<byte> read_page_data(const page_info& pi);
198
199 std::shared_ptr<nbt_leaf_page> read_nbt_leaf_page(const page_info& pi, disk::nbt_leaf_page<T>& the_page);
200 std::shared_ptr<bbt_leaf_page> read_bbt_leaf_page(const page_info& pi, disk::bbt_leaf_page<T>& the_page);
201
202 template<typename K, typename V>
203 std::shared_ptr<bt_nonleaf_page<K,V> > read_bt_nonleaf_page(const page_info& pi, disk::bt_page<T, disk::bt_entry<T> >& the_page);
204
205 std::shared_ptr<subnode_leaf_block> read_subnode_leaf_block(const shared_db_ptr& parent, const block_info& bi, disk::sub_leaf_block<T>& sub_block);
206 std::shared_ptr<subnode_nonleaf_block> read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi, disk::sub_nonleaf_block<T>& sub_block);
207
208 friend shared_db_ptr open_database(const std::wstring& filename);
209 friend shared_db_ptr open_database(std::shared_ptr<file> file);
211
212 friend std::shared_ptr<small_pst> open_small_pst(const std::wstring& filename);
213 friend std::shared_ptr<small_pst> open_small_pst(std::shared_ptr<file> file);
214 friend std::shared_ptr<large_pst> open_large_pst(const std::wstring& filename);
215 friend std::shared_ptr<large_pst> open_large_pst(std::shared_ptr<file> file);
216
217 std::shared_ptr<file> m_file;
219 std::shared_ptr<bbt_page> m_bbt_root;
220 std::shared_ptr<nbt_page> m_nbt_root;
221};
222
224template<>
226{
227 // the behavior of open_database depends on this throw; this can not go under PSTSDK_VALIDATION_WEAK
228 if(m_header.wVer >= disk::database_format_unicode_min)
229 throw invalid_format();
230
231#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
233
234 if(crc != m_header.dwCRCPartial)
235 throw crc_fail("header dwCRCPartial failure", 0, 0, crc, m_header.dwCRCPartial);
236#endif
237}
238
239template<>
241{
242 // the behavior of open_database depends on this throw; this can not go under PSTSDK_VALIDATION_WEAK
243 if(m_header.wVer < disk::database_format_unicode_min)
244 throw invalid_format();
245
246#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
247 ulong crc_partial = disk::compute_crc(((byte*)&m_header) + disk::header_crc_locations<ulonglong>::partial_start, disk::header_crc_locations<ulonglong>::partial_length);
248 ulong crc_full = disk::compute_crc(((byte*)&m_header) + disk::header_crc_locations<ulonglong>::full_start, disk::header_crc_locations<ulonglong>::full_length);
249
250 if(crc_partial != m_header.dwCRCPartial)
251 throw crc_fail("header dwCRCPartial failure", 0, 0, crc_partial, m_header.dwCRCPartial);
252
253 if(crc_full != m_header.dwCRCFull)
254 throw crc_fail("header dwCRCFull failure", 0, 0, crc_full, m_header.dwCRCFull);
255#endif
256}
258} // end namespace
259
261{
262 try
263 {
265 return db;
266 }
267 catch(invalid_format&)
268 {
269 // well, that didn't work
270 }
271
273 return db;
274}
275
276inline std::shared_ptr<pstsdk::small_pst> pstsdk::open_small_pst(const std::wstring& filename)
277{
278 std::shared_ptr<small_pst> db(new small_pst(filename));
279 return db;
280}
281
282inline std::shared_ptr<pstsdk::small_pst> pstsdk::open_small_pst(std::shared_ptr<file> custom_file)
283{
284 std::shared_ptr<small_pst> db(new small_pst(custom_file));
285 return db;
286}
287
288inline std::shared_ptr<pstsdk::large_pst> pstsdk::open_large_pst(const std::wstring& filename)
289{
290 std::shared_ptr<large_pst> db(new large_pst(filename));
291 return db;
292}
293
294inline std::shared_ptr<pstsdk::large_pst> pstsdk::open_large_pst(std::shared_ptr<file> custom_file)
295{
296 std::shared_ptr<large_pst> db(new large_pst(custom_file));
297 return db;
298}
299
301{
302 std::vector<byte> version_buf(2);
303 custom_file->read(version_buf, 10);
304 ushort wver;
305 memcpy(&wver, version_buf.data(), sizeof(ushort));
306
308 if (wver >= disk::database_format_unicode_min) {
310 } else {
312 }
313
314 if (!db) throw invalid_format();
315
316 return db;
317}
318
320{
321 auto small_pst_db = dynamic_cast<small_pst *>(other_database.get());
322 if (small_pst_db) return std::shared_ptr<small_pst>(new small_pst(small_pst_db));
323
324 auto large_pst_db = dynamic_cast<large_pst *>(other_database.get());
325 if (large_pst_db) return std::shared_ptr<large_pst>(new large_pst(large_pst_db));
326
327 return nullptr;
328}
329
330template<typename T>
331inline std::vector<pstsdk::byte> pstsdk::database_impl<T>::read_block_data(const block_info& bi)
332{
333 size_t aligned_size = disk::align_disk<T>(bi.size);
334
335#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
337 throw unexpected_block("nonsensical block size");
338
339 if(bi.address + aligned_size > m_header.root_info.ibFileEof)
340 throw unexpected_block("nonsensical block location; past eof");
341#endif
342
343 std::vector<byte> buffer(aligned_size);
345
346 m_file->read(buffer, bi.address);
347
348#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
349 if(bt->bid != bi.id)
350 throw unexpected_block("wrong block id");
351
352 if(bt->cb != bi.size)
353 throw unexpected_block("wrong block size");
354
355 if(bt->signature != disk::compute_signature(bi.id, bi.address))
356 throw sig_mismatch("block sig mismatch", bi.address, bi.id, disk::compute_signature(bi.id, bi.address), bt->signature);
357#endif
358
359#ifdef PSTSDK_VALIDATION_LEVEL_FULL
360 ulong crc = disk::compute_crc(&buffer[0], bi.size);
361 if(crc != bt->crc)
362 throw crc_fail("block crc failure", bi.address, bi.id, crc, bt->crc);
363#endif
364
365 return buffer;
366}
367
368template<typename T>
370{
371#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
372 if(pi.address + disk::page_size > m_header.root_info.ibFileEof)
373 throw unexpected_page("nonsensical page location; past eof");
374
375 if(((pi.address - disk::first_amap_page_location) % disk::page_size) != 0)
376 throw unexpected_page("nonsensical page location; not sector aligned");
377#endif
378
379 std::vector<byte> buffer(disk::page_size);
381
382 m_file->read(buffer, pi.address);
383
384#ifdef PSTSDK_VALIDATION_LEVEL_FULL
386 if(crc != ppage->trailer.crc)
387 throw crc_fail("page crc failure", pi.address, pi.id, crc, ppage->trailer.crc);
388#endif
389
390#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
391 if(ppage->trailer.bid != pi.id)
392 throw unexpected_page("wrong page id");
393
394 if(ppage->trailer.page_type != ppage->trailer.page_type_repeat)
395 throw database_corrupt("ptype != ptype repeat?");
396
397 if(ppage->trailer.signature != disk::compute_signature(pi.id, pi.address))
398 throw sig_mismatch("page sig mismatch", pi.address, pi.id, disk::compute_signature(pi.id, pi.address), ppage->trailer.signature);
399#endif
400
401 return buffer;
402}
403
404
405template<typename T>
406inline std::shared_ptr<pstsdk::bbt_page> pstsdk::database_impl<T>::read_bbt_root()
407{
408 if(!m_bbt_root)
409 {
410 page_info pi = { m_header.root_info.brefBBT.bid, m_header.root_info.brefBBT.ib };
411 m_bbt_root = read_bbt_page(pi);
412 }
413
414 return m_bbt_root;
415}
416
417template<typename T>
418inline std::shared_ptr<pstsdk::nbt_page> pstsdk::database_impl<T>::read_nbt_root()
419{
420 if(!m_nbt_root)
421 {
422 page_info pi = { m_header.root_info.brefNBT.bid, m_header.root_info.brefNBT.ib };
423 m_nbt_root = read_nbt_page(pi);
424 }
425
426 return m_nbt_root;
427}
428
429template<typename T>
431: m_file(std::make_unique<file>(filename))
432{
433 std::vector<byte> buffer(sizeof(m_header));
434 m_file->read(buffer, 0);
435 memcpy(&m_header, &buffer[0], sizeof(m_header));
436
438}
439
440template<typename T>
442: m_file(file)
443{
444 std::vector<byte> buffer(sizeof(m_header));
445 m_file->read(buffer, 0);
446 memcpy(&m_header, &buffer[0], sizeof(m_header));
447
449}
450
451template<typename T>
453: m_file(other_database->m_file)
454{
455 // We assume that the header was already validated, so just copy it
456 memcpy(&m_header, &other_database->m_header, sizeof(m_header));
457}
458
459template<typename T>
460inline std::shared_ptr<pstsdk::nbt_leaf_page> pstsdk::database_impl<T>::read_nbt_leaf_page(const page_info& pi)
461{
462 std::vector<byte> buffer = read_page_data(pi);
464
465 if(ppage->trailer.page_type == disk::page_type_nbt)
466 {
468
469 if(leaf_page->level == 0)
470 return read_nbt_leaf_page(pi, *leaf_page);
471 }
472
473 throw unexpected_page("page_type != page_type_nbt");
474}
475
476template<typename T>
477inline std::shared_ptr<pstsdk::nbt_leaf_page> pstsdk::database_impl<T>::read_nbt_leaf_page(const page_info& pi, disk::nbt_leaf_page<T>& the_page)
478{
480 std::vector<std::pair<node_id, node_info> > nodes;
481
482 for(int i = 0; i < the_page.num_entries; ++i)
483 {
484 ni.id = static_cast<node_id>(the_page.entries[i].nid);
485 ni.data_bid = the_page.entries[i].data;
486 ni.sub_bid = the_page.entries[i].sub;
487 ni.parent_id = the_page.entries[i].parent_nid;
488
489 nodes.push_back(std::make_pair(ni.id, ni));
490 }
491
492#ifndef BOOST_NO_RVALUE_REFERENCES
493 return std::shared_ptr<nbt_leaf_page>(new nbt_leaf_page(shared_from_this(), pi, std::move(nodes)));
494#else
495 return std::shared_ptr<nbt_leaf_page>(new nbt_leaf_page(shared_from_this(), pi, nodes));
496#endif
497}
498
499template<typename T>
500inline std::shared_ptr<pstsdk::bbt_leaf_page> pstsdk::database_impl<T>::read_bbt_leaf_page(const page_info& pi)
501{
502 std::vector<byte> buffer = read_page_data(pi);
504
505 if(ppage->trailer.page_type == disk::page_type_bbt)
506 {
508
509 if(leaf_page->level == 0)
510 return read_bbt_leaf_page(pi, *leaf_page);
511 }
512
513 throw unexpected_page("page_type != page_type_bbt");
514}
515
516template<typename T>
517inline std::shared_ptr<pstsdk::bbt_leaf_page> pstsdk::database_impl<T>::read_bbt_leaf_page(const page_info& pi, disk::bbt_leaf_page<T>& the_page)
518{
520 std::vector<std::pair<block_id, block_info> > blocks;
521
522 for(int i = 0; i < the_page.num_entries; ++i)
523 {
524 bi.id = the_page.entries[i].ref.bid;
525 bi.address = the_page.entries[i].ref.ib;
526 bi.size = the_page.entries[i].size;
527 bi.ref_count = the_page.entries[i].ref_count;
528
529 blocks.push_back(std::make_pair(bi.id, bi));
530 }
531
532#ifndef BOOST_NO_RVALUE_REFERENCES
533 return std::shared_ptr<bbt_leaf_page>(new bbt_leaf_page(shared_from_this(), pi, std::move(blocks)));
534#else
535 return std::shared_ptr<bbt_leaf_page>(new bbt_leaf_page(shared_from_this(), pi, blocks));
536#endif
537}
538
539template<typename T>
540inline std::shared_ptr<pstsdk::nbt_nonleaf_page> pstsdk::database_impl<T>::read_nbt_nonleaf_page(const page_info& pi)
541{
542 std::vector<byte> buffer = read_page_data(pi);
544
545 if(ppage->trailer.page_type == disk::page_type_nbt)
546 {
548
549 if(nonleaf_page->level > 0)
551 }
552
553 throw unexpected_page("page_type != page_type_nbt");
554}
555
556template<typename T>
557template<typename K, typename V>
558inline std::shared_ptr<pstsdk::bt_nonleaf_page<K,V> > pstsdk::database_impl<T>::read_bt_nonleaf_page(const page_info& pi, pstsdk::disk::bt_page<T, disk::bt_entry<T> >& the_page)
559{
560 std::vector<std::pair<K, page_info> > nodes;
561
562 for(int i = 0; i < the_page.num_entries; ++i)
563 {
564 page_info subpi = { the_page.entries[i].ref.bid, the_page.entries[i].ref.ib };
565 nodes.push_back(std::make_pair(static_cast<K>(the_page.entries[i].key), subpi));
566 }
567
568#ifndef BOOST_NO_RVALUE_REFERENCES
569 return std::shared_ptr<bt_nonleaf_page<K,V> >(new bt_nonleaf_page<K,V>(shared_from_this(), pi, the_page.level, std::move(nodes)));
570#else
571 return std::shared_ptr<bt_nonleaf_page<K,V> >(new bt_nonleaf_page<K,V>(shared_from_this(), pi, the_page.level, nodes));
572#endif
573}
574
575template<typename T>
576inline std::shared_ptr<pstsdk::bbt_nonleaf_page> pstsdk::database_impl<T>::read_bbt_nonleaf_page(const page_info& pi)
577{
578 std::vector<byte> buffer = read_page_data(pi);
580
581 if(ppage->trailer.page_type == disk::page_type_bbt)
582 {
584
585 if(nonleaf_page->level > 0)
587 }
588
589 throw unexpected_page("page_type != page_type_bbt");
590}
591
592template<typename T>
593inline std::shared_ptr<pstsdk::bbt_page> pstsdk::database_impl<T>::read_bbt_page(const page_info& pi)
594{
595 std::vector<byte> buffer = read_page_data(pi);
597
598 if(ppage->trailer.page_type == disk::page_type_bbt)
599 {
601 if(leaf->level == 0)
602 {
603 // it really is a leaf!
604 return read_bbt_leaf_page(pi, *leaf);
605 }
606 else
607 {
610 }
611 }
612 else
613 {
614 throw unexpected_page("page_type != page_type_bbt");
615 }
616}
617
618template<typename T>
619inline std::shared_ptr<pstsdk::nbt_page> pstsdk::database_impl<T>::read_nbt_page(const page_info& pi)
620{
621 std::vector<byte> buffer = read_page_data(pi);
623
624 if(ppage->trailer.page_type == disk::page_type_nbt)
625 {
627 if(leaf->level == 0)
628 {
629 // it really is a leaf!
630 return read_nbt_leaf_page(pi, *leaf);
631 }
632 else
633 {
636 }
637 }
638 else
639 {
640 throw unexpected_page("page_type != page_type_nbt");
641 }
642}
643
644template<typename T>
646{
647 return read_nbt_root()->lookup(nid);
648}
649
650template<typename T>
652{
653 if(bid == 0)
654 {
656 bi.id = bi.address = bi.size = bi.ref_count = 0;
657 return bi;
658 }
659 else
660 {
661 return read_bbt_root()->lookup(bid & (~(block_id(disk::block_id_attached_bit))));
662 }
663}
664
665template<typename T>
666inline std::shared_ptr<pstsdk::block> pstsdk::database_impl<T>::read_block(const shared_db_ptr& parent, const block_info& bi)
667{
668 std::shared_ptr<block> pblock;
669
670 try
671 {
672 pblock = read_data_block(parent, bi);
673 }
674 catch(unexpected_block&)
675 {
676 pblock = read_subnode_block(parent, bi);
677 }
678
679 return pblock;
680}
681
682template<typename T>
683inline std::shared_ptr<pstsdk::data_block> pstsdk::database_impl<T>::read_data_block(const shared_db_ptr& parent, const block_info& bi)
684{
686 return read_external_block(parent, bi);
687
688 std::vector<byte> buffer(sizeof(disk::extended_block<T>));
690 m_file->read(buffer, bi.address);
691
692 // the behavior of read_block depends on this throw; this can not go under PSTSDK_VALIDATION_WEAK
693 if(peblock->block_type != disk::block_type_extended)
694 throw unexpected_block("extended block expected");
695
696 return read_extended_block(parent, bi);
697}
698
699template<typename T>
700inline std::shared_ptr<pstsdk::extended_block> pstsdk::database_impl<T>::read_extended_block(const shared_db_ptr& parent, const block_info& bi)
701{
703 throw unexpected_block("internal bid expected");
704
705 std::vector<byte> buffer = read_block_data(bi);
707 std::vector<block_id> child_blocks;
708
709 for(int i = 0; i < peblock->count; ++i)
710 child_blocks.push_back(peblock->bid[i]);
711
712#ifdef __GNUC__
713 // GCC gave link errors on extended_block<T> and external_block<T> max_size
714 // with the below alernative
715 uint sub_size = 0;
716 if(peblock->level == 1)
718 else
719 sub_size = disk::extended_block<T>::max_size;
720#else
721 uint sub_size = (peblock->level == 1 ? disk::external_block<T>::max_size : disk::extended_block<T>::max_size);
722#endif
723 uint sub_page_count = peblock->level == 1 ? 1 : disk::extended_block<T>::max_count;
724
725#ifndef BOOST_NO_RVALUE_REFERENCES
726 return std::shared_ptr<extended_block>(new extended_block(parent, bi, peblock->level, peblock->total_size, sub_size, disk::extended_block<T>::max_count, sub_page_count, std::move(child_blocks)));
727#else
728 return std::shared_ptr<extended_block>(new extended_block(parent, bi, peblock->level, peblock->total_size, sub_size, disk::extended_block<T>::max_count, sub_page_count, child_blocks));
729#endif
730}
731
733template<typename T>
734inline std::shared_ptr<pstsdk::external_block> pstsdk::database_impl<T>::create_external_block(const shared_db_ptr& parent, size_t size)
735{
736 return std::shared_ptr<external_block>(new external_block(parent, disk::external_block<T>::max_size, size));
737}
738
739template<typename T>
740inline std::shared_ptr<pstsdk::extended_block> pstsdk::database_impl<T>::create_extended_block(const shared_db_ptr& parent, std::shared_ptr<external_block>& pchild_block)
741{
742 std::vector<std::shared_ptr<data_block> > child_blocks;
743 child_blocks.push_back(pchild_block);
744
745#ifndef BOOST_NO_RVALUE_REFERENCES
746 return std::shared_ptr<extended_block>(new extended_block(parent, 1, pchild_block->get_total_size(), disk::external_block<T>::max_size, disk::extended_block<T>::max_count, 1, std::move(child_blocks)));
747#else
748 return std::shared_ptr<extended_block>(new extended_block(parent, 1, pchild_block->get_total_size(), disk::external_block<T>::max_size, disk::extended_block<T>::max_count, 1, child_blocks));
749#endif
750}
751
752template<typename T>
753inline std::shared_ptr<pstsdk::extended_block> pstsdk::database_impl<T>::create_extended_block(const shared_db_ptr& parent, std::shared_ptr<extended_block>& pchild_block)
754{
755 std::vector<std::shared_ptr<data_block> > child_blocks;
756 child_blocks.push_back(pchild_block);
757
758 assert(pchild_block->get_level() == 1);
759
760#ifndef BOOST_NO_RVALUE_REFERENCES
761 return std::shared_ptr<extended_block>(new extended_block(parent, 2, pchild_block->get_total_size(), disk::extended_block<T>::max_size, disk::extended_block<T>::max_count, disk::extended_block<T>::max_count, std::move(child_blocks)));
762#else
763 return std::shared_ptr<extended_block>(new extended_block(parent, 2, pchild_block->get_total_size(), disk::extended_block<T>::max_size, disk::extended_block<T>::max_count, disk::extended_block<T>::max_count, child_blocks));
764#endif
765}
766
767template<typename T>
768inline std::shared_ptr<pstsdk::extended_block> pstsdk::database_impl<T>::create_extended_block(const shared_db_ptr& parent, size_t size)
769{
770 ushort level = size > disk::extended_block<T>::max_size ? 2 : 1;
771#ifdef __GNUC__
772 // More strange link errors
773 size_t child_max_size;
774 if(level == 1)
775 child_max_size = disk::external_block<T>::max_size;
776 else
777 child_max_size = disk::extended_block<T>::max_size;
778#else
779 size_t child_max_size = level == 1 ? disk::external_block<T>::max_size : disk::extended_block<T>::max_size;
780#endif
781 ulong child_max_blocks = level == 1 ? 1 : disk::extended_block<T>::max_count;
782
783 return std::shared_ptr<extended_block>(new extended_block(parent, level, size, child_max_size, disk::extended_block<T>::max_count, child_max_blocks));
784}
786
787template<typename T>
788inline std::shared_ptr<pstsdk::external_block> pstsdk::database_impl<T>::read_external_block(const shared_db_ptr& parent, const block_info& bi)
789{
790 if(bi.id == 0)
791 {
792 return std::shared_ptr<external_block>(new external_block(parent, bi, disk::external_block<T>::max_size, std::vector<byte>()));
793 }
794
796 throw unexpected_block("External BID expected");
797
798 std::vector<byte> buffer = read_block_data(bi);
799
800 if(m_header.bCryptMethod == disk::crypt_method_permute)
801 {
802 disk::permute(&buffer[0], bi.size, false);
803 }
804 else if(m_header.bCryptMethod == disk::crypt_method_cyclic)
805 {
806 disk::cyclic(&buffer[0], bi.size, (ulong)bi.id);
807 }
808
809#ifndef BOOST_NO_RVALUE_REFERENCES
810 return std::shared_ptr<external_block>(new external_block(parent, bi, disk::external_block<T>::max_size, std::move(buffer)));
811#else
812 return std::shared_ptr<external_block>(new external_block(parent, bi, disk::external_block<T>::max_size, buffer));
813#endif
814}
815
816template<typename T>
817inline std::shared_ptr<pstsdk::subnode_block> pstsdk::database_impl<T>::read_subnode_block(const shared_db_ptr& parent, const block_info& bi)
818{
819 if(bi.id == 0)
820 {
821 return std::shared_ptr<subnode_block>(new subnode_leaf_block(parent, bi, std::vector<std::pair<node_id, subnode_info> >()));
822 }
823
824 std::vector<byte> buffer = read_block_data(bi);
826 std::shared_ptr<subnode_block> sub_block;
827
828 if(psub->level == 0)
829 {
830 sub_block = read_subnode_leaf_block(parent, bi, *psub);
831 }
832 else
833 {
834 sub_block = read_subnode_nonleaf_block(parent, bi, *(disk::sub_nonleaf_block<T>*)&buffer[0]);
835 }
836
837 return sub_block;
838}
839
840template<typename T>
841inline std::shared_ptr<pstsdk::subnode_leaf_block> pstsdk::database_impl<T>::read_subnode_leaf_block(const shared_db_ptr& parent, const block_info& bi)
842{
843 std::vector<byte> buffer = read_block_data(bi);
845 std::shared_ptr<subnode_leaf_block> sub_block;
846
847 if(psub->level == 0)
848 {
849 sub_block = read_subnode_leaf_block(parent, bi, *psub);
850 }
851 else
852 {
853 throw unexpected_block("psub->level != 0");
854 }
855
856 return sub_block;
857}
858
859template<typename T>
860inline std::shared_ptr<pstsdk::subnode_nonleaf_block> pstsdk::database_impl<T>::read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi)
861{
862 std::vector<byte> buffer = read_block_data(bi);
864 std::shared_ptr<subnode_nonleaf_block> sub_block;
865
866 if(psub->level != 0)
867 {
868 sub_block = read_subnode_nonleaf_block(parent, bi, *psub);
869 }
870 else
871 {
872 throw unexpected_block("psub->level == 1");
873 }
874
875 return sub_block;
876}
877
878template<typename T>
879inline std::shared_ptr<pstsdk::subnode_leaf_block> pstsdk::database_impl<T>::read_subnode_leaf_block(const shared_db_ptr& parent, const block_info& bi, disk::sub_leaf_block<T>& sub_block)
880{
882 std::vector<std::pair<node_id, subnode_info> > subnodes;
883
884 for(int i = 0; i < sub_block.count; ++i)
885 {
886 ni.id = sub_block.entry[i].nid;
887 ni.data_bid = sub_block.entry[i].data;
888 ni.sub_bid = sub_block.entry[i].sub;
889
890 subnodes.push_back(std::make_pair(sub_block.entry[i].nid, ni));
891 }
892
893#ifndef BOOST_NO_RVALUE_REFERENCES
894 return std::shared_ptr<subnode_leaf_block>(new subnode_leaf_block(parent, bi, std::move(subnodes)));
895#else
896 return std::shared_ptr<subnode_leaf_block>(new subnode_leaf_block(parent, bi, subnodes));
897#endif
898}
899
900template<typename T>
901inline std::shared_ptr<pstsdk::subnode_nonleaf_block> pstsdk::database_impl<T>::read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi, disk::sub_nonleaf_block<T>& sub_block)
902{
903 std::vector<std::pair<node_id, block_id> > subnodes;
904
905 for(int i = 0; i < sub_block.count; ++i)
906 {
907 subnodes.push_back(std::make_pair(sub_block.entry[i].nid_key, sub_block.entry[i].sub_block_bid));
908 }
909
910#ifndef BOOST_NO_RVALUE_REFERENCES
911 return std::shared_ptr<subnode_nonleaf_block>(new subnode_nonleaf_block(parent, bi, std::move(subnodes)));
912#else
913 return std::shared_ptr<subnode_nonleaf_block>(new subnode_nonleaf_block(parent, bi, subnodes));
914#endif
915}
916
918template<typename T>
920{
921#ifdef __GNUC__
923 memcpy(&disk_id, m_header.bidNextB, sizeof(disk_id));
924
926
928 memcpy(m_header.bidNextB, &disk_id, sizeof(disk_id));
929#else
930 block_id next_bid = m_header.bidNextB;
931 m_header.bidNextB += disk::block_id_increment;
932#endif
933
934
935 if(is_internal)
937
938 return next_bid;
939}
941
942#endif
Generic BTree implementation.
Contains references to other bth_node allocations.
Definition heap.h:364
const V & lookup(const K &key) const
Looks up the associated value for a given key.
Definition btree.h:358
A CRC of an item failed.
Definition errors.h:84
The database is corrupt.
Definition errors.h:48
PST implementation.
Definition database.h:102
std::shared_ptr< bt_nonleaf_page< K, V > > read_bt_nonleaf_page(const page_info &pi, disk::bt_page< T, disk::bt_entry< T > > &the_page)
std::shared_ptr< nbt_page > read_nbt_page(const page_info &pi)
Open a NBT page.
Definition database.h:619
std::shared_ptr< subnode_nonleaf_block > read_subnode_nonleaf_block(const shared_db_ptr &parent, block_id bid)
Open a subnode_nonleaf_block in the specified context.
Definition database.h:139
std::shared_ptr< bbt_page > read_bbt_page(const page_info &pi)
Open a BBT page.
Definition database.h:593
node_info lookup_node_info(node_id nid)
Lookup information about a node.
Definition database.h:645
std::vector< byte > read_block_data(const block_info &bi)
Read block data, perform validation checks.
Definition database.h:331
std::vector< byte > read_page_data(const page_info &pi)
Read page data, perform validation checks.
Definition database.h:369
disk::header< T > m_header
Definition database.h:218
std::shared_ptr< subnode_leaf_block > read_subnode_leaf_block(const shared_db_ptr &parent, block_id bid)
Open a subnode_leaf_block in the specified context.
Definition database.h:137
friend shared_db_ptr open_database(const std::wstring &filename)
Open a db_context for the given file.
std::shared_ptr< nbt_leaf_page > read_nbt_leaf_page(const page_info &pi)
Open a NBT leaf page.
Definition database.h:460
friend std::shared_ptr< large_pst > open_large_pst(std::shared_ptr< file > file)
Try to open the given file as a Unicode store with custom file instance.
std::shared_ptr< file > m_file
Definition database.h:217
node lookup_node(node_id nid)
Open a node.
Definition database.h:107
std::shared_ptr< extended_block > read_extended_block(const shared_db_ptr &parent, block_id bid)
Open an extended_block in the specified context.
Definition database.h:131
friend shared_db_ptr open_database(std::shared_ptr< file > file)
Open a db_context for the given file instance.
std::shared_ptr< nbt_page > m_nbt_root
Definition database.h:220
std::shared_ptr< block > read_block(const shared_db_ptr &parent, block_id bid)
Open a block in the specified context.
Definition database.h:127
std::shared_ptr< nbt_nonleaf_page > read_nbt_nonleaf_page(const page_info &pi)
Open a NBT nonleaf page.
Definition database.h:540
std::shared_ptr< bbt_nonleaf_page > read_bbt_nonleaf_page(const page_info &pi)
Open a BBT nonleaf page.
Definition database.h:576
std::shared_ptr< bbt_page > read_bbt_root()
Get the root of the BBT of this context.
Definition database.h:406
std::shared_ptr< nbt_page > read_nbt_root()
Get the root of the NBT of this context.
Definition database.h:418
friend std::shared_ptr< large_pst > open_large_pst(const std::wstring &filename)
Try to open the given file as a Unicode store.
friend shared_db_ptr open_database(const shared_db_ptr &other_database)
Open a db_context by copying the in-memory header and file handle from another db_context.
block_info lookup_block_info(block_id bid)
Lookup information about a block.
Definition database.h:651
std::shared_ptr< subnode_block > read_subnode_block(const shared_db_ptr &parent, block_id bid)
Open a subnode_block in the specified context.
Definition database.h:135
std::shared_ptr< data_block > read_data_block(const shared_db_ptr &parent, block_id bid)
Open a data_block in the specified context.
Definition database.h:129
friend std::shared_ptr< small_pst > open_small_pst(const std::wstring &filename)
Try to open the given file as an ANSI store.
std::shared_ptr< bbt_page > m_bbt_root
Definition database.h:219
friend std::shared_ptr< small_pst > open_small_pst(std::shared_ptr< file > file)
Try to open the given file as an ANSI store with custom file instance.
std::shared_ptr< bbt_leaf_page > read_bbt_leaf_page(const page_info &pi)
Open a BBT leaf page.
Definition database.h:500
std::shared_ptr< external_block > read_external_block(const shared_db_ptr &parent, block_id bid)
Open a external_block in the specified context.
Definition database.h:133
void validate_header()
Validate the header of this file.
Database external interface.
A data block which refers to other data blocks, in order to extend the physical size limit (8k) to a ...
Definition node.h:629
Contains actual data.
Definition node.h:708
A generic class to read and write to a file.
Definition util.h:39
The database was not in the expected format.
Definition errors.h:57
An in memory representation of the "node" concept in a PST data file.
Definition node.h:320
An unexpected signature was encountered.
Definition errors.h:98
Contains the actual subnode information.
Definition node.h:841
Contains references to subnode_leaf_blocks.
Definition node.h:804
An unexpected block or block type was encountered.
Definition errors.h:75
An unexpected page or page type was encountered.
Definition errors.h:66
Database interface.
Disk data structure definitions.
The exceptions used by pstsdk.
const uint block_id_internal_bit
The internal bit indicates a block is an extended_block or a subnode_block.
Definition disk.h:973
const uint block_id_increment
The block id counter in the header is incremented by this amount for each block.
Definition disk.h:978
bool bid_is_internal(T bid)
Determines if a block is internal or not.
Definition disk.h:996
const size_t max_block_disk_size
The maximum individual block size.
Definition disk.h:933
bool bid_is_external(T bid)
Determines if a block is external or not.
Definition disk.h:987
@ block_type_extended
An extended block type.
Definition disk.h:941
@ database_format_unicode_min
Initial unicode version number.
Definition disk.h:71
@ crypt_method_permute
The permute method is used in this file.
Definition disk.h:99
@ crypt_method_cyclic
The cyclic method is used in this file.
Definition disk.h:100
const size_t page_size
Size of all pages in the file in bytes, including the page trailer.
Definition disk.h:525
const size_t first_amap_page_location
The location of the first AMap page in the file.
Definition disk.h:616
@ page_type_nbt
A NBT (Nodes BTree) page.
Definition disk.h:535
@ page_type_bbt
A BBT (Blocks BTree) page.
Definition disk.h:534
void permute(void *pdata, ulong cb, bool encrypt)
Modifies the data block in place, according to the permute method.
Definition disk.h:1645
void cyclic(void *pdata, ulong cb, ulong key)
Modifies the data block in place, according to the cyclic method.
Definition disk.h:1658
shared_db_ptr open_database(const std::wstring &filename)
Open a db_context for the given file.
Definition database.h:260
std::shared_ptr< small_pst > open_small_pst(const std::wstring &filename)
Try to open the given file as an ANSI store.
Definition database.h:276
std::shared_ptr< large_pst > open_large_pst(const std::wstring &filename)
Try to open the given file as a Unicode store.
Definition database.h:288
boost::uint32_t uint
Definition primitives.h:67
ulong node_id
Definition primitives.h:86
boost::uint32_t ulong
Definition primitives.h:68
ulonglong block_id
Definition primitives.h:87
boost::uint16_t ushort
Definition primitives.h:73
ushort compute_signature(T id, T address)
Calculate the signature of an item.
ulong compute_crc(const void *pdata, ulong cb)
Compute the CRC of a block of data.
Definition disk.h:1634
const uint block_id_attached_bit
The attached bit indicates a block is referenced in memory This is an implementation detail,...
Definition disk.h:968
Contains the definition of all in memory representations of disk structures.
Definition disk.h:19
database_impl< ulong > small_pst
Definition database.h:33
bt_leaf_page< block_id, block_info > bbt_leaf_page
std::shared_ptr< db_context > shared_db_ptr
database_impl< ulonglong > large_pst
Definition database.h:32
bt_leaf_page< node_id, node_info > nbt_leaf_page
Node and Block definitions.
Page definitions.
Primitive structures defined by MS-PST and MAPI.
An in memory, database format agnostic version of disk::bbt_leaf_entry.
The fundamental page structure which forms the basis of the two BTrees.
Definition disk.h:829
BTH Nonleaf node.
Definition disk.h:1405
External block definition.
Definition disk.h:1059
static const size_t max_size
Definition disk.h:1060
Generic page structure.
Definition disk.h:597
An in memory, database format agnostic version of disk::nbt_leaf_entry.
An in memory, database format agnostic version of disk::block_reference used specifically for the pag...
An in memory, database format agnostic version of disk::sub_leaf_entry.
General utility functions and classes.