PST File Format SDK v0.4
Loading...
Searching...
No Matches
table.h
Go to the documentation of this file.
1
5
6#ifndef PSTSDK_LTP_TABLE_H
7#define PSTSDK_LTP_TABLE_H
8
9#include <vector>
10
11#include <unordered_map>
12#include <boost/iterator/iterator_facade.hpp>
13
15
16#include "pstsdk/ndb/node.h"
17
18#include "pstsdk/ltp/object.h"
19#include "pstsdk/ltp/heap.h"
20
21namespace pstsdk
22{
23
24class table_impl;
26
27typedef std::shared_ptr<table_impl> table_ptr;
28typedef std::shared_ptr<const table_impl> const_table_ptr;
30
39
51{
52public:
56 : m_position(other.m_position), m_table(other.m_table) { }
61 : m_position(position), m_table(table) { }
62
65 row_id get_row_id() const;
66
67 // const_property_object
68 std::vector<prop_id> get_prop_list() const;
70 bool prop_exists(prop_id id) const;
71 size_t size(prop_id id) const;
73
74private:
75 // const_property_object
76 byte get_value_1(prop_id id) const;
77 ushort get_value_2(prop_id id) const;
78 ulong get_value_4(prop_id id) const;
79 ulonglong get_value_8(prop_id id) const;
80 std::vector<byte> get_value_variable(prop_id id) const;
81
82 ulong m_position;
83 const_table_ptr m_table;
84};
85
93class const_table_row_iter : public boost::iterator_facade<const_table_row_iter, const_table_row, boost::random_access_traversal_tag, const_table_row>
94{
95public:
98 : m_position(0) { }
99
104 : m_position(pos), m_table(table) { }
105
106private:
108
109 void increment() { ++m_position; }
110 bool equal(const const_table_row_iter& other) const
111 { return ((m_position == other.m_position) && (m_table == other.m_table)); }
112 const_table_row dereference() const
113 { return const_table_row(m_position, m_table); }
114 void decrement() { --m_position; }
115 void advance(int off) { m_position += off; }
116 size_t distance_to(const const_table_row_iter& other) const
117 { return (other.m_position - m_position); }
118
119 ulong m_position;
120 const_table_ptr m_table;
121};
122
137class table_impl : public std::enable_shared_from_this<table_impl>
138{
139public:
140 virtual ~table_impl() { }
145 virtual ulong lookup_row(row_id id) const = 0;
146
160
163 virtual node& get_node() = 0;
166 virtual const node& get_node() const = 0;
173 virtual ulonglong get_cell_value(ulong row, prop_id id) const = 0;
180 virtual std::vector<byte> read_cell(ulong row, prop_id id) const = 0;
195 virtual std::vector<prop_id> get_prop_list() const = 0;
198 virtual prop_type get_prop_type(prop_id id) const = 0;
204 virtual row_id get_row_id(ulong row) const = 0;
207 virtual size_t size() const = 0;
212 virtual bool prop_exists(ulong row, prop_id id) const = 0;
218 virtual size_t row_prop_size(ulong row, prop_id id) const = 0;
219};
220
235template<typename T>
237{
238public:
240 { return m_prows->get_node(); }
241 const node& get_node() const
242 { return m_prows->get_node(); }
243 ulong lookup_row(row_id id) const;
245 std::vector<byte> read_cell(ulong row, prop_id id) const;
247 std::vector<prop_id> get_prop_list() const;
249 row_id get_row_id(ulong row) const;
250 size_t size() const;
251 bool prop_exists(ulong row, prop_id id) const;
252 size_t row_prop_size(ulong row, prop_id id) const;
253
254private:
255 friend table_ptr open_table(const node& n);
257 basic_table(const node& n);
258 basic_table(const node& n, alias_tag);
259
260 std::shared_ptr<bth_node<row_id, T> > m_prows;
261
262 // only one of the following two items is valid
263 std::vector<byte> m_vec_rowarray;
264 std::shared_ptr<node> m_pnode_rowarray;
265
266 std::unordered_map<prop_id, disk::column_description> m_columns;
267 typedef std::unordered_map<prop_id, disk::column_description>::iterator column_iter;
268 typedef std::unordered_map<prop_id, disk::column_description>::const_iterator const_column_iter;
269
270 ushort m_offsets[disk::tc_offsets_max];
271
272 // helper functions
275 ulong cb_per_row() const { return m_offsets[disk::tc_offsets_bitmap]; }
278 ulong exists_bitmap_start() const { return m_offsets[disk::tc_offsets_one]; }
281 ulong rows_per_page() const { return (m_pnode_rowarray ? m_pnode_rowarray->get_page_size(0) / cb_per_row() : m_vec_rowarray.size() / cb_per_row()); }
286 template<typename Val> Val read_raw_row(ulong row, ushort offset) const;
289 std::vector<byte> read_exists_bitmap(ulong row) const;
290};
291
294
307class table
308{
309public:
312 explicit table(const node& n);
318 table(const table& other);
322 : m_ptable(other.m_ptable) { }
323
326 { return (*m_ptable)[row]; }
329 { return m_ptable->begin(); }
332 { return m_ptable->end(); }
333
336 { return m_ptable->get_node(); }
338 const node& get_node() const
339 { return m_ptable->get_node(); }
342 { return m_ptable->get_cell_value(row, id); }
344 std::vector<byte> read_cell(ulong row, prop_id id) const
345 { return m_ptable->read_cell(row, id); }
348 { return m_ptable->open_cell_stream(row, id); }
350 std::vector<prop_id> get_prop_list() const
351 { return m_ptable->get_prop_list(); }
354 { return m_ptable->get_prop_type(id); }
357 { return m_ptable->get_row_id(row); }
360 { return m_ptable->lookup_row(id); }
362 size_t size() const
363 { return m_ptable->size(); }
364private:
365 table();
366
367 table_ptr m_ptable;
368};
369
370} // end pstsdk namespace
371
373{
375 {
376 //return table_ptr(new gust(n));
377 throw not_implemented("gust table");
378 }
379
380 heap h(n);
381 std::vector<byte> table_info = h.read(h.get_root_id());
383
384 std::vector<byte> bth_info = h.read(pheader->row_btree_id);
386
387 if(pbthheader->entry_size == 4)
388 return table_ptr(new large_table(n));
389 else
390 return table_ptr(new small_table(n));
391}
392
394{
396 {
397 //return table_ptr(new gust(n));
398 throw not_implemented("gust table");
399 }
400
401 heap h(n);
402 std::vector<byte> table_info = h.read(h.get_root_id());
404
405 std::vector<byte> bth_info = h.read(pheader->row_btree_id);
407
408 if(pbthheader->entry_size == 4)
409 return table_ptr(new large_table(n, alias_tag()));
410 else
411 return table_ptr(new small_table(n, alias_tag()));
412}
413
414inline std::vector<pstsdk::prop_id> pstsdk::const_table_row::get_prop_list() const
415{
416 std::vector<prop_id> columns = m_table->get_prop_list();
417 std::vector<prop_id> props;
418
419 for(size_t i = 0; i < columns.size(); ++i)
420 {
421 if(prop_exists(columns[i]))
422 props.push_back(columns[i]);
423 }
424
425 return props;
426}
427
429{
430 return m_table->row_prop_size(m_position, id);
431}
432
434{
435 return m_table->get_prop_type(id);
436}
437
439{
440 return m_table->prop_exists(m_position, id);
441}
442
444{
445 return m_table->get_row_id(m_position);
446}
447
448inline pstsdk::byte pstsdk::const_table_row::get_value_1(prop_id id) const
449{
450 return (byte)m_table->get_cell_value(m_position, id);
451}
452
453inline pstsdk::ushort pstsdk::const_table_row::get_value_2(prop_id id) const
454{
455 return (ushort)m_table->get_cell_value(m_position, id);
456}
457
458inline pstsdk::ulong pstsdk::const_table_row::get_value_4(prop_id id) const
459{
460 return (ulong)m_table->get_cell_value(m_position, id);
461}
462
463inline pstsdk::ulonglong pstsdk::const_table_row::get_value_8(prop_id id) const
464{
465 return m_table->get_cell_value(m_position, id);
466}
467
468inline std::vector<pstsdk::byte> pstsdk::const_table_row::get_value_variable(prop_id id) const
469{
470 return m_table->read_cell(m_position, id);
471}
472
474{
475 return (std::const_pointer_cast<table_impl>(m_table))->open_cell_stream(m_position, id);
476}
477
478template<typename T>
480{
482
483 std::vector<byte> table_info = h.read(h.get_root_id());
485
486#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
487 if(pheader->signature != disk::heap_sig_tc)
488 throw sig_mismatch("heap_sig_tc expected", 0, n.get_id(), pheader->signature, disk::heap_sig_tc);
489#endif
490
491 m_prows = h.open_bth<row_id, T>(pheader->row_btree_id);
492
493 for(int i = 0; i < pheader->num_columns; ++i)
494 m_columns[pheader->columns[i].id] = pheader->columns[i];
495
496 for(int i = 0; i < disk::tc_offsets_max; ++i)
497 m_offsets[i] = pheader->size_offsets[i];
498
499 if(is_subnode_id(pheader->row_matrix_id))
500 {
501 m_pnode_rowarray.reset(new node(n.lookup(pheader->row_matrix_id)));
502 }
503 else if(pheader->row_matrix_id)
504 {
505 m_vec_rowarray = h.read(pheader->row_matrix_id);
506 }
507}
508
509template<typename T>
510inline pstsdk::basic_table<T>::basic_table(const node& n, alias_tag)
511{
512 heap h(n, disk::heap_sig_tc, alias_tag());
513
514 std::vector<byte> table_info = h.read(h.get_root_id());
515 disk::tc_header* pheader = (disk::tc_header*)&table_info[0];
516
517#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
518 if(pheader->signature != disk::heap_sig_tc)
519 throw sig_mismatch("heap_sig_tc expected", 0, n.get_id(), pheader->signature, disk::heap_sig_tc);
520#endif
521
522 m_prows = h.open_bth<row_id, T>(pheader->row_btree_id);
523
524 for(int i = 0; i < pheader->num_columns; ++i)
525 m_columns[pheader->columns[i].id] = pheader->columns[i];
526
527 for(int i = 0; i < disk::tc_offsets_max; ++i)
528 m_offsets[i] = pheader->size_offsets[i];
529
530 if(is_subnode_id(pheader->row_matrix_id))
531 {
532 m_pnode_rowarray.reset(new node(n.lookup(pheader->row_matrix_id)));
533 }
534 else if(pheader->row_matrix_id)
535 {
536 m_vec_rowarray = h.read(pheader->row_matrix_id);
537 }
538}
539
540template<typename T>
541inline size_t pstsdk::basic_table<T>::size() const
542{
543 if(m_pnode_rowarray)
544 {
545 return (m_pnode_rowarray->get_page_count()-1) * rows_per_page() + m_pnode_rowarray->get_page_size(m_pnode_rowarray->get_page_count()-1) / cb_per_row();
546 }
547 else
548 {
549 return m_vec_rowarray.size() / cb_per_row();
550 }
551}
552
553template<typename T>
554inline std::vector<pstsdk::prop_id> pstsdk::basic_table<T>::get_prop_list() const
555{
556 std::vector<prop_id> props;
557
558 for(const_column_iter i = m_columns.begin(); i != m_columns.end(); ++i)
559 props.push_back(i->first);
560
561 return props;
562}
563
564template<typename T>
566{
567 try
568 {
569 return (ulong)m_prows->lookup(id);
570 }
571 catch(key_not_found<T>& e)
572 {
573 throw key_not_found<row_id>(e.which());
574 }
575}
576
577template<typename T>
579{
580 if(!prop_exists(row, id))
581 throw key_not_found<prop_id>(id);
582
583 const_column_iter column = m_columns.find(id);
584 ulonglong value;
585
586 switch(column->second.size)
587 {
588 case 8:
589 value = read_raw_row<ulonglong>(row, column->second.offset);
590 break;
591 case 4:
592 value = read_raw_row<ulong>(row, column->second.offset);
593 break;
594 case 2:
595 value = read_raw_row<ushort>(row, column->second.offset);
596 break;
597 case 1:
598 value = read_raw_row<byte>(row, column->second.offset);
599 break;
600 default:
601 throw database_corrupt("get_cell_value: invalid cell size");
602 }
603
604 return value;
605}
606
607template<typename T>
609{
610 heapnode_id hid = static_cast<heapnode_id>(get_cell_value(row, id));
611
612 if(is_subnode_id(hid))
613 return get_node().lookup(hid).size();
614 else
615 return m_prows->get_heap_ptr()->size(hid);
616}
617
618template<typename T>
619inline std::vector<pstsdk::byte> pstsdk::basic_table<T>::read_cell(ulong row, prop_id id) const
620{
621 heapnode_id hid = static_cast<heapnode_id>(get_cell_value(row, id));
622 std::vector<byte> buffer;
623
624 if(is_subnode_id(hid))
625 {
626 node sub(get_node().lookup(hid));
627 buffer.resize(sub.size());
628 sub.read(buffer, 0);
629 }
630 else
631 {
632 buffer = m_prows->get_heap_ptr()->read(hid);
633 }
634 return buffer;
635}
636
637template<typename T>
639{
640 heapnode_id hid = static_cast<heapnode_id>(get_cell_value(row, id));
641
642 if(is_subnode_id(hid))
643 return get_node().lookup(hid).open_as_stream();
644 else
645 return m_prows->get_heap_ptr()->open_stream(hid);
646}
647
648template<typename T>
650{
651 const_column_iter iter = m_columns.find(id);
652
653 if(iter == m_columns.end())
654 throw key_not_found<prop_id>(id);
655
656 return (prop_type)iter->second.type;
657}
658
659template<typename T>
664
665template<typename T>
666template<typename Val>
668{
669 if(row >= size())
670 throw std::out_of_range("row >= size()");
671
672 if(m_pnode_rowarray)
673 {
674 ulong page_num = row / rows_per_page();
675 ulong page_offset = (row % rows_per_page()) * cb_per_row();
676
677 return m_pnode_rowarray->read<Val>(page_num, page_offset+offset);
678 }
679 else
680 {
681 Val val;
682 memcpy(&val, &m_vec_rowarray[ row * cb_per_row() + offset ], sizeof(Val));
683 return val;
684 }
685}
686
687template<typename T>
688inline std::vector<pstsdk::byte> pstsdk::basic_table<T>::read_exists_bitmap(ulong row) const
689{
690 std::vector<byte> exists_bitmap(cb_per_row() - exists_bitmap_start());
691
692 if(row >= size())
693 throw std::out_of_range("row >= size()");
694
695 if(m_pnode_rowarray)
696 {
697 ulong page_num = row / rows_per_page();
698 ulong page_offset = (row % rows_per_page()) * cb_per_row();
699
700 m_pnode_rowarray->read(exists_bitmap, page_num, page_offset + exists_bitmap_start());
701 }
702 else
703 {
704 memcpy(&exists_bitmap[0], &m_vec_rowarray[ row * cb_per_row() + exists_bitmap_start() ], exists_bitmap.size());
705 }
706
707 return exists_bitmap;
708}
709
710template<typename T>
712{
713 const_column_iter column = m_columns.find(id);
714
715 if(column == m_columns.end())
716 return false;
717
718 std::vector<byte> exists_map = read_exists_bitmap(row);
719
720 return test_bit(&exists_map[0], column->second.bit_offset);
721}
722
724{
725 m_ptable = open_table(n);
726}
727
729{
730 m_ptable = open_table(other.m_ptable->get_node());
731}
732
733#endif
Implementation of an ANSI TC (64k rows) and a unicode TC.
Definition table.h:237
hnid_stream_device open_cell_stream(ulong row, prop_id id)
Open a stream over a property in a given row.
Definition table.h:638
std::vector< byte > read_cell(ulong row, prop_id id) const
Get the contents of a indirect property in the specified row.
Definition table.h:619
std::vector< prop_id > get_prop_list() const
Get all of the properties on this table.
Definition table.h:554
friend table_ptr open_table(const node &n, alias_tag)
Open the specified node as a table.
prop_type get_prop_type(prop_id id) const
Get the type of a property.
Definition table.h:649
size_t row_prop_size(ulong row, prop_id id) const
Return the size of a property for a given row.
Definition table.h:608
friend table_ptr open_table(const node &n)
Open the specified node as a table.
size_t size() const
Get the number of rows in this table.
Definition table.h:541
const node & get_node() const
Get the node backing this table.
Definition table.h:241
ulonglong get_cell_value(ulong row, prop_id id) const
Get the contents of the specified cell in the specified row.
Definition table.h:578
bool prop_exists(ulong row, prop_id id) const
Check to see if a property exists for a given row.
Definition table.h:711
node & get_node()
Get the node backing this table.
Definition table.h:239
row_id get_row_id(ulong row) const
Get the row id of a specified row.
Definition table.h:660
ulong lookup_row(row_id id) const
Find the offset into the table of the given row_id.
Definition table.h:565
const heap_ptr get_heap_ptr() const
Returns the heap this bth_node is in.
Definition heap.h:335
heap_id get_id() const
Return the heap_id of this bth_node.
Definition heap.h:322
const node & get_node() const
Get the node underlying this BTH.
Definition heap.h:342
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
void first(btree_iter_impl< K, V > &iter) const
Positions the iterator at the first element on this tree.
Definition btree.h:369
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
Property object base class.
Definition object.h:94
The iterator type exposed by the table for row iteration.
Definition table.h:94
const_table_row_iter(ulong pos, const const_table_ptr &table)
Construct an iterator from a position and table.
Definition table.h:103
const_table_row_iter()
Default constructor.
Definition table.h:97
friend class boost::iterator_core_access
Definition table.h:107
An abstraction of a table row.
Definition table.h:51
bool prop_exists(prop_id id) const
Indicates the existance of a given property on this object.
Definition table.h:438
prop_type get_prop_type(prop_id id) const
Get the property type of a given prop_id.
Definition table.h:433
std::vector< prop_id > get_prop_list() const
Get a list of all properties on this object.
Definition table.h:414
size_t size(prop_id id) const
Returns the total size of a variable length property.
Definition table.h:428
const_table_row(ulong position, const const_table_ptr &table)
Construct a const_table_row object from a table and row offset.
Definition table.h:60
row_id get_row_id() const
Get the row_id of this row.
Definition table.h:443
hnid_stream_device open_prop_stream(prop_id id)
Creates a stream device over a property on this object.
Definition table.h:473
const_table_row(const const_table_row &other)
Copy construct this row.
Definition table.h:55
The database is corrupt.
Definition errors.h:48
Heap-on-Node implementation.
Definition heap.h:195
Defines a stream device which can wrap one of the two prop sources.
Definition object.h:56
An in memory representation of the "node" concept in a PST data file.
Definition node.h:320
size_t read(std::vector< byte > &buffer, ulong offset) const
Read data from this node.
Definition node.h:387
size_t size() const
Returns the size of this node.
Definition node.h:425
This function or method has not been implemented.
Definition errors.h:30
An unexpected signature was encountered.
Definition errors.h:98
Table implementation.
Definition table.h:138
virtual row_id get_row_id(ulong row) const =0
Get the row id of a specified row.
virtual size_t size() const =0
Get the number of rows in this table.
virtual prop_type get_prop_type(prop_id id) const =0
Get the type of a property.
virtual ulong lookup_row(row_id id) const =0
Find the offset into the table of the given row_id.
const_table_row_iter end() const
Get an end iterator for this table.
Definition table.h:158
virtual node & get_node()=0
Get the node backing this table.
virtual std::vector< prop_id > get_prop_list() const =0
Get all of the properties on this table.
virtual ~table_impl()
Definition table.h:140
virtual const node & get_node() const =0
Get the node backing this table.
const_table_row operator[](ulong row) const
Get the requested table row.
Definition table.h:150
virtual hnid_stream_device open_cell_stream(ulong row, prop_id id)=0
Open a stream over a property in a given row.
virtual std::vector< byte > read_cell(ulong row, prop_id id) const =0
Get the contents of a indirect property in the specified row.
virtual bool prop_exists(ulong row, prop_id id) const =0
Check to see if a property exists for a given row.
const_table_row_iter begin() const
Get an iterator pointing to the first row.
Definition table.h:154
virtual size_t row_prop_size(ulong row, prop_id id) const =0
Return the size of a property for a given row.
virtual ulonglong get_cell_value(ulong row, prop_id id) const =0
Get the contents of the specified cell in the specified row.
The actual table object that clients reference.
Definition table.h:308
std::vector< prop_id > get_prop_list() const
Get all of the properties on this table.
Definition table.h:350
row_id get_row_id(ulong row) const
Get the row id of a specified row.
Definition table.h:356
prop_type get_prop_type(prop_id id) const
Get the type of a property.
Definition table.h:353
hnid_stream_device open_cell_stream(ulong row, prop_id id)
Open a stream over a property in a given row.
Definition table.h:347
ulonglong get_cell_value(ulong row, prop_id id) const
Get the contents of the specified cell in the specified row.
Definition table.h:341
size_t size() const
Get the number of rows in this table.
Definition table.h:362
const_table_row_iter end() const
Get an end iterator for this table.
Definition table.h:331
node & get_node()
Get the node backing this table.
Definition table.h:335
table(const node &n, alias_tag)
Construct a table from this node.
ulong lookup_row(row_id id) const
Find the offset into the table of the given row_id.
Definition table.h:359
std::vector< byte > read_cell(ulong row, prop_id id) const
Get the contents of a indirect property in the specified row.
Definition table.h:344
table(const node &n)
Construct a table from this node.
Definition table.h:723
const_table_row operator[](ulong row) const
Get the requested table row.
Definition table.h:325
table(const table &other, alias_tag)
Alias constructor.
Definition table.h:321
const_table_row_iter begin() const
Get an iterator pointing to the first row.
Definition table.h:328
const node & get_node() const
Get the node backing this table.
Definition table.h:338
@ heap_sig_tc
Definition disk.h:1228
@ tc_offsets_max
Definition disk.h:1473
@ tc_offsets_one
Definition disk.h:1471
@ tc_offsets_bitmap
Definition disk.h:1472
table_ptr open_table(const node &n)
Open the specified node as a table.
Definition table.h:372
boost::uint64_t ulonglong
Definition primitives.h:70
boost::uint8_t byte
Definition primitives.h:72
ulong row_id
Definition primitives.h:95
boost::uint32_t ulong
Definition primitives.h:68
ulong heapnode_id
Definition primitives.h:91
boost::uint16_t ushort
Definition primitives.h:73
ushort prop_id
Definition primitives.h:93
bool is_subnode_id(heapnode_id id)
Inspects a heapnode_id (also known as a HNID) to determine if it is a node_id (NID)
Definition primitives.h:281
prop_type
The different property types as defined by MAPI.
Definition primitives.h:292
@ nid_all_message_search_contents
Definition primitives.h:202
bool test_bit(const byte *pbytes, ulong bit)
Test to see if the specified bit in the buffer is set.
Definition util.h:232
Heap-on-Node (HN) and BTree-on-Heap (BTH) implementation.
Contains the definition of all in memory representations of disk structures.
Definition disk.h:19
basic_table< ushort > small_table
Definition table.h:292
basic_table< ulong > large_table
Definition table.h:293
std::shared_ptr< const table_impl > const_table_ptr
Definition table.h:28
std::shared_ptr< table_impl > table_ptr
Definition table.h:27
Node and Block definitions.
Property access base class.
Primitive structures defined by MS-PST and MAPI.
Tag structure used to indicate a copy constructed class should be an alias (shallow copy) rather than...
Definition primitives.h:110
Describes the BTH, including the size of the keys/values and the heap_id of the root allocation.
Definition disk.h:1324
The root_id allocation out of the Heap of a TC node.
Definition disk.h:1511
heapnode_id row_matrix_id
Definition disk.h:1516