Fairport
v1.0.38
|
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