PST File Format SDK v0.4
Loading...
Searching...
No Matches
util.h
Go to the documentation of this file.
1
9
10#ifndef PSTSDK_UTIL_UTIL_H
11#define PSTSDK_UTIL_UTIL_H
12
13#include <cstdio>
14#include <cstdlib>
15#include <time.h>
16#include <memory>
17#include <string>
18#include <vector>
19#include <boost/utility.hpp>
20
21#include "pstsdk/util/errors.h"
23
24#if defined(_WIN32) || defined(__MINGW32__)
25#define NOMINMAX
26#include <windows.h>
27#endif
28
29namespace pstsdk
30{
31
38class file : private boost::noncopyable
39{
40public:
41 // TODO
42 file() {
43 m_pfile = nullptr;
44 m_filename = L"";
45 }
46
50 file(const std::wstring& filename);
51
53 ~file();
54
60 virtual size_t read(std::vector<byte>& buffer, ulonglong offset) const;
61
63
69 virtual size_t write(const std::vector<byte>& buffer, ulonglong offset);
71
72private:
73 std::wstring m_filename;
74 FILE * m_pfile;
75};
76
77
86time_t filetime_to_time_t(ulonglong filetime);
87
96ulonglong time_t_to_filetime(time_t time);
97
106time_t vt_date_to_time_t(double vt_time);
107
116double time_t_to_vt_date(time_t time);
117
123bool test_bit(const byte* pbytes, ulong bit);
124
129std::string bytes_to_string(const std::vector<byte> &bytes);
130
135std::wstring bytes_to_wstring(const std::vector<byte> &bytes);
136
141std::vector<byte> wstring_to_bytes(const std::wstring &wstr);
142
143} // end pstsdk namespace
144
145inline pstsdk::file::file(const std::wstring& filename)
146: m_filename(filename)
147{
148 const char* mode = "rb";
149
150#ifdef _MSC_VER
151 errno_t err = fopen_s(&m_pfile, std::string(filename.begin(), filename.end()).c_str(), mode);
152 if(err != 0)
153 m_pfile = NULL;
154#else
155 m_pfile = fopen(std::string(filename.begin(), filename.end()).c_str(), mode);
156#endif
157 if(m_pfile == NULL)
158 throw std::runtime_error("fopen failed");
159}
160
162{
163 if (!m_pfile) return;
164 fflush(m_pfile);
165 fclose(m_pfile);
166}
167
168inline size_t pstsdk::file::read(std::vector<byte>& buffer, ulonglong offset) const
169{
170#ifdef _MSC_VER
171 if(_fseeki64(m_pfile, offset, SEEK_SET) != 0)
172#else
173 if(fseek(m_pfile, offset, SEEK_SET) != 0)
174#endif
175 {
176 throw std::out_of_range("fseek failed");
177 }
178
179 size_t read = fread(&buffer[0], 1, buffer.size(), m_pfile);
180
181 if(read != buffer.size())
182 throw std::out_of_range("fread failed");
183
184 return read;
185}
186
188inline size_t pstsdk::file::write(const std::vector<byte>& buffer, ulonglong offset)
189{
190#ifdef _MSC_VER
191 if(_fseeki64(m_pfile, offset, SEEK_SET) != 0)
192#else
193 if(fseek(m_pfile, offset, SEEK_SET) != 0)
194#endif
195 {
196 throw std::out_of_range("fseek failed");
197 }
198
199 size_t write = fwrite(&buffer[0], 1, buffer.size(), m_pfile);
200
201 if(write != buffer.size())
202 throw std::out_of_range("fwrite failed");
203
204 return write;
205}
207
209{
210 const ulonglong jan1970 = 116444736000000000ULL;
211
212 return (filetime - jan1970) / 10000000;
213}
214
216{
217 const ulonglong jan1970 = 116444736000000000ULL;
218
219 return (time * 10000000) + jan1970;
220}
221
223{
224 throw not_implemented("vt_date_to_time_t");
225}
226
228{
229 throw not_implemented("vt_date_to_time_t");
230}
231
232inline bool pstsdk::test_bit(const byte* pbytes, ulong bit)
233{
234 return (*(pbytes + (bit >> 3)) & (0x80 >> (bit & 7))) != 0;
235}
236
237#if defined(_WIN32) || defined(__MINGW32__)
238
239// We know that std::wstring is always UCS-2LE on Windows.
240
241inline std::wstring pstsdk::bytes_to_wstring(const std::vector<byte> &bytes)
242{
243 if(bytes.size() == 0)
244 return std::wstring();
245
246 return std::wstring(reinterpret_cast<const wchar_t *>(&bytes[0]), bytes.size()/sizeof(wchar_t));
247}
248
249inline std::vector<pstsdk::byte> pstsdk::wstring_to_bytes(const std::wstring &wstr)
250{
251 if(wstr.size() == 0)
252 return std::vector<byte>();
253
254 const byte *begin = reinterpret_cast<const byte *>(&wstr[0]);
255 return std::vector<byte>(begin, begin + wstr.size()*sizeof(wchar_t));
256}
257
258// Assume UCS-2LE, use WideCharToMultiByte to support pre Win 10
259inline std::string pstsdk::bytes_to_string(const std::vector<byte> &bytes)
260{
261 // Do the wstr cast and use c_str to avoid any issues stemming from null terminator
262 std::wstring ws = bytes_to_wstring(bytes);
263 size_t utf8_sz = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), ws.size(), NULL, 0, NULL, NULL);
264
265 std::vector<char> utf8_str(utf8_sz);
266 size_t copied = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), ws.size(), &utf8_str.data()[0], utf8_sz, NULL, NULL);
267
268 if (copied != utf8_sz)
269 throw std::runtime_error("Expected to copy " + std::to_string(utf8_sz) + " bytes but copied " + std::to_string(copied));
270
271 return { utf8_str.begin(), utf8_str.end() };
272}
273
274#else // !(defined(_WIN32) || defined(__MINGW32__))
275
276// We're going to have to do this the hard way, since we don't know how
277// big wchar_t really is, or what encoding it uses.
278#include <iconv.h>
279
280inline std::wstring pstsdk::bytes_to_wstring(const std::vector<byte> &bytes)
281{
282 if(bytes.size() == 0)
283 return std::wstring();
284
285 // Up to one wchar_t for every 2 bytes, if there are no surrogate pairs.
286 if(bytes.size() % 2 != 0)
287 throw std::runtime_error("Cannot interpret odd number of bytes as UTF-16LE");
288 std::wstring out(bytes.size() / 2, L'\0');
289
290 iconv_t cd(::iconv_open("WCHAR_T", "UTF-16LE"));
291 if(cd == (iconv_t)(-1)) {
292 perror("bytes_to_wstring");
293 throw std::runtime_error("Unable to convert from UTF-16LE to wstring");
294 }
295
296 const char *inbuf = reinterpret_cast<const char *>(&bytes[0]);
297 size_t inbytesleft = bytes.size();
298 char *outbuf = reinterpret_cast<char *>(&out[0]);
299 size_t outbytesleft = out.size() * sizeof(wchar_t);
300 size_t result = ::iconv(cd, const_cast<char **>(&inbuf), &inbytesleft, &outbuf, &outbytesleft);
301 ::iconv_close(cd);
302 if(result == (size_t)(-1) || inbytesleft > 0 || outbytesleft % sizeof(wchar_t) != 0)
303 throw std::runtime_error("Failed to convert from UTF-16LE to wstring");
304
305 out.resize(out.size() - (outbytesleft / sizeof(wchar_t)));
306 return out;
307}
308
309// Allows reading wstring props directly into std::string for non-Windows
310inline std::string pstsdk::bytes_to_string(const std::vector<byte> &bytes)
311{
312 if(bytes.size() == 0)
313 return std::string();
314
315 // Up to one wchar_t for every 2 bytes, if there are no surrogate pairs.
316 if(bytes.size() % 2 != 0)
317 throw std::runtime_error("Cannot interpret odd number of bytes as UTF-16LE");
318
319 // Up to 4 bytes out per char
320 std::string out(bytes.size() * 2, L'\0');
321
322 iconv_t cd(::iconv_open("UTF-8", "UTF-16LE"));
323 if(cd == (iconv_t)(-1)) {
324 perror("bytes_to_string");
325 throw std::runtime_error("Unable to convert from UTF-16LE to string");
326 }
327
328 const char *inbuf = reinterpret_cast<const char *>(&bytes[0]);
329 size_t inbytesleft = bytes.size();
330 char *outbuf = reinterpret_cast<char *>(&out[0]);
331 size_t outbytesleft = out.size();
332 size_t result = ::iconv(cd, const_cast<char **>(&inbuf), &inbytesleft, &outbuf, &outbytesleft);
333 ::iconv_close(cd);
334
335 if(result == (size_t)(-1) || inbytesleft > 0)
336 throw std::runtime_error("Failed to convert from UTF-16LE to string");
337
338 out.resize(out.size() - outbytesleft);
339
340 return out;
341}
342
343inline std::vector<pstsdk::byte> pstsdk::wstring_to_bytes(const std::wstring &wstr)
344{
345 if(wstr.size() == 0)
346 return std::vector<byte>();
347
348 // Up to 4 bytes per character if all codepoints are surrogate pairs.
349 std::vector<byte> out(wstr.size() * 4);
350
351 iconv_t cd(::iconv_open("UTF-16LE", "WCHAR_T"));
352 if(cd == (iconv_t)(-1)) {
353 perror("wstring_to_bytes");
354 throw std::runtime_error("Unable to convert from wstring to UTF-16LE");
355 }
356
357 const char *inbuf = reinterpret_cast<const char *>(&wstr[0]);
358 size_t inbytesleft = wstr.size() * sizeof(wchar_t);
359 char *outbuf = reinterpret_cast<char *>(&out[0]);
360 size_t outbytesleft = out.size();
361 size_t result = ::iconv(cd, const_cast<char **>(&inbuf), &inbytesleft, &outbuf, &outbytesleft);
362 ::iconv_close(cd);
363 if(result == (size_t)(-1) || inbytesleft > 0)
364 throw std::runtime_error("Failed to convert from wstring to UTF-16LE");
365
366 out.resize(out.size() - outbytesleft);
367 return out;
368}
369
370#endif // !(defined(_WIN32) || defined(__MINGW32__))
371
372#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
A generic class to read and write to a file.
Definition util.h:39
virtual size_t read(std::vector< byte > &buffer, ulonglong offset) const
Read from the file.
Definition util.h:168
~file()
Close the file.
Definition util.h:161
This function or method has not been implemented.
Definition errors.h:30
The exceptions used by pstsdk.
boost::uint64_t ulonglong
Definition primitives.h:70
boost::uint32_t ulong
Definition primitives.h:68
ulonglong time_t_to_filetime(time_t time)
Convert from a time_t to filetime.
Definition util.h:215
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
double time_t_to_vt_date(time_t time)
Convert from a time_t to a VT_DATE.
Definition util.h:227
time_t vt_date_to_time_t(double vt_time)
Convert from a VT_DATE to a time_t.
Definition util.h:222
bool test_bit(const byte *pbytes, ulong bit)
Test to see if the specified bit in the buffer is set.
Definition util.h:232
std::string bytes_to_string(const std::vector< byte > &bytes)
Convert an array of bytes to a std::wstring.
Definition util.h:310
std::vector< byte > wstring_to_bytes(const std::wstring &wstr)
Convert a std::wstring to an array of bytes.
Definition util.h:343
Contains the definition of all in memory representations of disk structures.
Definition disk.h:19
Primitive structures defined by MS-PST and MAPI.