PST File Format SDK v0.4
Loading...
Searching...
No Matches
object.h
Go to the documentation of this file.
1
12
13#ifndef PSTSDK_LTP_OBJECT_H
14#define PSTSDK_LTP_OBJECT_H
15
16#include "pstsdk/util/util.h"
17#include <functional>
18#include <type_traits>
19#include <algorithm>
20#include <optional>
21#include <boost/iostreams/concepts.hpp>
22#ifdef _MSC_VER
23#pragma warning(push)
24#pragma warning(disable:4244)
25#endif
26#include <boost/iostreams/stream.hpp>
27#ifdef _MSC_VER
28#pragma warning(pop)
29#endif
30
32#include "pstsdk/util/errors.h"
33
34#include "pstsdk/ltp/heap.h"
35
36#include "pstsdk/ndb/node.h"
37
38namespace pstsdk
39{
40
43
55class hnid_stream_device : public boost::iostreams::device<boost::iostreams::input_seekable>
56{
57public:
59 std::streamsize read(char* pbuffer, std::streamsize n)
60 { if(m_is_hid) return m_hid_device.read(pbuffer, n); else return m_node_device.read(pbuffer, n); }
62 std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way)
63 { if(m_is_hid) return m_hid_device.seek(off, way); else return m_node_device.seek(off, way); }
64
66 hnid_stream_device(const hid_stream_device& hid_device) : m_hid_device(hid_device), m_is_hid(true) { }
68 hnid_stream_device(const node_stream_device& node_device) : m_node_device(node_device), m_is_hid(false) { }
69
70private:
71 hid_stream_device m_hid_device;
72 node_stream_device m_node_device;
73 bool m_is_hid;
74
75 std::streamsize m_pos;
76};
77
81typedef boost::iostreams::stream<hnid_stream_device> prop_stream;
82
94{
95public:
99 virtual std::vector<prop_id> get_prop_list() const = 0;
104 virtual prop_type get_prop_type(prop_id id) const = 0;
108 virtual bool prop_exists(prop_id id) const = 0;
113 virtual size_t size(prop_id id) const = 0;
114
123 template<typename T>
124 T read_prop(prop_id id) const;
125
134 template<typename T>
135 std::optional<T> read_prop_if_exists(prop_id id) const;
136
146 template<typename T>
147 std::vector<T> read_prop_array(prop_id id) const;
148
162
163// GCC has time_t defined as a typedef of a long, so calling
164// read_prop<slong> activates the time_t specialization. I'm
165// turning them into first class member functions in GCC for now until
166// I figure out a portable way to deal with time.
167#ifdef __GNUC__
169 std::vector<time_t> read_time_t_array(prop_id id) const;
170#endif
171
172protected:
174 virtual byte get_value_1(prop_id id) const = 0;
176 virtual ushort get_value_2(prop_id id) const = 0;
178 virtual ulong get_value_4(prop_id id) const = 0;
180 virtual ulonglong get_value_8(prop_id id) const = 0;
182 virtual std::vector<byte> get_value_variable(prop_id id) const = 0;
183};
184
185} // end pstsdk namespace
186
187template<typename T>
189{
190#ifdef _MSC_VER
191#pragma warning(suppress:4127)
192#endif
193 if(!std::is_pod<T>::value)
194 throw std::invalid_argument("T must be a POD or one of the specialized classes");
195
196 if(sizeof(T) == sizeof(ulonglong))
197 {
198 ulonglong t = get_value_8(id);
199 return *(reinterpret_cast<T*>(&t));
200 }
201 else if(sizeof(T) == sizeof(ulong))
202 {
203 ulong t = get_value_4(id);
204 return *(reinterpret_cast<T*>(&t));
205 }
206 else if(sizeof(T) == sizeof(ushort))
207 {
208 ushort t = get_value_2(id);
209 return *(reinterpret_cast<T*>(&t));
210 }
211 else if(sizeof(T) == sizeof(byte))
212 {
213 byte t = get_value_1(id);
214 return *(reinterpret_cast<T*>(&t));
215 }
216 else
217 {
218 std::vector<byte> buffer = get_value_variable(id);
219 return *(reinterpret_cast<T*>(&buffer[0]));
220 }
221}
222
223template<typename T>
225{
226#ifdef _MSC_VER
227#pragma warning(suppress:4127)
228#endif
229 if(!std::is_pod<T>::value)
230 throw std::invalid_argument("T must be a POD or one of the specialized classes");
231
232 std::vector<byte> buffer = get_value_variable(id);
233 return std::vector<T>(reinterpret_cast<T*>(&buffer[0]), reinterpret_cast<T*>(&buffer[0] + buffer.size()));
234}
235
236namespace pstsdk
237{
238
239template<>
240inline bool const_property_object::read_prop<bool>(prop_id id) const
241{
242 return get_value_4(id) != 0;
243}
244
245template<>
246inline std::vector<bool> pstsdk::const_property_object::read_prop_array<bool>(prop_id id) const
247{
248 using namespace std::placeholders;
249
250 std::vector<ulong> values = read_prop_array<ulong>(id);
251 std::vector<bool> results(values.size());
252 std::transform(values.begin(), values.end(), results.begin(), std::bind(std::not_equal_to<ulong>(), 0, _1));
253 return results;
254}
255
256// See the note in the class definition - convert the time_t read_prop
257// specialization into a member function in GCC
258#ifdef __GNUC__
259inline time_t const_property_object::read_time_t_prop(prop_id id) const
260#else
261template<>
262inline time_t const_property_object::read_prop<time_t>(prop_id id) const
263#endif
264{
265 if(get_prop_type(id) == prop_type_apptime)
266 {
267 double time_value = read_prop<double>(id);
269 }
270 else
271 {
274 }
275}
276
277#ifdef __GNUC__
278inline std::vector<time_t> const_property_object::read_time_t_array(prop_id id) const
279#else
280template<>
281inline std::vector<time_t> const_property_object::read_prop_array<time_t>(prop_id id) const
282#endif
283{
284 if(get_prop_type(id) == prop_type_mv_apptime)
285 {
286 std::vector<double> time_values = read_prop_array<double>(id);
287 std::vector<time_t> result(time_values.size());
289 return result;
290 }
291 else
292 {
293 std::vector<ulonglong> time_values = read_prop_array<ulonglong>(id);
294 std::vector<time_t> result(time_values.size());
295 std::transform(time_values.begin(), time_values.end(), result.begin(), filetime_to_time_t);
296 return result;
297 }
298
299}
300
301template<>
302inline std::vector<byte> const_property_object::read_prop<std::vector<byte> >(prop_id id) const
303{
304 return get_value_variable(id);
305}
306
307
308template<typename T>
310 if (prop_exists(id)) {
311 return read_prop<T>(id);
312 } else {
313 return {};
314 }
315}
316
317template<>
318inline std::vector<std::vector<byte>> const_property_object::read_prop_array<std::vector<byte> >(prop_id id) const
319{
320 std::vector<byte> buffer = get_value_variable(id);
321#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
322 if(buffer.size() < sizeof(ulong))
323 throw std::length_error("mv prop too short");
324#endif
325 disk::mv_toc* ptoc = reinterpret_cast<disk::mv_toc*>(&buffer[0]);
326 std::vector<std::vector<byte> > results;
327
328#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
329 if(buffer.size() < (sizeof(ulong) + ptoc->count * sizeof(ulong)))
330 throw std::length_error("mv prop too short");
331#endif
332
333 for(ulong i = 0; i < ptoc->count; ++i)
334 {
335 ulong start = ptoc->offsets[i];
336 ulong end = (i == (ptoc->count - 1)) ? buffer.size() : ptoc->offsets[i+1];
337#ifdef PSTSDK_VALIDATION_LEVEL_WEAK
338 if(end < start)
339 throw std::length_error("inconsistent mv prop toc");
340#endif
341 results.push_back(std::vector<byte>(&buffer[start], &buffer[start] + (end-start)));
342 }
343
344 return results;
345}
346
347template<>
348inline std::wstring const_property_object::read_prop<std::wstring>(prop_id id) const
349{
350 std::vector<byte> buffer = get_value_variable(id);
351
352 if(get_prop_type(id) == prop_type_string)
353 {
354 std::string s(buffer.begin(), buffer.end());
355 return std::wstring(s.begin(), s.end());
356 }
357 else
358 {
359 return bytes_to_wstring(buffer);
360 }
361}
362
363template<>
364inline std::vector<std::wstring> const_property_object::read_prop_array<std::wstring>(prop_id id) const
365{
366 std::vector<std::vector<byte> > buffer = read_prop_array<std::vector<byte> >(id);
367 std::vector<std::wstring> results;
368
369 for(size_t i = 0; i < buffer.size(); ++i)
370 {
371 if(get_prop_type(id) == prop_type_mv_string)
372 {
373 std::string s(buffer[i].begin(), buffer[i].end());
374 results.push_back(std::wstring(s.begin(), s.end()));
375 }
376 else
377 {
378 results.push_back(bytes_to_wstring(buffer[i]));
379 }
380 }
381
382 return results;
383}
384
385template<>
386inline std::string const_property_object::read_prop<std::string>(prop_id id) const
387{
388 std::vector<byte> buffer = get_value_variable(id);
389
390 if(get_prop_type(id) == prop_type_string)
391 {
392 return std::string(buffer.begin(), buffer.end());
393 }
394 else
395 {
396 if(buffer.size())
397 {
398 return std::string(bytes_to_string(buffer));
399 }
400 return std::string();
401 }
402}
403
404template<>
405inline std::vector<std::string> const_property_object::read_prop_array<std::string>(prop_id id) const
406{
407 std::vector<std::vector<byte> > buffer = read_prop_array<std::vector<byte> >(id);
408 std::vector<std::string> results;
409
410 for(size_t i = 0; i < buffer.size(); ++i)
411 {
412 if(get_prop_type(id) == prop_type_mv_string)
413 {
414 results.push_back(std::string(buffer[i].begin(), buffer[i].end()));
415 }
416 else
417 {
418 if(buffer[i].size())
419 {
420 std::wstring s(bytes_to_wstring(buffer[i]));
421 results.push_back(std::string(s.begin(), s.end()));
422 }
423 results.push_back(std::string());
424 }
425 }
426
427 return results;
428}
429
430} // end pstsdk namespace
431
432#endif
Contains references to other bth_node allocations.
Definition heap.h:364
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
virtual hnid_stream_device open_prop_stream(prop_id id)=0
Creates a stream device over a property on this object.
virtual ulong get_value_4(prop_id id) const =0
Implemented by child classes to fetch a 4 byte sized property.
std::optional< T > read_prop_if_exists(prop_id id) const
Read a property as a given type, if it exists.
Definition object.h:309
virtual ushort get_value_2(prop_id id) const =0
Implemented by child classes to fetch a 2 byte sized property.
virtual std::vector< byte > get_value_variable(prop_id id) const =0
Implemented by child classes to fetch a variable sized property.
virtual bool prop_exists(prop_id id) const =0
Indicates the existance of a given property on this object.
T read_prop(prop_id id) const
Read a property as a given type.
Definition object.h:188
virtual prop_type get_prop_type(prop_id id) const =0
Get the property type of a given prop_id.
virtual ~const_property_object()
Definition object.h:96
virtual byte get_value_1(prop_id id) const =0
Implemented by child classes to fetch a 1 byte sized property.
virtual size_t size(prop_id id) const =0
Returns the total size of a variable length property.
virtual ulonglong get_value_8(prop_id id) const =0
Implemented by child classes to fetch a 8 byte sized property.
virtual std::vector< prop_id > get_prop_list() const =0
Get a list of all properties on this object.
std::vector< T > read_prop_array(prop_id id) const
Read a property as an array of the given type.
Definition object.h:224
Defines a stream device for a heap allocation for use by boost iostream.
Definition heap.h:59
std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way)
Move the current position in the stream.
Definition heap.h:675
std::streamsize read(char *pbuffer, std::streamsize n)
Read data from this node into the buffer at the current position.
Definition heap.h:657
Defines a stream device which can wrap one of the two prop sources.
Definition object.h:56
std::streamsize read(char *pbuffer, std::streamsize n)
Read data from this node into the buffer at the current position.
Definition object.h:59
hnid_stream_device(const node_stream_device &node_device)
Wrap a node_stream_device.
Definition object.h:68
hnid_stream_device(const hid_stream_device &hid_device)
Wrap a hid_stream_device.
Definition object.h:66
std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way)
Move the current position in the stream.
Definition object.h:62
Defines a stream device for a node for use by boost iostream.
Definition node.h:261
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
The exceptions used by pstsdk.
boost::iostreams::stream< hnid_stream_device > prop_stream
The actual property stream, defined using the boost iostream library and the hnid_stream_device.
Definition object.h:81
boost::uint64_t ulonglong
Definition primitives.h:70
boost::uint8_t byte
Definition primitives.h:72
boost::uint32_t ulong
Definition primitives.h:68
boost::uint16_t ushort
Definition primitives.h:73
ushort prop_id
Definition primitives.h:93
prop_type
The different property types as defined by MAPI.
Definition primitives.h:292
@ prop_type_mv_string
Definition primitives.h:313
@ prop_type_apptime
VT_DATE.
Definition primitives.h:305
@ prop_type_string
Definition primitives.h:312
@ prop_type_mv_apptime
Definition primitives.h:306
time_t filetime_to_time_t(ulonglong filetime)
Convert from a filetime to time_t.
Definition util.h:208
std::wstring bytes_to_wstring(const std::vector< byte > &bytes)
Convert an array of bytes to a std::wstring.
Definition util.h:280
time_t vt_date_to_time_t(double vt_time)
Convert from a VT_DATE to a time_t.
Definition util.h:222
std::string bytes_to_string(const std::vector< byte > &bytes)
Convert an array of bytes to a std::wstring.
Definition util.h:310
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
Node and Block definitions.
Primitive structures defined by MS-PST and MAPI.
Multi-valued, variable length property TOC.
Definition disk.h:1452
General utility functions and classes.