Fairport  v1.0.38
fairport/util/util.h
Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 #ifndef FAIRPORT_UTIL_UTIL_H
00011 #define FAIRPORT_UTIL_UTIL_H
00012 
00013 #include <cstdio>
00014 #include <time.h>
00015 #include <memory>
00016 #include <vector>
00017 #include <boost/utility.hpp>
00018 
00019 #include "fairport/util/errors.h"
00020 #include "fairport/util/primitives.h"
00021 
00022 namespace fairport
00023 {
00024 
00031 class file : private boost::noncopyable
00032 {
00033 public:
00037     file(const std::wstring& filename);
00038     
00040     ~file();
00041 
00047     size_t read(std::vector<byte>& buffer, ulonglong offset) const;
00048 
00049 private:
00050     std::wstring m_filename;    
00051     FILE * m_pfile;             
00052 };
00053 
00054 
00063 time_t filetime_to_time_t(ulonglong filetime);
00064 
00073 ulonglong time_t_to_filetime(time_t time);
00074 
00083 time_t vt_date_to_time_t(double vt_time);
00084 
00093 double time_t_to_vt_date(time_t time);
00094 
00100 bool test_bit(const byte* pbytes, ulong bit);
00101 
00106 std::wstring codepage_1252_to_wstring(const std::string &cp1252);
00107 
00112 std::wstring bytes_to_wstring(const std::vector<byte> &bytes);
00113 
00118 std::vector<byte> wstring_to_bytes(const std::wstring &wstr);
00119 
00120 } // end fairport namespace
00121 
00122 inline fairport::file::file(const std::wstring& filename)
00123 : m_filename(filename)
00124 {
00125     const char* mode = "rb";
00126 
00127 #ifdef _MSC_VER 
00128     errno_t err = fopen_s(&m_pfile, std::string(filename.begin(), filename.end()).c_str(), mode);
00129     if(err != 0)
00130         m_pfile = NULL;
00131 #else
00132     m_pfile = fopen(std::string(filename.begin(), filename.end()).c_str(), mode);
00133 #endif
00134     if(m_pfile == NULL)
00135         throw std::runtime_error("fopen failed");
00136 }
00137 
00138 inline fairport::file::~file()
00139 {
00140     fflush(m_pfile);
00141     fclose(m_pfile);
00142 }
00143 
00144 inline size_t fairport::file::read(std::vector<byte>& buffer, ulonglong offset) const
00145 {
00146 #ifdef _MSC_VER
00147     if(_fseeki64(m_pfile, offset, SEEK_SET) != 0)
00148 #else
00149     if(fseek(m_pfile, offset, SEEK_SET) != 0)
00150 #endif
00151     {
00152         throw std::out_of_range("fseek failed");
00153     }
00154 
00155     size_t read = fread(&buffer[0], 1, buffer.size(), m_pfile);
00156 
00157     if(read != buffer.size())
00158         throw std::out_of_range("fread failed");
00159 
00160     return read;
00161 }
00162 
00163 inline time_t fairport::filetime_to_time_t(ulonglong filetime)
00164 {
00165     const ulonglong jan1970 = 116444736000000000ULL;
00166 
00167     return (filetime - jan1970) / 10000000;
00168 }
00169 
00170 inline fairport::ulonglong fairport::time_t_to_filetime(time_t time)
00171 {
00172     const ulonglong jan1970 = 116444736000000000ULL;
00173 
00174     return (time * 10000000) + jan1970;
00175 }
00176 
00177 inline time_t fairport::vt_date_to_time_t(double)
00178 {
00179     throw not_implemented("vt_date_to_time_t");
00180 }
00181 
00182 inline double fairport::time_t_to_vt_date(time_t)
00183 {
00184     throw not_implemented("vt_date_to_time_t");
00185 }
00186 
00187 inline bool fairport::test_bit(const byte* pbytes, ulong bit)
00188 {
00189     return (*(pbytes + (bit >> 3)) & (0x80 >> (bit & 7))) != 0;
00190 }
00191 
00192 inline std::wstring fairport::codepage_1252_to_wstring(const std::string &cp1252)
00193 {
00194     // http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit1252.txt
00195     // has a listing of code page 1252 characters and how they map to Unicode.
00196     static const wchar_t specials[32] = {
00197         0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
00198         0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
00199         0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
00200         0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178
00201     };
00202 
00203     std::wstring wstr(cp1252.size(), L'\0');
00204     for (size_t i = 0; i < wstr.size(); ++i) {
00205         unsigned char c(static_cast<unsigned char>(cp1252[i]));
00206         if (0x80 <= c && c < 0xa0)
00207             wstr[i] = specials[c - 0x80];
00208         else
00209             wstr[i] = c;
00210     }
00211     return wstr;
00212 }
00213 
00214 #if defined(_WIN32) || defined(__MINGW32__)
00215 
00216 // We know that std::wstring is always UCS-2LE on Windows.
00217 
00218 inline std::wstring fairport::bytes_to_wstring(const std::vector<byte> &bytes)
00219 {
00220     if(bytes.size() == 0)
00221         return std::wstring();
00222 
00223     return std::wstring(reinterpret_cast<const wchar_t *>(&bytes[0]), bytes.size()/sizeof(wchar_t));
00224 }
00225 
00226 inline std::vector<fairport::byte> fairport::wstring_to_bytes(const std::wstring &wstr)
00227 {
00228     if(wstr.size() == 0)
00229         return std::vector<byte>();
00230 
00231     const byte *begin = reinterpret_cast<const byte *>(&wstr[0]);
00232     return std::vector<byte>(begin, begin + wstr.size()*sizeof(wchar_t));
00233 }
00234 
00235 #else // !(defined(_WIN32) || defined(__MINGW32__))
00236 
00237 // We're going to have to do this the hard way, since we don't know how
00238 // big wchar_t really is, or what encoding it uses.
00239 #include <iconv.h>
00240 
00241 inline std::wstring fairport::bytes_to_wstring(const std::vector<byte> &bytes)
00242 {
00243     if(bytes.size() == 0)
00244         return std::wstring();
00245 
00246     // Up to one wchar_t for every 2 bytes, if there are no surrogate pairs.
00247     if(bytes.size() % 2 != 0)
00248         throw std::runtime_error("Cannot interpret odd number of bytes as UTF-16LE");
00249     std::wstring out(bytes.size() / 2, L'\0');
00250 
00251     iconv_t cd(::iconv_open("WCHAR_T", "UTF-16LE"));
00252     if(cd == (iconv_t)(-1)) {
00253         perror("bytes_to_wstring");
00254         throw std::runtime_error("Unable to convert from UTF-16LE to wstring");
00255     }
00256 
00257     const char *inbuf = reinterpret_cast<const char *>(&bytes[0]);
00258     size_t inbytesleft = bytes.size();
00259     char *outbuf = reinterpret_cast<char *>(&out[0]);
00260     size_t outbytesleft = out.size() * sizeof(wchar_t);
00261     size_t result = ::iconv(cd, const_cast<char **>(&inbuf), &inbytesleft, &outbuf, &outbytesleft);
00262     ::iconv_close(cd);
00263     if(result == (size_t)(-1) || inbytesleft > 0 || outbytesleft % sizeof(wchar_t) != 0)
00264         throw std::runtime_error("Failed to convert from UTF-16LE to wstring");
00265 
00266     out.resize(out.size() - (outbytesleft / sizeof(wchar_t)));
00267     return out;
00268 }
00269 
00270 inline std::vector<fairport::byte> fairport::wstring_to_bytes(const std::wstring &wstr)
00271 {
00272     if(wstr.size() == 0)
00273         return std::vector<byte>();
00274 
00275     // Up to 4 bytes per character if all codepoints are surrogate pairs.
00276     std::vector<byte> out(wstr.size() * 4);
00277 
00278     iconv_t cd(::iconv_open("UTF-16LE", "WCHAR_T"));
00279     if(cd == (iconv_t)(-1)) {
00280         perror("wstring_to_bytes");
00281         throw std::runtime_error("Unable to convert from wstring to UTF-16LE");
00282     }
00283 
00284     const char *inbuf = reinterpret_cast<const char *>(&wstr[0]);
00285     size_t inbytesleft = wstr.size() * sizeof(wchar_t);
00286     char *outbuf = reinterpret_cast<char *>(&out[0]);
00287     size_t outbytesleft = out.size();
00288     size_t result = ::iconv(cd, const_cast<char **>(&inbuf), &inbytesleft, &outbuf, &outbytesleft);
00289     ::iconv_close(cd);
00290     if(result == (size_t)(-1) || inbytesleft > 0)
00291         throw std::runtime_error("Failed to convert from wstring to UTF-16LE");
00292 
00293     out.resize(out.size() - outbytesleft);
00294     return out;
00295 }
00296 
00297 #endif // !(defined(_WIN32) || defined(__MINGW32__))
00298 
00299 #endif