PST File Format SDK v0.4
Loading...
Searching...
No Matches
node.h
Go to the documentation of this file.
1
8
9#ifndef PSTSDK_NDB_NODE_H
10#define PSTSDK_NDB_NODE_H
11
12#include <vector>
13#include <algorithm>
14#include <memory>
15#include <cassert>
16#include <boost/iterator/transform_iterator.hpp>
17#include <boost/iostreams/concepts.hpp>
18#ifdef _MSC_VER
19#pragma warning(push)
20#pragma warning(disable:4244)
21#endif
22#include <boost/iostreams/stream.hpp>
23#ifdef _MSC_VER
24#pragma warning(pop)
25#endif
26
27#include "pstsdk/util/util.h"
28#include "pstsdk/util/btree.h"
29
31
32#ifdef _MSC_VER
33#pragma warning(push)
34#pragma warning(disable:4250)
35#endif
36
37namespace pstsdk
38{
39
42
62class node_impl : public std::enable_shared_from_this<node_impl>
63{
64public:
71 : m_id(info.id), m_original_data_id(info.data_bid), m_original_sub_id(info.sub_bid), m_original_parent_id(info.parent_id), m_parent_id(info.parent_id), m_db(db) { }
72
78 node_impl(const std::shared_ptr<node_impl>& container_node, const subnode_info& info)
79 : m_id(info.id), m_original_data_id(info.data_bid), m_original_sub_id(info.sub_bid), m_original_parent_id(0), m_parent_id(0), m_pcontainer_node(container_node), m_db(container_node->m_db) { }
80
90 { m_pdata = other.m_pdata; m_psub = other.m_psub; return *this; }
91
94 node_id get_id() const { return m_id; }
97 block_id get_data_id() const;
100 block_id get_sub_id() const;
101
108 node_id get_parent_id() const { return m_parent_id; }
109
112 bool is_subnode() { return m_pcontainer_node != nullptr; }
113
116 std::shared_ptr<data_block> get_data_block() const
117 { ensure_data_block(); return m_pdata; }
120 std::shared_ptr<subnode_block> get_subnode_block() const
121 { ensure_sub_block(); return m_psub; }
122
130 size_t read(std::vector<byte>& buffer, ulong offset) const;
131
138 template<typename T> T read(ulong offset) const;
139
150 size_t read(std::vector<byte>& buffer, uint page_num, ulong offset) const;
151
158 template<typename T> T read(uint page_num, ulong offset) const;
159
165 size_t read_raw(byte* pdest_buffer, size_t size, ulong offset) const;
166
168 size_t write(const std::vector<byte>& buffer, ulong offset);
169 template<typename T> void write(const T& obj, ulong offset);
170 size_t write(const std::vector<byte>& buffer, uint page_num, ulong offset);
171 template<typename T> void write(const T& obj, uint page_num, ulong offset);
172 size_t write_raw(const byte* pdest_buffer, size_t size, ulong offset);
174
177 size_t size() const;
179 size_t resize(size_t size);
181
186 size_t get_page_size(uint page_num) const;
187
191 uint get_page_count() const;
192
193 // iterate over subnodes
200
205 node lookup(node_id id) const;
206
207private:
210 data_block* ensure_data_block() const;
213 subnode_block* ensure_sub_block() const;
214
215 const node_id m_id;
216 block_id m_original_data_id;
217 block_id m_original_sub_id;
218 node_id m_original_parent_id;
219
220 mutable std::shared_ptr<data_block> m_pdata;
221 mutable std::shared_ptr<subnode_block> m_psub;
222 node_id m_parent_id;
223
224 std::shared_ptr<node_impl> m_pcontainer_node;
225
226 shared_db_ptr m_db;
227};
228
238{
239public:
242 subnode_transform_info(const std::shared_ptr<node_impl>& parent)
243 : m_parent(parent) { }
244
248 node operator()(const subnode_info& info) const;
249
250private:
251 std::shared_ptr<node_impl> m_parent;
252};
253
260class node_stream_device : public boost::iostreams::device<boost::iostreams::seekable>
261{
262public:
264 node_stream_device() : m_pos(0) { }
265
270 std::streamsize read(char* pbuffer, std::streamsize n);
271
273 std::streamsize write(const char* pbuffer, std::streamsize n);
275
280 std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way);
281
282private:
283 friend class node;
285 node_stream_device(std::shared_ptr<node_impl>& _node) : m_pos(0), m_pnode(_node) { }
286
287 std::streamsize m_pos;
288 std::shared_ptr<node_impl> m_pnode;
289};
290
294typedef boost::iostreams::stream<node_stream_device> node_stream;
295
319class node
320{
321public:
324 typedef boost::transform_iterator<subnode_transform_info, const_subnodeinfo_iterator> subnode_iterator;
325
328 : m_pimpl(new node_impl(db, info)) { }
329
336 : m_pimpl(new node_impl(container_node.m_pimpl, info)) { }
338 node(const std::shared_ptr<node_impl>& container_node, const subnode_info& info)
339 : m_pimpl(new node_impl(container_node, info)) { }
340
346 : m_pimpl(new node_impl(*other.m_pimpl)) { }
347
354 : m_pimpl(other.m_pimpl) { }
355
356#ifndef BOOST_NO_RVALUE_REFERENCES
360 : m_pimpl(std::move(other.m_pimpl)) { }
361#endif
362
365 { *m_pimpl = *(other.m_pimpl); return *this; }
366
368 node_id get_id() const { return m_pimpl->get_id(); }
370 block_id get_data_id() const { return m_pimpl->get_data_id(); }
372 block_id get_sub_id() const { return m_pimpl->get_sub_id(); }
373
375 node_id get_parent_id() const { return m_pimpl->get_parent_id(); }
377 bool is_subnode() { return m_pimpl->is_subnode(); }
378
380 std::shared_ptr<data_block> get_data_block() const
381 { return m_pimpl->get_data_block(); }
383 std::shared_ptr<subnode_block> get_subnode_block() const
384 { return m_pimpl->get_subnode_block(); }
385
387 size_t read(std::vector<byte>& buffer, ulong offset) const
388 { return m_pimpl->read(buffer, offset); }
390 template<typename T> T read(ulong offset) const
391 { return m_pimpl->read<T>(offset); }
393 size_t read(std::vector<byte>& buffer, uint page_num, ulong offset) const
394 { return m_pimpl->read(buffer, page_num, offset); }
396 template<typename T> T read(uint page_num, ulong offset) const
397 { return m_pimpl->read<T>(page_num, offset); }
398
400 size_t write(std::vector<byte>& buffer, ulong offset)
401 { return m_pimpl->write(buffer, offset); }
402 template<typename T> void write(const T& obj, ulong offset)
403 { return m_pimpl->write<T>(obj, offset); }
404 size_t write(std::vector<byte>& buffer, uint page_num, ulong offset)
405 { return m_pimpl->write(buffer, page_num, offset); }
406 template<typename T> void write(const T& obj, uint page_num, ulong offset)
407 { return m_pimpl->write<T>(obj, page_num, offset); }
408 size_t resize(size_t size)
409 { return m_pimpl->resize(size); }
411
423
425 size_t size() const { return m_pimpl->size(); }
428 { return m_pimpl->get_page_size(page_num); }
430 uint get_page_count() const { return m_pimpl->get_page_count(); }
431
432 // iterate over subnodes
435 { return m_pimpl->subnode_info_begin(); }
438 { return m_pimpl->subnode_info_end(); }
439
448 { return boost::make_transform_iterator(subnode_info_begin(), subnode_transform_info(m_pimpl)); }
449
458 { return boost::make_transform_iterator(subnode_info_end(), subnode_transform_info(m_pimpl)); }
459
462 { return m_pimpl->lookup(id); }
463
464private:
465 std::shared_ptr<node_impl> m_pimpl;
466};
467
470
491class block
492{
493public:
498 : m_modified(false), m_size(info.size), m_id(info.id), m_address(info.address), m_db(db) { }
499
501 block(const block& other)
504
505 virtual ~block() { }
506
509 virtual bool is_internal() const = 0;
510
513 size_t get_disk_size() const { return m_size; }
515 void set_disk_size(size_t new_size) { m_size = new_size; }
517
520 block_id get_id() const { return m_id; }
521
524 ulonglong get_address() const { return m_address; }
527
528 void touch();
530
531protected:
533 virtual void trim() { }
534
536 size_t m_size;
539
541};
542
550class data_block : public block
551{
552public:
557 data_block(const shared_db_ptr& db, const block_info& info, size_t total_size)
558 : block(db, info), m_total_size(total_size) { }
559 virtual ~data_block() { }
560
568 size_t read(std::vector<byte>& buffer, ulong offset) const;
569
576 template<typename T> T read(ulong offset) const;
577
583 virtual size_t read_raw(byte* pdest_buffer, size_t size, ulong offset) const = 0;
584
586 size_t write(const std::vector<byte>& buffer, ulong offset, std::shared_ptr<data_block>& presult);
587 template<typename T> void write(const T& buffer, ulong offset, std::shared_ptr<data_block>& presult);
588 virtual size_t write_raw(const byte* psrc_buffer, size_t size, ulong offset, std::shared_ptr<data_block>& presult) = 0;
590
594 virtual uint get_page_count() const = 0;
595
601 virtual std::shared_ptr<external_block> get_page(uint page_num) const = 0;
602
605 size_t get_total_size() const { return m_total_size; }
607 virtual size_t resize(size_t size, std::shared_ptr<data_block>& presult) = 0;
609
610protected:
612};
613
627 public data_block,
628 public std::enable_shared_from_this<extended_block>
629{
630public:
640#ifndef BOOST_NO_RVALUE_REFERENCES
641 extended_block(const shared_db_ptr& db, const block_info& info, ushort level, size_t total_size, size_t child_max_total_size, ulong page_max_count, ulong child_page_max_count, std::vector<block_id> bi)
642 : data_block(db, info, total_size), m_child_max_total_size(child_max_total_size), m_child_max_page_count(child_page_max_count), m_max_page_count(page_max_count), m_level(level), m_block_info(std::move(bi)), m_child_blocks(m_block_info.size()) { }
643#else
644 extended_block(const shared_db_ptr& db, const block_info& info, ushort level, size_t total_size, size_t child_max_total_size, ulong page_max_count, ulong child_page_max_count, const std::vector<block_id>& bi)
645 : data_block(db, info, total_size), m_child_max_total_size(child_max_total_size), m_child_max_page_count(child_page_max_count), m_max_page_count(page_max_count), m_level(level), m_block_info(bi), m_child_blocks(m_block_info.size()) { }
646#endif
647
649 // new block constructors
650#ifndef BOOST_NO_RVALUE_REFERENCES
651 extended_block(const shared_db_ptr& db, ushort level, size_t total_size, size_t child_max_total_size, ulong page_max_count, ulong child_page_max_count, std::vector<std::shared_ptr<data_block> > child_blocks)
652 : data_block(db, block_info(), total_size), m_child_max_total_size(child_max_total_size), m_child_max_page_count(child_page_max_count), m_max_page_count(page_max_count), m_level(level), m_child_blocks(std::move(child_blocks))
653 { m_block_info.resize(m_child_blocks.size()); touch(); }
654#else
655 extended_block(const shared_db_ptr& db, ushort level, size_t total_size, size_t child_max_total_size, ulong page_max_count, ulong child_page_max_count, const std::vector<std::shared_ptr<data_block> >& child_blocks)
656 : data_block(db, block_info(), total_size), m_child_max_total_size(child_max_total_size), m_child_max_page_count(child_page_max_count), m_max_page_count(page_max_count), m_level(level), m_child_blocks(child_blocks)
657 { m_block_info.resize(m_child_blocks.size()); touch(); }
658#endif
659 extended_block(const shared_db_ptr& db, ushort level, size_t total_size, size_t child_max_total_size, ulong page_max_count, ulong child_page_max_count);
661
662 size_t read_raw(byte* pdest_buffer, size_t size, ulong offset) const;
664 size_t write_raw(const byte* psrc_buffer, size_t size, ulong offset, std::shared_ptr<data_block>& presult);
666
667 uint get_page_count() const;
668 std::shared_ptr<external_block> get_page(uint page_num) const;
669
671 size_t resize(size_t size, std::shared_ptr<data_block>& presult);
673
679 ushort get_level() const { return m_level; }
680 bool is_internal() const { return true; }
681
682private:
683 extended_block& operator=(const extended_block& other); // = delete
684 data_block* get_child_block(uint index) const;
685
686 const size_t m_child_max_total_size;
687 const ulong m_child_max_page_count;
688 const ulong m_max_page_count;
689
691 size_t get_max_size() const { return m_child_max_total_size * m_max_page_count; }
692
693 const ushort m_level;
694 std::vector<block_id> m_block_info;
695 mutable std::vector<std::shared_ptr<data_block> > m_child_blocks;
696};
697
706 public data_block,
707 public std::enable_shared_from_this<external_block>
708{
709public:
715#ifndef BOOST_NO_RVALUE_REFERENCES
716 external_block(const shared_db_ptr& db, const block_info& info, size_t max_size, std::vector<byte> buffer)
717 : data_block(db, info, info.size), m_max_size(max_size), m_buffer(std::move(buffer)) { }
718#else
719 external_block(const shared_db_ptr& db, const block_info& info, size_t max_size, const std::vector<byte>& buffer)
720 : data_block(db, info, info.size), m_max_size(max_size), m_buffer(buffer) { }
721#endif
722
724 // new block constructors
725 external_block(const shared_db_ptr& db, size_t max_size, size_t current_size)
726 : data_block(db, block_info(), current_size), m_max_size(max_size), m_buffer(current_size)
727 { touch(); }
729
730 size_t read_raw(byte* pdest_buffer, size_t size, ulong offset) const;
732 size_t write_raw(const byte* psrc_buffer, size_t size, ulong offset, std::shared_ptr<data_block>& presult);
734
735 uint get_page_count() const { return 1; }
736 std::shared_ptr<external_block> get_page(uint page_num) const;
737
739 size_t resize(size_t size, std::shared_ptr<data_block>& presult);
741
742 bool is_internal() const { return false; }
743
744private:
745 external_block& operator=(const external_block& other); // = delete
746
747 const size_t m_max_size;
748 size_t get_max_size() const { return m_max_size; }
749
750 std::vector<byte> m_buffer;
751};
752
753
765 public block,
766 public virtual btree_node<node_id, subnode_info>
767{
768public:
774 : block(db, info), m_level(level) { }
775
776 virtual ~subnode_block() { }
777
780 ushort get_level() const { return m_level; }
781
782 bool is_internal() const { return true; }
783
784protected:
786};
787
801 public subnode_block,
802 public btree_node_nonleaf<node_id, subnode_info>,
803 public std::enable_shared_from_this<subnode_nonleaf_block>
804{
805public:
810#ifndef BOOST_NO_RVALUE_REFERENCES
811 subnode_nonleaf_block(const shared_db_ptr& db, const block_info& info, std::vector<std::pair<node_id, block_id> > subblocks)
812 : subnode_block(db, info, 1), m_subnode_info(std::move(subblocks)), m_child_blocks(m_subnode_info.size()) { }
813#else
814 subnode_nonleaf_block(const shared_db_ptr& db, const block_info& info, const std::vector<std::pair<node_id, block_id> >& subblocks)
815 : subnode_block(db, info, 1), m_subnode_info(subblocks), m_child_blocks(m_subnode_info.size()) { }
816#endif
817
818 // btree_node_nonleaf implementation
819 const node_id& get_key(uint pos) const
820 { return m_subnode_info[pos].first; }
822 const subnode_block* get_child(uint pos) const;
823 uint num_values() const { return m_subnode_info.size(); }
824
825private:
826 std::vector<std::pair<node_id, block_id> > m_subnode_info;
827 mutable std::vector<std::shared_ptr<subnode_block> > m_child_blocks;
828};
829
838 public subnode_block,
839 public btree_node_leaf<node_id, subnode_info>,
840 public std::enable_shared_from_this<subnode_leaf_block>
841{
842public:
847#ifndef BOOST_NO_RVALUE_REFERENCES
848 subnode_leaf_block(const shared_db_ptr& db, const block_info& info, std::vector<std::pair<node_id, subnode_info> > subnodes)
849 : subnode_block(db, info, 0), m_subnodes(std::move(subnodes)) { }
850#else
851 subnode_leaf_block(const shared_db_ptr& db, const block_info& info, const std::vector<std::pair<node_id, subnode_info> >& subnodes)
852 : subnode_block(db, info, 0), m_subnodes(subnodes) { }
853#endif
854
855 // btree_node_leaf implementation
857 { return m_subnodes[pos].second; }
858 const node_id& get_key(uint pos) const
859 { return m_subnodes[pos].first; }
861 { return m_subnodes.size(); }
862
863private:
864 std::vector<std::pair<node_id, subnode_info> > m_subnodes;
865};
866
867} // end pstsdk namespace
868
870{
871 return node(m_parent, info);
872}
873
875{
876 if(m_pdata)
877 return m_pdata->get_id();
878
879 return m_original_data_id;
880}
881
883{
884 if(m_psub)
885 return m_psub->get_id();
886
887 return m_original_sub_id;
888}
889
890inline size_t pstsdk::node_impl::size() const
891{
892 return ensure_data_block()->get_total_size();
893}
894
896{
897 return ensure_data_block()->get_page(page_num)->get_total_size();
898}
899
901{
902 return ensure_data_block()->get_page_count();
903}
904
905inline size_t pstsdk::node_impl::read(std::vector<byte>& buffer, ulong offset) const
906{
907 return ensure_data_block()->read(buffer, offset);
908}
909
910inline size_t pstsdk::node_impl::read_raw(byte* pdest_buffer, size_t size, ulong offset) const
911{
912 return ensure_data_block()->read_raw(pdest_buffer, size, offset);
913}
914
915template<typename T>
916inline T pstsdk::node_impl::read(ulong offset) const
917{
918 return ensure_data_block()->read<T>(offset);
919}
920
921inline size_t pstsdk::node_impl::read(std::vector<byte>& buffer, uint page_num, ulong offset) const
922{
923 return ensure_data_block()->get_page(page_num)->read(buffer, offset);
924}
925
926template<typename T>
928{
929 return ensure_data_block()->get_page(page_num)->read<T>(offset);
930}
931
933inline size_t pstsdk::node_impl::write(const std::vector<byte>& buffer, ulong offset)
934{
935 return ensure_data_block()->write(buffer, offset, m_pdata);
936}
937
938inline size_t pstsdk::node_impl::write_raw(const byte* pdest_buffer, size_t size, ulong offset)
939{
940 ensure_data_block();
941 return m_pdata->write_raw(pdest_buffer, size, offset, m_pdata);
942}
943
944template<typename T>
945inline void pstsdk::node_impl::write(const T& obj, ulong offset)
946{
947 return ensure_data_block()->write<T>(obj, offset, m_pdata);
948}
949
950inline size_t pstsdk::node_impl::write(const std::vector<byte>& buffer, uint page_num, ulong offset)
951{
952 return ensure_data_block()->write(buffer, page_num * get_page_size(0) + offset, m_pdata);
953}
954
955template<typename T>
956inline void pstsdk::node_impl::write(const T& obj, uint page_num, ulong offset)
957{
958 return ensure_data_block()->write<T>(obj, page_num * get_page_size(0) + offset, m_pdata);
959}
960
961inline size_t pstsdk::node_impl::resize(size_t size)
962{
963 return ensure_data_block()->resize(size, m_pdata);
964}
966
967inline pstsdk::data_block* pstsdk::node_impl::ensure_data_block() const
968{
969 if(!m_pdata)
970 m_pdata = m_db->read_data_block(m_original_data_id);
971
972 return m_pdata.get();
973}
974
975inline pstsdk::subnode_block* pstsdk::node_impl::ensure_sub_block() const
976{
977 if(!m_psub)
978 m_psub = m_db->read_subnode_block(m_original_sub_id);
979
980 return m_psub.get();
981}
982
984inline void pstsdk::block::touch()
985{
986 if(!m_modified)
987 {
988 m_modified = true;
989 m_address = 0;
990 m_size = 0;
991 m_id = get_db_ptr()->alloc_bid(is_internal());
992 }
993}
995
996inline std::streamsize pstsdk::node_stream_device::read(char* pbuffer, std::streamsize n)
997{
998 size_t read = m_pnode->read_raw(reinterpret_cast<byte*>(pbuffer), static_cast<size_t>(n), static_cast<size_t>(m_pos));
999 m_pos += read;
1000
1001 if(read)
1002 return read;
1003 else
1004 return -1;
1005}
1006
1008inline std::streamsize pstsdk::node_stream_device::write(const char* pbuffer, std::streamsize n)
1009{
1010 size_t written = m_pnode->write_raw(reinterpret_cast<const byte*>(pbuffer), static_cast<size_t>(n), static_cast<size_t>(m_pos));
1011 m_pos += written;
1012 return written;
1013}
1015
1016inline std::streampos pstsdk::node_stream_device::seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way)
1017{
1018#if defined(_MSC_VER) && (_MSC_VER < 1600)
1019#pragma warning(push)
1020#pragma warning(disable:4244)
1021#endif
1022 if(way == std::ios_base::beg)
1023 m_pos = off;
1024 else if(way == std::ios_base::end)
1025 m_pos = m_pnode->size() + off;
1026 else
1027 m_pos += off;
1028#if defined(_MSC_VER) && (_MSC_VER < 1600)
1029#pragma warning(pop)
1030#endif
1031
1032 if(m_pos < 0)
1033 m_pos = 0;
1034 else if(static_cast<size_t>(m_pos) > m_pnode->size())
1035 m_pos = m_pnode->size();
1036
1037 return m_pos;
1038}
1039
1041{
1042 if(m_child_blocks[pos] == NULL)
1043 {
1044 m_child_blocks[pos] = get_db_ptr()->read_subnode_block(m_subnode_info[pos].second);
1045 }
1046
1047 return m_child_blocks[pos].get();
1048}
1049
1051{
1052 if(m_child_blocks[pos] == NULL)
1053 {
1054 m_child_blocks[pos] = get_db_ptr()->read_subnode_block(m_subnode_info[pos].second);
1055 }
1056
1057 return m_child_blocks[pos].get();
1058}
1059
1060inline size_t pstsdk::data_block::read(std::vector<byte>& buffer, ulong offset) const
1061{
1062 size_t read_size = buffer.size();
1063
1064 if(read_size > 0)
1065 {
1066 if(offset >= get_total_size())
1067 throw std::out_of_range("offset >= size()");
1068
1069 read_size = read_raw(&buffer[0], read_size, offset);
1070 }
1071
1072 return read_size;
1073}
1074
1075template<typename T>
1076inline T pstsdk::data_block::read(ulong offset) const
1077{
1078 if(offset >= get_total_size())
1079 throw std::out_of_range("offset >= size()");
1080 if(sizeof(T) + offset > get_total_size())
1081 throw std::out_of_range("sizeof(T) + offset >= size()");
1082
1083 T t;
1084 read_raw(reinterpret_cast<byte*>(&t), sizeof(T), offset);
1085
1086 return t;
1087}
1088
1090inline size_t pstsdk::data_block::write(const std::vector<byte>& buffer, ulong offset, std::shared_ptr<data_block>& presult)
1091{
1092 size_t write_size = buffer.size();
1093
1094 if(write_size > 0)
1095 {
1096 if(offset >= get_total_size())
1097 throw std::out_of_range("offset >= size()");
1098
1099 write_size = write_raw(&buffer[0], write_size, offset, presult);
1100 }
1101
1102 return write_size;
1103}
1104
1105template<typename T>
1106void pstsdk::data_block::write(const T& buffer, ulong offset, std::shared_ptr<data_block>& presult)
1107{
1108 if(offset >= get_total_size())
1109 throw std::out_of_range("offset >= size()");
1110 if(sizeof(T) + offset > get_total_size())
1111 throw std::out_of_range("sizeof(T) + offset >= size()");
1112
1113 (void)write_raw(reinterpret_cast<const byte*>(&buffer), sizeof(T), offset, presult);
1114}
1116
1118{
1119 assert(m_child_max_total_size % m_child_max_page_count == 0);
1120 uint page_size = m_child_max_total_size / m_child_max_page_count;
1121 uint page_count = (get_total_size() / page_size) + ((get_total_size() % page_size) != 0 ? 1 : 0);
1122 assert(get_level() == 2 || page_count == m_block_info.size());
1123
1124 return page_count;
1125}
1126
1129: data_block(db, block_info(), total_size), m_child_max_total_size(child_max_total_size), m_child_max_page_count(child_page_max_count), m_max_page_count(page_max_count), m_level(level)
1130{
1131 int total_subblocks = total_size / m_child_max_total_size;
1132 if(total_size % m_child_max_total_size != 0)
1134
1135 m_child_blocks.resize(total_subblocks);
1136 m_block_info.resize(total_subblocks, 0);
1137
1138 touch();
1139}
1141
1142inline pstsdk::data_block* pstsdk::extended_block::get_child_block(uint index) const
1143{
1144 if(index >= m_child_blocks.size())
1145 throw std::out_of_range("index >= m_child_blocks.size()");
1146
1147 if(m_child_blocks[index] == NULL)
1148 {
1149 if(m_block_info[index] == 0)
1150 {
1151 if(get_level() == 1)
1152 m_child_blocks[index] = get_db_ptr()->create_external_block(m_child_max_total_size);
1153 else
1154 m_child_blocks[index] = get_db_ptr()->create_extended_block(m_child_max_total_size);
1155 }
1156 else
1157 m_child_blocks[index] = get_db_ptr()->read_data_block(m_block_info[index]);
1158 }
1159
1160 return m_child_blocks[index].get();
1161}
1162
1163inline std::shared_ptr<pstsdk::external_block> pstsdk::extended_block::get_page(uint page_num) const
1164{
1165 uint page = page_num / m_child_max_page_count;
1166 return get_child_block(page)->get_page(page_num % m_child_max_page_count);
1167}
1168
1169inline std::shared_ptr<pstsdk::external_block> pstsdk::external_block::get_page(uint index) const
1170{
1171 if(index != 0)
1172 throw std::out_of_range("index > 0");
1173
1174 return std::const_pointer_cast<external_block>(this->shared_from_this());
1175}
1176
1177inline size_t pstsdk::external_block::read_raw(byte* pdest_buffer, size_t size, ulong offset) const
1178{
1179 size_t read_size = size;
1180
1181 assert(offset <= get_total_size());
1182
1183 if(offset + size > get_total_size())
1184 read_size = get_total_size() - offset;
1185
1186 memcpy(pdest_buffer, &m_buffer[offset], read_size);
1187
1188 return read_size;
1189}
1190
1192inline size_t pstsdk::external_block::write_raw(const byte* psrc_buffer, size_t size, ulong offset, std::shared_ptr<data_block>& presult)
1193{
1194 std::shared_ptr<pstsdk::external_block> pblock = shared_from_this();
1195 if(pblock.use_count() > 2) // one for me, one for the caller
1196 {
1197 std::shared_ptr<pstsdk::external_block> pnewblock(new external_block(*this));
1198 return pnewblock->write_raw(psrc_buffer, size, offset, presult);
1199 }
1200 touch(); // mutate ourselves inplace
1201
1202 assert(offset <= get_total_size());
1203
1204 size_t write_size = size;
1205
1206 if(offset + size > get_total_size())
1207 write_size = get_total_size() - offset;
1208
1209 memcpy(&m_buffer[0]+offset, psrc_buffer, write_size);
1210
1211 // assign out param
1212#ifndef BOOST_NO_RVALUE_REFERENCES
1213 presult = std::move(pblock);
1214#else
1215 presult = pblock;
1216#endif
1217
1218 return write_size;
1219}
1221
1222inline size_t pstsdk::extended_block::read_raw(byte* pdest_buffer, size_t size, ulong offset) const
1223{
1224 assert(offset <= get_total_size());
1225
1226 if(offset + size > get_total_size())
1227 size = get_total_size() - offset;
1228
1229 byte* pend = pdest_buffer + size;
1230
1231 size_t total_bytes_read = 0;
1232
1233 while(pdest_buffer != pend)
1234 {
1235 // the child this read starts on
1236 uint child_pos = offset / m_child_max_total_size;
1237 // offset into the child block this read starts on
1238 ulong child_offset = offset % m_child_max_total_size;
1239
1240 // call into our child to read the data
1241 size_t bytes_read = get_child_block(child_pos)->read_raw(pdest_buffer, size, child_offset);
1242 assert(bytes_read <= size);
1243
1244 // adjust pointers accordingly
1246 offset += bytes_read;
1247 size -= bytes_read;
1249
1251 }
1252
1253 return total_bytes_read;
1254}
1255
1257inline size_t pstsdk::extended_block::write_raw(const byte* psrc_buffer, size_t size, ulong offset, std::shared_ptr<data_block>& presult)
1258{
1259 std::shared_ptr<extended_block> pblock = shared_from_this();
1260 if(pblock.use_count() > 2) // one for me, one for the caller
1261 {
1262 std::shared_ptr<extended_block> pnewblock(new extended_block(*this));
1263 return pnewblock->write_raw(psrc_buffer, size, offset, presult);
1264 }
1265 touch(); // mutate ourselves inplace
1266
1267 assert(offset <= get_total_size());
1268
1269 if(offset + size > get_total_size())
1270 size = get_total_size() - offset;
1271
1272 const byte* pend = psrc_buffer + size;
1273 size_t total_bytes_written = 0;
1274
1275 while(psrc_buffer != pend)
1276 {
1277 // the child this read starts on
1278 uint child_pos = offset / m_child_max_total_size;
1279 // offset into the child block this read starts on
1280 ulong child_offset = offset % m_child_max_total_size;
1281
1282 // call into our child to write the data
1283 size_t bytes_written = get_child_block(child_pos)->write_raw(psrc_buffer, size, child_offset, m_child_blocks[child_pos]);
1284 assert(bytes_written <= size);
1285
1286 // adjust pointers accordingly
1287 psrc_buffer += bytes_written;
1288 offset += bytes_written;
1289 size -= bytes_written;
1290 total_bytes_written += bytes_written;
1291
1292 assert(psrc_buffer <= pend);
1293 }
1294
1295 // assign out param
1296#ifndef BOOST_NO_RVALUE_REFERENCES
1297 presult = std::move(pblock);
1298#else
1299 presult = pblock;
1300#endif
1301
1302 return total_bytes_written;
1303}
1304
1305inline size_t pstsdk::external_block::resize(size_t size, std::shared_ptr<data_block>& presult)
1306{
1307 std::shared_ptr<external_block> pblock = shared_from_this();
1308 if(pblock.use_count() > 2) // one for me, one for the caller
1309 {
1310 std::shared_ptr<external_block> pnewblock(new external_block(*this));
1311 return pnewblock->resize(size, presult);
1312 }
1313 touch(); // mutate ourselves inplace
1314
1315 m_buffer.resize(size > m_max_size ? m_max_size : size);
1316 m_total_size = m_buffer.size();
1317
1318 if(size > get_max_size())
1319 {
1320 // we need to create an extended_block with us as the first entry
1321 std::shared_ptr<extended_block> pnewxblock = get_db_ptr()->create_extended_block(pblock);
1322 return pnewxblock->resize(size, presult);
1323 }
1324
1325 // assign out param
1326#ifndef BOOST_NO_RVALUE_REFERENCES
1327 presult = std::move(pblock);
1328#else
1329 presult = pblock;
1330#endif
1331
1332 return size;
1333}
1334
1335inline size_t pstsdk::extended_block::resize(size_t size, std::shared_ptr<data_block>& presult)
1336{
1337 // calculate the number of subblocks needed
1338 uint old_num_subblocks = m_block_info.size();
1339 uint num_subblocks = size / m_child_max_total_size;
1340
1341 if(size % m_child_max_total_size != 0)
1342 num_subblocks++;
1343
1344 if(num_subblocks > m_max_page_count)
1345 num_subblocks = m_max_page_count;
1346
1347 // defer to child if it's 1 (or less)
1348 assert(!m_child_blocks.empty());
1349 if(num_subblocks < 2)
1350 return get_child_block(0)->resize(size, presult);
1351
1352 std::shared_ptr<extended_block> pblock = shared_from_this();
1353 if(pblock.use_count() > 2) // one for me, one for the caller
1354 {
1355 std::shared_ptr<extended_block> pnewblock(new extended_block(*this));
1356 return pnewblock->resize(size, presult);
1357 }
1358 touch(); // mutate ourselves inplace
1359
1360 // set the total number of subblocks needed
1361 m_block_info.resize(num_subblocks, 0);
1362 m_child_blocks.resize(num_subblocks);
1363
1364 if(old_num_subblocks < num_subblocks)
1365 get_child_block(old_num_subblocks-1)->resize(m_child_max_total_size, m_child_blocks[old_num_subblocks-1]);
1366
1367 // size the last subblock appropriately
1368 size_t last_child_size = size - (num_subblocks-1) * m_child_max_total_size;
1369 get_child_block(num_subblocks-1)->resize(last_child_size, m_child_blocks[num_subblocks-1]);
1370
1371 if(size > get_max_size())
1372 {
1373 m_total_size = get_max_size();
1374
1375 if(get_level() == 2)
1376 throw can_not_resize("size > max_size");
1377
1378 // we need to create a level 2 extended_block with us as the first entry
1379 std::shared_ptr<extended_block> pnewxblock = get_db_ptr()->create_extended_block(pblock);
1380 return pnewxblock->resize(size, presult);
1381 }
1382
1383 // assign out param
1384 m_total_size = size;
1385#ifndef BOOST_NO_RVALUE_REFERENCES
1386 presult = std::move(pblock);
1387#else
1388 presult = pblock;
1389#endif
1390
1391 return size;
1392}
1394
1396{
1397 const subnode_block* pblock = ensure_sub_block();
1398 return pblock->begin();
1399}
1400
1402{
1403 const subnode_block* pblock = ensure_sub_block();
1404 return pblock->end();
1405}
1406
1408{
1409 return node(std::const_pointer_cast<node_impl>(shared_from_this()), ensure_sub_block()->lookup(id));
1410}
1411
1412#ifdef _MSC_VER
1413#pragma warning(pop)
1414#endif
1415
1416#endif
Generic BTree implementation.
The base class of the block class hierarchy.
Definition node.h:492
shared_db_ptr get_db_ptr() const
Definition node.h:532
bool m_modified
True if this block has been modified and needs to be saved.
Definition node.h:535
block(const shared_db_ptr &db, const block_info &info)
Basic block constructor.
Definition node.h:497
virtual bool is_internal() const =0
Returns the blocks internal/external state.
virtual ~block()
Definition node.h:505
ulonglong m_address
The address of this specific block on disk, 0 if unknown.
Definition node.h:538
block_id get_id() const
Get the block_id of this block.
Definition node.h:520
weak_db_ptr m_db
Definition node.h:540
virtual void trim()
Definition node.h:533
block_id m_id
The id of this block.
Definition node.h:537
size_t get_disk_size() const
Get the last known size of this block on disk.
Definition node.h:513
size_t m_size
The size of this specific block on disk at last save.
Definition node.h:536
ulonglong get_address() const
Get the address of this block on disk.
Definition node.h:524
Contains references to other bth_node allocations.
Definition heap.h:364
Represents a leaf node in a BTree structure.
Definition btree.h:132
Represents a non-leaf node in a BTree structure.
Definition btree.h:172
A BTree Node.
Definition btree.h:52
const_iterator end() const
Returns a STL style iterator positioned at the "end" entry.
Definition btree.h:93
const_iterator begin() const
Returns a STL style iterator positioned at the first entry.
Definition btree.h:85
A block which represents end user data.
Definition node.h:551
size_t m_total_size
the total or logical size (sum of all external child blocks)
Definition node.h:611
virtual std::shared_ptr< external_block > get_page(uint page_num) const =0
Get a specific page of this data_block.
virtual size_t read_raw(byte *pdest_buffer, size_t size, ulong offset) const =0
Read data from this block.
virtual ~data_block()
Definition node.h:559
size_t get_total_size() const
Get the total logical size of this block.
Definition node.h:605
size_t read(std::vector< byte > &buffer, ulong offset) const
Read data from this block.
Definition node.h:1060
virtual uint get_page_count() const =0
Get the number of physical pages in this data_block.
data_block(const shared_db_ptr &db, const block_info &info, size_t total_size)
Constructor for a data_block.
Definition node.h:557
A data block which refers to other data blocks, in order to extend the physical size limit (8k) to a ...
Definition node.h:629
extended_block(const shared_db_ptr &db, const block_info &info, ushort level, size_t total_size, size_t child_max_total_size, ulong page_max_count, ulong child_page_max_count, std::vector< block_id > bi)
Construct an extended_block from disk.
Definition node.h:641
uint get_page_count() const
Get the number of physical pages in this data_block.
Definition node.h:1117
ushort get_level() const
Get the "level" of this extended_block.
Definition node.h:679
std::shared_ptr< external_block > get_page(uint page_num) const
Get a specific page of this data_block.
Definition node.h:1163
size_t read_raw(byte *pdest_buffer, size_t size, ulong offset) const
Read data from this block.
Definition node.h:1222
bool is_internal() const
Returns the blocks internal/external state.
Definition node.h:680
Contains actual data.
Definition node.h:708
bool is_internal() const
Returns the blocks internal/external state.
Definition node.h:742
std::shared_ptr< external_block > get_page(uint page_num) const
Get a specific page of this data_block.
Definition node.h:1169
uint get_page_count() const
Get the number of physical pages in this data_block.
Definition node.h:735
size_t read_raw(byte *pdest_buffer, size_t size, ulong offset) const
Read data from this block.
Definition node.h:1177
external_block(const shared_db_ptr &db, const block_info &info, size_t max_size, std::vector< byte > buffer)
Construct an external_block from disk.
Definition node.h:716
The node implementation.
Definition node.h:63
size_t read(std::vector< byte > &buffer, ulong offset) const
Read data from this node.
Definition node.h:905
size_t get_page_size(uint page_num) const
Returns the size of a page in this node.
Definition node.h:895
block_id get_data_id() const
Get the block_id of the data block of this node.
Definition node.h:874
bool is_subnode()
Tells you if this is a subnode.
Definition node.h:112
node_id get_id() const
Get the id of this node.
Definition node.h:94
node_impl(const std::shared_ptr< node_impl > &container_node, const subnode_info &info)
Constructor for subnodes.
Definition node.h:78
size_t size() const
Returns the size of this node.
Definition node.h:890
node_impl & operator=(const node_impl &other)
Set one node equal to another.
Definition node.h:89
block_id get_sub_id() const
Get the block_id of the subnode block of this node.
Definition node.h:882
std::shared_ptr< subnode_block > get_subnode_block() const
Returns the subnode block associated with this node.
Definition node.h:120
node_id get_parent_id() const
Get the parent id.
Definition node.h:108
std::shared_ptr< data_block > get_data_block() const
Returns the data block associated with this node.
Definition node.h:116
node_impl(const shared_db_ptr &db, const node_info &info)
Constructor for top level nodes.
Definition node.h:70
uint get_page_count() const
Returns the number of pages in this node.
Definition node.h:900
node lookup(node_id id) const
Lookup a subnode by node id.
Definition node.h:1407
const_subnodeinfo_iterator subnode_info_begin() const
Returns an iterator positioned at first subnodeinfo.
Definition node.h:1395
const_subnodeinfo_iterator subnode_info_end() const
Returns an iterator positioned past the last subnodeinfo.
Definition node.h:1401
size_t read_raw(byte *pdest_buffer, size_t size, ulong offset) const
Read data from this node.
Definition node.h:910
Defines a stream device for a node for use by boost iostream.
Definition node.h:261
node_stream_device()
Default construct the node stream device.
Definition node.h:264
std::streamsize read(char *pbuffer, std::streamsize n)
Read data from this node into the buffer at the current position.
Definition node.h:996
std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way)
Move the current position in the stream.
Definition node.h:1016
An in memory representation of the "node" concept in a PST data file.
Definition node.h:320
node_stream_device open_as_stream()
Creates a stream device over this node.
Definition node.h:421
subnode_iterator subnode_begin() const
Returns a proxy iterator for the first subnode.
Definition node.h:447
uint get_page_count() const
Returns the number of pages in this node.
Definition node.h:430
node & operator=(const node &other)
Set one node equal to another.
Definition node.h:364
size_t read(std::vector< byte > &buffer, uint page_num, ulong offset) const
Read data from this node.
Definition node.h:393
node(const node &container_node, const subnode_info &info)
Constructor for subnodes.
Definition node.h:335
subnode_iterator subnode_end() const
Returns a proxy iterator positioned past the last subnode.
Definition node.h:457
node(const std::shared_ptr< node_impl > &container_node, const subnode_info &info)
Constructor for subnodes.
Definition node.h:338
size_t get_page_size(uint page_num) const
Returns the size of a page in this node.
Definition node.h:427
size_t read(std::vector< byte > &buffer, ulong offset) const
Read data from this node.
Definition node.h:387
bool is_subnode()
Tells you if this is a subnode.
Definition node.h:377
boost::transform_iterator< subnode_transform_info, const_subnodeinfo_iterator > subnode_iterator
A transform iterator, so we can expose the subnodes as a collection of nodes rather than subnode_info...
Definition node.h:324
size_t size() const
Returns the size of this node.
Definition node.h:425
node(const node &other)
Copy construct this node.
Definition node.h:345
block_id get_data_id() const
Get the block_id of the data block of this node.
Definition node.h:370
const_subnodeinfo_iterator subnode_info_end() const
Returns an iterator positioned past the last subnodeinfo.
Definition node.h:437
block_id get_sub_id() const
Get the block_id of the subnode block of this node.
Definition node.h:372
std::shared_ptr< subnode_block > get_subnode_block() const
Returns the subnode block associated with this node.
Definition node.h:383
std::shared_ptr< data_block > get_data_block() const
Returns the data block associated with this node.
Definition node.h:380
node(const shared_db_ptr &db, const node_info &info)
Constructor for top level nodes.
Definition node.h:327
node_id get_parent_id() const
Get the parent id.
Definition node.h:375
T read(ulong offset) const
Read data from this node.
Definition node.h:390
T read(uint page_num, ulong offset) const
Read data from a specific block on this node.
Definition node.h:396
node(const node &other, alias_tag)
Alias constructor.
Definition node.h:353
node(node &&other)
Move constructor.
Definition node.h:359
node lookup(node_id id) const
Lookup a subnode by node id.
Definition node.h:461
const_subnodeinfo_iterator subnode_info_begin() const
Returns an iterator positioned at first subnodeinfo.
Definition node.h:434
node_id get_id() const
Get the id of this node.
Definition node.h:368
Generic base class for all page typesA page which forms a node in the NBT or BBT.
Definition page.h:52
A block which contains information about subnodes.
Definition node.h:767
virtual ~subnode_block()
Definition node.h:776
bool is_internal() const
Returns the blocks internal/external state.
Definition node.h:782
ushort get_level() const
Get the level of this subnode_block.
Definition node.h:780
ushort m_level
Level of this subnode_block.
Definition node.h:785
subnode_block(const shared_db_ptr &db, const block_info &info, ushort level)
Construct a block from disk.
Definition node.h:773
Contains the actual subnode information.
Definition node.h:841
uint num_values() const
Returns the number of entries in this btree_node.
Definition node.h:860
const node_id & get_key(uint pos) const
Returns the key at the specified position.
Definition node.h:858
subnode_leaf_block(const shared_db_ptr &db, const block_info &info, std::vector< std::pair< node_id, subnode_info > > subnodes)
Construct a subnode_leaf_block from disk.
Definition node.h:848
const subnode_info & get_value(uint pos) const
Returns the value at the associated position on this leaf node.
Definition node.h:856
Contains references to subnode_leaf_blocks.
Definition node.h:804
subnode_block * get_child(uint pos)
Returns the child btree_node at the requested location.
Definition node.h:1040
const node_id & get_key(uint pos) const
Returns the key at the specified position.
Definition node.h:819
subnode_nonleaf_block(const shared_db_ptr &db, const block_info &info, std::vector< std::pair< node_id, block_id > > subblocks)
Construct a subnode_nonleaf_block from disk.
Definition node.h:811
uint num_values() const
Returns the number of entries in this btree_node.
Definition node.h:823
Defines a transform from a subnode_info to an actual node object.
Definition node.h:238
node operator()(const subnode_info &info) const
Given a subnode_info, construct a subnode.
Definition node.h:869
subnode_transform_info(const std::shared_ptr< node_impl > &parent)
Initialize this functor with the container node involved.
Definition node.h:242
Database interface.
boost::iostreams::stream< node_stream_device > node_stream
The actual node stream, defined using the boost iostream library and the node_stream_device.
Definition node.h:294
boost::uint64_t ulonglong
Definition primitives.h:70
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
Contains the definition of all in memory representations of disk structures.
Definition disk.h:19
std::weak_ptr< db_context > weak_db_ptr
std::shared_ptr< db_context > shared_db_ptr
Tag structure used to indicate a copy constructed class should be an alias (shallow copy) rather than...
Definition primitives.h:110
An in memory, database format agnostic version of disk::bbt_leaf_entry.
An in memory, database format agnostic version of disk::nbt_leaf_entry.
An in memory, database format agnostic version of disk::sub_leaf_entry.
General utility functions and classes.