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
36template<typename T>
37class db_writer;
39
47shared_db_ptr open_database(const std::wstring& filename);
55shared_db_ptr open_database(std::shared_ptr<file> file);
68std::shared_ptr<small_pst> open_small_pst(const std::wstring& filename);
76std::shared_ptr<small_pst> open_small_pst(std::shared_ptr<file> file);
84std::shared_ptr<large_pst> open_large_pst(const std::wstring& filename);
92std::shared_ptr<large_pst> open_large_pst(std::shared_ptr<file> file);
93
105template<typename T>
107{
108public:
109
111
113 { return node(this->shared_from_this(), lookup_node_info(nid)); }
117
119
120 std::shared_ptr<bbt_page> read_bbt_root();
121 std::shared_ptr<nbt_page> read_nbt_root();
122 std::shared_ptr<bbt_page> read_bbt_page(const page_info& pi);
123 std::shared_ptr<nbt_page> read_nbt_page(const page_info& pi);
124 std::shared_ptr<nbt_leaf_page> read_nbt_leaf_page(const page_info& pi);
125 std::shared_ptr<bbt_leaf_page> read_bbt_leaf_page(const page_info& pi);
126 std::shared_ptr<nbt_nonleaf_page> read_nbt_nonleaf_page(const page_info& pi);
127 std::shared_ptr<bbt_nonleaf_page> read_bbt_nonleaf_page(const page_info& pi);
129
131
132 std::shared_ptr<block> read_block(const shared_db_ptr& parent, block_id bid)
133 { return read_block(parent, lookup_block_info(bid)); }
134 std::shared_ptr<data_block> read_data_block(const shared_db_ptr& parent, block_id bid)
135 { return read_data_block(parent, lookup_block_info(bid)); }
136 std::shared_ptr<extended_block> read_extended_block(const shared_db_ptr& parent, block_id bid)
138 std::shared_ptr<external_block> read_external_block(const shared_db_ptr& parent, block_id bid)
140 std::shared_ptr<subnode_block> read_subnode_block(const shared_db_ptr& parent, block_id bid)
142 std::shared_ptr<subnode_leaf_block> read_subnode_leaf_block(const shared_db_ptr& parent, block_id bid)
144 std::shared_ptr<subnode_nonleaf_block> read_subnode_nonleaf_block(const shared_db_ptr& parent, block_id bid)
146
147 std::shared_ptr<block> read_block(const shared_db_ptr& parent, const block_info& bi);
148 std::shared_ptr<data_block> read_data_block(const shared_db_ptr& parent, const block_info& bi);
149 std::shared_ptr<extended_block> read_extended_block(const shared_db_ptr& parent, const block_info& bi);
150 std::shared_ptr<external_block> read_external_block(const shared_db_ptr& parent, const block_info& bi);
151 std::shared_ptr<subnode_block> read_subnode_block(const shared_db_ptr& parent, const block_info& bi);
152 std::shared_ptr<subnode_leaf_block> read_subnode_leaf_block(const shared_db_ptr& parent, const block_info& bi);
153 std::shared_ptr<subnode_nonleaf_block> read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi);
155
157 std::shared_ptr<external_block> create_external_block(const shared_db_ptr& parent, size_t size);
158 std::shared_ptr<extended_block> create_extended_block(const shared_db_ptr& parent, std::shared_ptr<external_block>& pblock);
159 std::shared_ptr<extended_block> create_extended_block(const shared_db_ptr& parent, std::shared_ptr<extended_block>& pblock);
160 std::shared_ptr<extended_block> create_extended_block(const shared_db_ptr& parent, size_t size);
161
162 block_id alloc_bid(bool is_internal);
164
165protected:
166 database_impl(); // = delete
171 database_impl(const std::wstring& filename);
172
177 database_impl(std::shared_ptr<file> file);
178
182
187
194 std::vector<byte> read_block_data(const block_info& bi);
202 std::vector<byte> read_page_data(const page_info& pi);
203
204 std::shared_ptr<nbt_leaf_page> read_nbt_leaf_page(const page_info& pi, disk::nbt_leaf_page<T>& the_page);
205 std::shared_ptr<bbt_leaf_page> read_bbt_leaf_page(const page_info& pi, disk::bbt_leaf_page<T>& the_page);
206
207 template<typename K, typename V>
208 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);
209
210 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);
211 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);
212
213 friend shared_db_ptr open_database(const std::wstring& filename);
214 friend shared_db_ptr open_database(std::shared_ptr<file> file);
216
217 friend std::shared_ptr<small_pst> open_small_pst(const std::wstring& filename);
218 friend std::shared_ptr<small_pst> open_small_pst(std::shared_ptr<file> file);
219 friend std::shared_ptr<large_pst> open_large_pst(const std::wstring& filename);
220 friend std::shared_ptr<large_pst> open_large_pst(std::shared_ptr<file> file);
221
223 template<typename> friend class db_writer;
224
225 file& get_file() { return *m_file; }
226 disk::header<T>& get_header() { return m_header; }
227
233 void reset_page_cache() { m_bbt_root.reset(); m_nbt_root.reset(); }
235
236 std::shared_ptr<file> m_file;
238 std::shared_ptr<bbt_page> m_bbt_root;
239 std::shared_ptr<nbt_page> m_nbt_root;
240};
241
243template<>
245{
246 // the behavior of open_database depends on this throw; this can not go under PSTSDK_VALIDATION_WEAK
247 if(m_header.wVer >= disk::database_format_unicode_min)
248 throw invalid_format();
249
250#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
252
253 if(crc != m_header.dwCRCPartial)
254 throw crc_fail("header dwCRCPartial failure", 0, 0, crc, m_header.dwCRCPartial);
255#endif
256}
257
258template<>
260{
261 // the behavior of open_database depends on this throw; this can not go under PSTSDK_VALIDATION_WEAK
262 if(m_header.wVer < disk::database_format_unicode_min)
263 throw invalid_format();
264
265#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
266 ulong crc_partial = disk::compute_crc(((byte*)&m_header) + disk::header_crc_locations<ulonglong>::partial_start, disk::header_crc_locations<ulonglong>::partial_length);
267 ulong crc_full = disk::compute_crc(((byte*)&m_header) + disk::header_crc_locations<ulonglong>::full_start, disk::header_crc_locations<ulonglong>::full_length);
268
269 if(crc_partial != m_header.dwCRCPartial)
270 throw crc_fail("header dwCRCPartial failure", 0, 0, crc_partial, m_header.dwCRCPartial);
271
272 if(crc_full != m_header.dwCRCFull)
273 throw crc_fail("header dwCRCFull failure", 0, 0, crc_full, m_header.dwCRCFull);
274#endif
275}
277} // end namespace
278
280{
281 try
282 {
284 return db;
285 }
286 catch(invalid_format&)
287 {
288 // well, that didn't work
289 }
290
292 return db;
293}
294
295inline std::shared_ptr<pstsdk::small_pst> pstsdk::open_small_pst(const std::wstring& filename)
296{
297 std::shared_ptr<small_pst> db(new small_pst(filename));
298 return db;
299}
300
301inline std::shared_ptr<pstsdk::small_pst> pstsdk::open_small_pst(std::shared_ptr<file> custom_file)
302{
303 std::shared_ptr<small_pst> db(new small_pst(custom_file));
304 return db;
305}
306
307inline std::shared_ptr<pstsdk::large_pst> pstsdk::open_large_pst(const std::wstring& filename)
308{
309 std::shared_ptr<large_pst> db(new large_pst(filename));
310 return db;
311}
312
313inline std::shared_ptr<pstsdk::large_pst> pstsdk::open_large_pst(std::shared_ptr<file> custom_file)
314{
315 std::shared_ptr<large_pst> db(new large_pst(custom_file));
316 return db;
317}
318
320{
321 std::vector<byte> version_buf(2);
322 custom_file->read(version_buf, 10);
323 ushort wver;
324 memcpy(&wver, version_buf.data(), sizeof(ushort));
325
327 if (wver >= disk::database_format_unicode_min) {
329 } else {
331 }
332
333 if (!db) throw invalid_format();
334
335 return db;
336}
337
339{
340 auto small_pst_db = dynamic_cast<small_pst *>(other_database.get());
341 if (small_pst_db) return std::shared_ptr<small_pst>(new small_pst(small_pst_db));
342
343 auto large_pst_db = dynamic_cast<large_pst *>(other_database.get());
344 if (large_pst_db) return std::shared_ptr<large_pst>(new large_pst(large_pst_db));
345
346 return nullptr;
347}
348
349template<typename T>
350inline std::vector<pstsdk::byte> pstsdk::database_impl<T>::read_block_data(const block_info& bi)
351{
352 size_t aligned_size = disk::align_disk<T>(bi.size);
353
354#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
356 throw unexpected_block("nonsensical block size");
357
358 if(bi.address + aligned_size > m_header.root_info.ibFileEof)
359 throw unexpected_block("nonsensical block location; past eof");
360#endif
361
362 std::vector<byte> buffer(aligned_size);
364
365 m_file->read(buffer, bi.address);
366
367#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
368 if(bt->bid != bi.id)
369 throw unexpected_block("wrong block id");
370
371 if(bt->cb != bi.size)
372 throw unexpected_block("wrong block size");
373
374 if(bt->signature != disk::compute_signature(bi.id, bi.address))
375 throw sig_mismatch("block sig mismatch", bi.address, bi.id, disk::compute_signature(bi.id, bi.address), bt->signature);
376#endif
377
378#ifdef PSTSDK_VALIDATION_LEVEL_FULL
379 ulong crc = disk::compute_crc(&buffer[0], bi.size);
380 if(crc != bt->crc)
381 throw crc_fail("block crc failure", bi.address, bi.id, crc, bt->crc);
382#endif
383
384 return buffer;
385}
386
387template<typename T>
389{
390#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
391 if(pi.address + disk::page_size > m_header.root_info.ibFileEof)
392 throw unexpected_page("nonsensical page location; past eof");
393
394 if(((pi.address - disk::first_amap_page_location) % disk::page_size) != 0)
395 throw unexpected_page("nonsensical page location; not sector aligned");
396#endif
397
398 std::vector<byte> buffer(disk::page_size);
400
401 m_file->read(buffer, pi.address);
402
403#ifdef PSTSDK_VALIDATION_LEVEL_FULL
405 if(crc != ppage->trailer.crc)
406 throw crc_fail("page crc failure", pi.address, pi.id, crc, ppage->trailer.crc);
407#endif
408
409#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
410 if(ppage->trailer.bid != pi.id)
411 throw unexpected_page("wrong page id");
412
413 if(ppage->trailer.page_type != ppage->trailer.page_type_repeat)
414 throw database_corrupt("ptype != ptype repeat?");
415
416 if(ppage->trailer.signature != disk::compute_signature(pi.id, pi.address))
417 throw sig_mismatch("page sig mismatch", pi.address, pi.id, disk::compute_signature(pi.id, pi.address), ppage->trailer.signature);
418#endif
419
420 return buffer;
421}
422
423
424template<typename T>
425inline std::shared_ptr<pstsdk::bbt_page> pstsdk::database_impl<T>::read_bbt_root()
426{
427 if(!m_bbt_root)
428 {
429 page_info pi = { m_header.root_info.brefBBT.bid, m_header.root_info.brefBBT.ib };
430 m_bbt_root = read_bbt_page(pi);
431 }
432
433 return m_bbt_root;
434}
435
436template<typename T>
437inline std::shared_ptr<pstsdk::nbt_page> pstsdk::database_impl<T>::read_nbt_root()
438{
439 if(!m_nbt_root)
440 {
441 page_info pi = { m_header.root_info.brefNBT.bid, m_header.root_info.brefNBT.ib };
442 m_nbt_root = read_nbt_page(pi);
443 }
444
445 return m_nbt_root;
446}
447
448template<typename T>
450: m_file(std::make_unique<file>(filename))
451{
452 std::vector<byte> buffer(sizeof(m_header));
453 m_file->read(buffer, 0);
454 memcpy(&m_header, &buffer[0], sizeof(m_header));
455
457}
458
459template<typename T>
461: m_file(file)
462{
463 std::vector<byte> buffer(sizeof(m_header));
464 m_file->read(buffer, 0);
465 memcpy(&m_header, &buffer[0], sizeof(m_header));
466
468}
469
470template<typename T>
472: m_file(other_database->m_file)
473{
474 // We assume that the header was already validated, so just copy it
475 memcpy(&m_header, &other_database->m_header, sizeof(m_header));
476}
477
478template<typename T>
479inline std::shared_ptr<pstsdk::nbt_leaf_page> pstsdk::database_impl<T>::read_nbt_leaf_page(const page_info& pi)
480{
481 std::vector<byte> buffer = read_page_data(pi);
483
484 if(ppage->trailer.page_type == disk::page_type_nbt)
485 {
487
488 if(leaf_page->level == 0)
489 return read_nbt_leaf_page(pi, *leaf_page);
490 }
491
492 throw unexpected_page("page_type != page_type_nbt");
493}
494
495template<typename T>
496inline 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)
497{
499 std::vector<std::pair<node_id, node_info> > nodes;
500
501 for(int i = 0; i < the_page.num_entries; ++i)
502 {
503 ni.id = static_cast<node_id>(the_page.entries[i].nid);
504 ni.data_bid = the_page.entries[i].data;
505 ni.sub_bid = the_page.entries[i].sub;
506 ni.parent_id = the_page.entries[i].parent_nid;
507
508 nodes.push_back(std::make_pair(ni.id, ni));
509 }
510
511#ifndef BOOST_NO_RVALUE_REFERENCES
512 return std::shared_ptr<nbt_leaf_page>(new nbt_leaf_page(shared_from_this(), pi, std::move(nodes)));
513#else
514 return std::shared_ptr<nbt_leaf_page>(new nbt_leaf_page(shared_from_this(), pi, nodes));
515#endif
516}
517
518template<typename T>
519inline std::shared_ptr<pstsdk::bbt_leaf_page> pstsdk::database_impl<T>::read_bbt_leaf_page(const page_info& pi)
520{
521 std::vector<byte> buffer = read_page_data(pi);
523
524 if(ppage->trailer.page_type == disk::page_type_bbt)
525 {
527
528 if(leaf_page->level == 0)
529 return read_bbt_leaf_page(pi, *leaf_page);
530 }
531
532 throw unexpected_page("page_type != page_type_bbt");
533}
534
535template<typename T>
536inline 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)
537{
539 std::vector<std::pair<block_id, block_info> > blocks;
540
541 for(int i = 0; i < the_page.num_entries; ++i)
542 {
543 bi.id = the_page.entries[i].ref.bid;
544 bi.address = the_page.entries[i].ref.ib;
545 bi.size = the_page.entries[i].size;
546 bi.ref_count = the_page.entries[i].ref_count;
547
548 blocks.push_back(std::make_pair(bi.id, bi));
549 }
550
551#ifndef BOOST_NO_RVALUE_REFERENCES
552 return std::shared_ptr<bbt_leaf_page>(new bbt_leaf_page(shared_from_this(), pi, std::move(blocks)));
553#else
554 return std::shared_ptr<bbt_leaf_page>(new bbt_leaf_page(shared_from_this(), pi, blocks));
555#endif
556}
557
558template<typename T>
559inline std::shared_ptr<pstsdk::nbt_nonleaf_page> pstsdk::database_impl<T>::read_nbt_nonleaf_page(const page_info& pi)
560{
561 std::vector<byte> buffer = read_page_data(pi);
563
564 if(ppage->trailer.page_type == disk::page_type_nbt)
565 {
567
568 if(nonleaf_page->level > 0)
570 }
571
572 throw unexpected_page("page_type != page_type_nbt");
573}
574
575template<typename T>
576template<typename K, typename V>
577inline 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)
578{
579 std::vector<std::pair<K, page_info> > nodes;
580
581 for(int i = 0; i < the_page.num_entries; ++i)
582 {
583 page_info subpi = { the_page.entries[i].ref.bid, the_page.entries[i].ref.ib };
584 nodes.push_back(std::make_pair(static_cast<K>(the_page.entries[i].key), subpi));
585 }
586
587#ifndef BOOST_NO_RVALUE_REFERENCES
588 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)));
589#else
590 return std::shared_ptr<bt_nonleaf_page<K,V> >(new bt_nonleaf_page<K,V>(shared_from_this(), pi, the_page.level, nodes));
591#endif
592}
593
594template<typename T>
595inline std::shared_ptr<pstsdk::bbt_nonleaf_page> pstsdk::database_impl<T>::read_bbt_nonleaf_page(const page_info& pi)
596{
597 std::vector<byte> buffer = read_page_data(pi);
599
600 if(ppage->trailer.page_type == disk::page_type_bbt)
601 {
603
604 if(nonleaf_page->level > 0)
606 }
607
608 throw unexpected_page("page_type != page_type_bbt");
609}
610
611template<typename T>
612inline std::shared_ptr<pstsdk::bbt_page> pstsdk::database_impl<T>::read_bbt_page(const page_info& pi)
613{
614 std::vector<byte> buffer = read_page_data(pi);
616
617 if(ppage->trailer.page_type == disk::page_type_bbt)
618 {
620 if(leaf->level == 0)
621 {
622 // it really is a leaf!
623 return read_bbt_leaf_page(pi, *leaf);
624 }
625 else
626 {
629 }
630 }
631 else
632 {
633 throw unexpected_page("page_type != page_type_bbt");
634 }
635}
636
637template<typename T>
638inline std::shared_ptr<pstsdk::nbt_page> pstsdk::database_impl<T>::read_nbt_page(const page_info& pi)
639{
640 std::vector<byte> buffer = read_page_data(pi);
642
643 if(ppage->trailer.page_type == disk::page_type_nbt)
644 {
646 if(leaf->level == 0)
647 {
648 // it really is a leaf!
649 return read_nbt_leaf_page(pi, *leaf);
650 }
651 else
652 {
655 }
656 }
657 else
658 {
659 throw unexpected_page("page_type != page_type_nbt");
660 }
661}
662
663template<typename T>
665{
666 return read_nbt_root()->lookup(nid);
667}
668
669template<typename T>
671{
672 if(bid == 0)
673 {
675 bi.id = bi.address = bi.size = bi.ref_count = 0;
676 return bi;
677 }
678 else
679 {
680 return read_bbt_root()->lookup(bid & (~(block_id(disk::block_id_attached_bit))));
681 }
682}
683
684template<typename T>
685inline std::shared_ptr<pstsdk::block> pstsdk::database_impl<T>::read_block(const shared_db_ptr& parent, const block_info& bi)
686{
687 std::shared_ptr<block> pblock;
688
689 try
690 {
691 pblock = read_data_block(parent, bi);
692 }
693 catch(unexpected_block&)
694 {
695 pblock = read_subnode_block(parent, bi);
696 }
697
698 return pblock;
699}
700
701template<typename T>
702inline std::shared_ptr<pstsdk::data_block> pstsdk::database_impl<T>::read_data_block(const shared_db_ptr& parent, const block_info& bi)
703{
705 return read_external_block(parent, bi);
706
707 std::vector<byte> buffer(sizeof(disk::extended_block<T>));
709 m_file->read(buffer, bi.address);
710
711 // the behavior of read_block depends on this throw; this can not go under PSTSDK_VALIDATION_WEAK
712 if(peblock->block_type != disk::block_type_extended)
713 throw unexpected_block("extended block expected");
714
715 return read_extended_block(parent, bi);
716}
717
718template<typename T>
719inline std::shared_ptr<pstsdk::extended_block> pstsdk::database_impl<T>::read_extended_block(const shared_db_ptr& parent, const block_info& bi)
720{
722 throw unexpected_block("internal bid expected");
723
724 std::vector<byte> buffer = read_block_data(bi);
726 std::vector<block_id> child_blocks;
727
728 for(int i = 0; i < peblock->count; ++i)
729 child_blocks.push_back(peblock->bid[i]);
730
731#ifdef __GNUC__
732 // GCC gave link errors on extended_block<T> and external_block<T> max_size
733 // with the below alernative
734 uint sub_size = 0;
735 if(peblock->level == 1)
737 else
738 sub_size = disk::extended_block<T>::max_size;
739#else
740 uint sub_size = (peblock->level == 1 ? disk::external_block<T>::max_size : disk::extended_block<T>::max_size);
741#endif
742 uint sub_page_count = peblock->level == 1 ? 1 : disk::extended_block<T>::max_count;
743
744#ifndef BOOST_NO_RVALUE_REFERENCES
745 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)));
746#else
747 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));
748#endif
749}
750
752template<typename T>
753inline std::shared_ptr<pstsdk::external_block> pstsdk::database_impl<T>::create_external_block(const shared_db_ptr& parent, size_t size)
754{
755 return std::shared_ptr<external_block>(new external_block(parent, disk::external_block<T>::max_size, size));
756}
757
758template<typename T>
759inline 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)
760{
761 std::vector<std::shared_ptr<data_block> > child_blocks;
762 child_blocks.push_back(pchild_block);
763
764#ifndef BOOST_NO_RVALUE_REFERENCES
765 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)));
766#else
767 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));
768#endif
769}
770
771template<typename T>
772inline 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)
773{
774 std::vector<std::shared_ptr<data_block> > child_blocks;
775 child_blocks.push_back(pchild_block);
776
777 assert(pchild_block->get_level() == 1);
778
779#ifndef BOOST_NO_RVALUE_REFERENCES
780 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)));
781#else
782 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));
783#endif
784}
785
786template<typename T>
787inline std::shared_ptr<pstsdk::extended_block> pstsdk::database_impl<T>::create_extended_block(const shared_db_ptr& parent, size_t size)
788{
789 ushort level = size > disk::extended_block<T>::max_size ? 2 : 1;
790#ifdef __GNUC__
791 // More strange link errors
792 size_t child_max_size;
793 if(level == 1)
794 child_max_size = disk::external_block<T>::max_size;
795 else
796 child_max_size = disk::extended_block<T>::max_size;
797#else
798 size_t child_max_size = level == 1 ? disk::external_block<T>::max_size : disk::extended_block<T>::max_size;
799#endif
800 ulong child_max_blocks = level == 1 ? 1 : disk::extended_block<T>::max_count;
801
802 return std::shared_ptr<extended_block>(new extended_block(parent, level, size, child_max_size, disk::extended_block<T>::max_count, child_max_blocks));
803}
805
806template<typename T>
807inline std::shared_ptr<pstsdk::external_block> pstsdk::database_impl<T>::read_external_block(const shared_db_ptr& parent, const block_info& bi)
808{
809 if(bi.id == 0)
810 {
811 return std::shared_ptr<external_block>(new external_block(parent, bi, disk::external_block<T>::max_size, std::vector<byte>()));
812 }
813
815 throw unexpected_block("External BID expected");
816
817 std::vector<byte> buffer = read_block_data(bi);
818
819 if(m_header.bCryptMethod == disk::crypt_method_permute)
820 {
821 disk::permute(&buffer[0], bi.size, false);
822 }
823 else if(m_header.bCryptMethod == disk::crypt_method_cyclic)
824 {
825 disk::cyclic(&buffer[0], bi.size, (ulong)bi.id);
826 }
827
828#ifndef BOOST_NO_RVALUE_REFERENCES
829 return std::shared_ptr<external_block>(new external_block(parent, bi, disk::external_block<T>::max_size, std::move(buffer)));
830#else
831 return std::shared_ptr<external_block>(new external_block(parent, bi, disk::external_block<T>::max_size, buffer));
832#endif
833}
834
835template<typename T>
836inline std::shared_ptr<pstsdk::subnode_block> pstsdk::database_impl<T>::read_subnode_block(const shared_db_ptr& parent, const block_info& bi)
837{
838 if(bi.id == 0)
839 {
840 return std::shared_ptr<subnode_block>(new subnode_leaf_block(parent, bi, std::vector<std::pair<node_id, subnode_info> >()));
841 }
842
843 std::vector<byte> buffer = read_block_data(bi);
845 std::shared_ptr<subnode_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 sub_block = read_subnode_nonleaf_block(parent, bi, *(disk::sub_nonleaf_block<T>*)&buffer[0]);
854 }
855
856 return sub_block;
857}
858
859template<typename T>
860inline std::shared_ptr<pstsdk::subnode_leaf_block> pstsdk::database_impl<T>::read_subnode_leaf_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_leaf_block> sub_block;
865
866 if(psub->level == 0)
867 {
868 sub_block = read_subnode_leaf_block(parent, bi, *psub);
869 }
870 else
871 {
872 throw unexpected_block("psub->level != 0");
873 }
874
875 return sub_block;
876}
877
878template<typename T>
879inline std::shared_ptr<pstsdk::subnode_nonleaf_block> pstsdk::database_impl<T>::read_subnode_nonleaf_block(const shared_db_ptr& parent, const block_info& bi)
880{
881 std::vector<byte> buffer = read_block_data(bi);
883 std::shared_ptr<subnode_nonleaf_block> sub_block;
884
885 if(psub->level != 0)
886 {
887 sub_block = read_subnode_nonleaf_block(parent, bi, *psub);
888 }
889 else
890 {
891 throw unexpected_block("psub->level == 1");
892 }
893
894 return sub_block;
895}
896
897template<typename T>
898inline 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)
899{
901 std::vector<std::pair<node_id, subnode_info> > subnodes;
902
903 for(int i = 0; i < sub_block.count; ++i)
904 {
905 ni.id = sub_block.entry[i].nid;
906 ni.data_bid = sub_block.entry[i].data;
907 ni.sub_bid = sub_block.entry[i].sub;
908
909 subnodes.push_back(std::make_pair(sub_block.entry[i].nid, ni));
910 }
911
912#ifndef BOOST_NO_RVALUE_REFERENCES
913 return std::shared_ptr<subnode_leaf_block>(new subnode_leaf_block(parent, bi, std::move(subnodes)));
914#else
915 return std::shared_ptr<subnode_leaf_block>(new subnode_leaf_block(parent, bi, subnodes));
916#endif
917}
918
919template<typename T>
920inline 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)
921{
922 std::vector<std::pair<node_id, block_id> > subnodes;
923
924 for(int i = 0; i < sub_block.count; ++i)
925 {
926 subnodes.push_back(std::make_pair(sub_block.entry[i].nid_key, sub_block.entry[i].sub_block_bid));
927 }
928
929#ifndef BOOST_NO_RVALUE_REFERENCES
930 return std::shared_ptr<subnode_nonleaf_block>(new subnode_nonleaf_block(parent, bi, std::move(subnodes)));
931#else
932 return std::shared_ptr<subnode_nonleaf_block>(new subnode_nonleaf_block(parent, bi, subnodes));
933#endif
934}
935
937template<typename T>
939{
940#ifdef __GNUC__
942 memcpy(&disk_id, m_header.bidNextB, sizeof(disk_id));
943
945
947 memcpy(m_header.bidNextB, &disk_id, sizeof(disk_id));
948#else
949 block_id next_bid = m_header.bidNextB;
950 m_header.bidNextB += disk::block_id_increment;
951#endif
952
953
954 if(is_internal)
956
957 return next_bid;
958}
960
961#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:96
The database is corrupt.
Definition errors.h:60
PST implementation.
Definition database.h:107
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:638
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:144
std::shared_ptr< bbt_page > read_bbt_page(const page_info &pi)
Open a BBT page.
Definition database.h:612
node_info lookup_node_info(node_id nid)
Lookup information about a node.
Definition database.h:664
std::vector< byte > read_block_data(const block_info &bi)
Read block data, perform validation checks.
Definition database.h:350
std::vector< byte > read_page_data(const page_info &pi)
Read page data, perform validation checks.
Definition database.h:388
disk::header< T > m_header
Definition database.h:237
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:142
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:479
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:236
node lookup_node(node_id nid)
Open a node.
Definition database.h:112
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:136
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:239
std::shared_ptr< block > read_block(const shared_db_ptr &parent, block_id bid)
Open a block in the specified context.
Definition database.h:132
std::shared_ptr< nbt_nonleaf_page > read_nbt_nonleaf_page(const page_info &pi)
Open a NBT nonleaf page.
Definition database.h:559
std::shared_ptr< bbt_nonleaf_page > read_bbt_nonleaf_page(const page_info &pi)
Open a BBT nonleaf page.
Definition database.h:595
std::shared_ptr< bbt_page > read_bbt_root()
Get the root of the BBT of this context.
Definition database.h:425
std::shared_ptr< nbt_page > read_nbt_root()
Get the root of the NBT of this context.
Definition database.h:437
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:670
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:140
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:134
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:238
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:519
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:138
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:45
The database was not in the expected format.
Definition errors.h:69
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:110
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:87
An unexpected page or page type was encountered.
Definition errors.h:78
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:995
const uint block_id_increment
The block id counter in the header is incremented by this amount for each block.
Definition disk.h:1000
bool bid_is_internal(T bid)
Determines if a block is internal or not.
Definition disk.h:1018
const size_t max_block_disk_size
The maximum individual block size.
Definition disk.h:955
bool bid_is_external(T bid)
Determines if a block is external or not.
Definition disk.h:1009
@ block_type_extended
An extended block type.
Definition disk.h:963
@ 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:539
const size_t first_amap_page_location
The location of the first AMap page in the file.
Definition disk.h:630
@ page_type_nbt
A NBT (Nodes BTree) page.
Definition disk.h:549
@ page_type_bbt
A BBT (Blocks BTree) page.
Definition disk.h:548
void permute(void *pdata, ulong cb, bool encrypt)
Modifies the data block in place, according to the permute method.
Definition disk.h:1667
void cyclic(void *pdata, ulong cb, ulong key)
Modifies the data block in place, according to the cyclic method.
Definition disk.h:1680
shared_db_ptr open_database(const std::wstring &filename)
Open a db_context for the given file.
Definition database.h:279
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:295
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:307
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:1656
const uint block_id_attached_bit
The attached bit indicates a block is referenced in memory This is an implementation detail,...
Definition disk.h:990
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:851
BTH Nonleaf node.
Definition disk.h:1427
External block definition.
Definition disk.h:1081
static const size_t max_size
Definition disk.h:1082
Generic page structure.
Definition disk.h:611
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.