1 /* 2 * Copyright (C) 2001-2012 Jacek Sieka, arnetheduck on gmail point com 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 */ 18 19 #pragma once 20 21 #ifdef _WIN32 22 # define PATH_SEPARATOR '\\' 23 # define PATH_SEPARATOR_STR "\\" 24 #else 25 # define PATH_SEPARATOR '/' 26 # define PATH_SEPARATOR_STR "/" 27 #endif 28 29 #include <sys/stat.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <unistd.h> 33 #include <cstdlib> 34 #include <vector> 35 #include <functional> 36 #include <algorithm> 37 #include <map> 38 #include "Text.h" 39 40 extern "C" int _nl_msg_cat_cntr; 41 42 namespace dcpp { 43 44 template<typename T, bool flag> struct ReferenceSelector { 45 typedef T ResultType; 46 }; 47 template<typename T> struct ReferenceSelector<T,true> { 48 typedef const T& ResultType; 49 }; 50 51 template<typename T> class IsOfClassType { 52 public: 53 template<typename U> static char check(int U::*); 54 template<typename U> static float check(...); 55 public: 56 enum { Result = sizeof(check<T>(0)) }; 57 }; 58 59 template<typename T> struct TypeTraits { 60 typedef IsOfClassType<T> ClassType; 61 typedef ReferenceSelector<T, ((ClassType::Result == 1) || (sizeof(T) > sizeof(char*)) ) > Selector; 62 typedef typename Selector::ResultType ParameterType; 63 }; 64 65 #define GETSET(type, name, name2) \ 66 private: type name; \ 67 public: TypeTraits<type>::ParameterType get##name2() const { return name; } \ 68 void set##name2(TypeTraits<type>::ParameterType a##name2) { name = a##name2; } 69 70 #define LIT(x) x, (sizeof(x)-1) 71 72 /** Evaluates op(pair<T1, T2>.first, compareTo) */ 73 template<class T1, class T2, class op = std::equal_to<T1> > 74 class CompareFirst { 75 public: 76 CompareFirst(const T1& compareTo) : a(compareTo) { } 77 bool operator()(const pair<T1, T2>& p) { return op()(p.first, a); } 78 private: 79 CompareFirst& operator=(const CompareFirst&); 80 const T1& a; 81 }; 82 83 /** Evaluates op(pair<T1, T2>.second, compareTo) */ 84 template<class T1, class T2, class op = std::equal_to<T2> > 85 class CompareSecond { 86 public: 87 CompareSecond(const T2& compareTo) : a(compareTo) { } 88 bool operator()(const pair<T1, T2>& p) { return op()(p.second, a); } 89 private: 90 CompareSecond& operator=(const CompareSecond&); 91 const T2& a; 92 }; 93 94 /** 95 * Compares two values 96 * @return -1 if v1 < v2, 0 if v1 == v2 and 1 if v1 > v2 97 */ 98 template<typename T1> 99 inline int compare(const T1& v1, const T1& v2) { return (v1 < v2) ? -1 : ((v1 == v2) ? 0 : 1); } 100 101 template<typename T1> inline double fraction(T1 a, T1 b) { return static_cast<double>(a) / b; } 102 103 class Util 104 { 105 public: 106 static tstring emptyStringT; 107 static string emptyString; 108 static wstring emptyStringW; 109 110 enum Paths { 111 /** Global configuration */ 112 PATH_GLOBAL_CONFIG, 113 /** Per-user configuration (queue, favorites, ...) */ 114 PATH_USER_CONFIG, 115 /** Per-user local data (cache, temp files, ...) */ 116 PATH_USER_LOCAL, 117 /** Various resources (help files etc) */ 118 PATH_RESOURCES, 119 /** Translations */ 120 PATH_LOCALE, 121 /** Default download location */ 122 PATH_DOWNLOADS, 123 /** Default file list location */ 124 PATH_FILE_LISTS, 125 /** Default hub list cache */ 126 PATH_HUB_LISTS, 127 /** Where the notepad file is stored */ 128 PATH_NOTEPAD, 129 PATH_LAST 130 }; 131 132 typedef std::map<Util::Paths, std::string> PathsMap; 133 static void initialize(PathsMap pathOverrides = PathsMap()); 134 135 /** Path of temporary storage */ 136 static string getTempPath() { 137 #ifdef _WIN32 138 TCHAR buf[MAX_PATH + 1]; 139 DWORD x = GetTempPath(MAX_PATH, buf); 140 return Text::fromT(tstring(buf, x)); 141 #else 142 return "/tmp/"; 143 #endif 144 } 145 146 /** Path of configuration files */ 147 static const string& getPath(Paths path) { return paths[path]; } 148 149 /** Migrate from pre-localmode config location */ 150 static void migrate(const string& file); 151 152 /** */ 153 static string getLoginName(); 154 155 /** Path of file lists */ 156 static string getListPath() { return getPath(PATH_FILE_LISTS); } 157 /** Path of hub lists */ 158 static string getHubListsPath() { return getPath(PATH_HUB_LISTS); } 159 /** Notepad filename */ 160 static string getNotepadFile() { return getPath(PATH_NOTEPAD); } 161 162 static string translateError(int aError); 163 164 static string getFilePath(const string& path, char separator = PATH_SEPARATOR) { 165 string::size_type i = path.rfind(separator); 166 return (i != string::npos) ? path.substr(0, i + 1) : path; 167 } 168 static string getFileName(const string& path, char separator = PATH_SEPARATOR) { 169 string::size_type i = path.rfind(separator); 170 return (i != string::npos) ? path.substr(i + 1) : path; 171 } 172 static string getFileExt(const string& path) { 173 string::size_type i = path.rfind('.'); 174 return (i != string::npos) ? path.substr(i) : Util::emptyString; 175 } 176 static string getLastDir(const string& path, char separator = PATH_SEPARATOR) { 177 string::size_type i = path.rfind(separator); 178 if(i == string::npos) 179 return Util::emptyString; 180 string::size_type j = path.rfind(separator, i-1); 181 return (j != string::npos) ? path.substr(j+1, i-j-1) : path; 182 } 183 184 static wstring getFilePath(const wstring& path) { 185 wstring::size_type i = path.rfind(PATH_SEPARATOR); 186 return (i != wstring::npos) ? path.substr(0, i + 1) : path; 187 } 188 static wstring getFileName(const wstring& path) { 189 wstring::size_type i = path.rfind(PATH_SEPARATOR); 190 return (i != wstring::npos) ? path.substr(i + 1) : path; 191 } 192 static wstring getFileExt(const wstring& path) { 193 wstring::size_type i = path.rfind('.'); 194 return (i != wstring::npos) ? path.substr(i) : Util::emptyStringW; 195 } 196 static wstring getLastDir(const wstring& path) { 197 wstring::size_type i = path.rfind(PATH_SEPARATOR); 198 if(i == wstring::npos) 199 return Util::emptyStringW; 200 wstring::size_type j = path.rfind(PATH_SEPARATOR, i-1); 201 return (j != wstring::npos) ? path.substr(j+1, i-j-1) : path; 202 } 203 204 template<typename string_t> 205 static void replace(const string_t& search, const string_t& replacement, string_t& str) { 206 typename string_t::size_type i = 0; 207 while((i = str.find(search, i)) != string_t::npos) { 208 str.replace(i, search.size(), replacement); 209 i += replacement.size(); 210 } 211 } 212 template<typename string_t> 213 static inline void replace(const typename string_t::value_type* search, const typename string_t::value_type* replacement, string_t& str) { 214 replace(string_t(search), string_t(replacement), str); 215 } 216 217 static void decodeUrl(const string& aUrl, string& protocol, string& host, uint16_t& port, string& path, string& query, string& fragment); 218 static std::map<string, string> decodeQuery(const string& query); 219 static string validateFileName(string aFile, const string& badCharsExtra = ""); 220 static bool checkExtension(const string& tmp); 221 static string cleanPathChars(string aNick); 222 static string addBrackets(const string& s); 223 224 static string formatBytes(const string& aString) { return formatBytes(toInt64(aString)); } 225 226 static string getShortTimeString(time_t t = time(NULL) ); 227 228 static string getTimeString(); 229 static string toAdcFile(const string& file); 230 static string toNmdcFile(const string& file); 231 232 static string formatBytes(int64_t aBytes); 233 234 static string formatExactSize(int64_t aBytes); 235 static time_t getStartTime() { return startTime; } 236 static time_t getUpTime() { return time(NULL) - getStartTime(); } 237 static string formatSeconds(int64_t aSec) { 238 char buf[64]; 239 snprintf(buf, sizeof(buf), "%01lu:%02d:%02d", (unsigned long)(aSec / (60*60)), (int)((aSec / 60) % 60), (int)(aSec % 60)); 240 return buf; 241 } 242 243 static string formatParams(const string& msg, const StringMap& params, bool filter); 244 static string formatTime(const string &msg, const time_t t); 245 246 static inline int64_t roundDown(int64_t size, int64_t blockSize) { 247 return ((size + blockSize / 2) / blockSize) * blockSize; 248 } 249 250 static inline int64_t roundUp(int64_t size, int64_t blockSize) { 251 return ((size + blockSize - 1) / blockSize) * blockSize; 252 } 253 254 static inline int roundDown(int size, int blockSize) { 255 return ((size + blockSize / 2) / blockSize) * blockSize; 256 } 257 258 static inline int roundUp(int size, int blockSize) { 259 return ((size + blockSize - 1) / blockSize) * blockSize; 260 } 261 262 263 static int64_t toInt64(const string& aString) { 264 #ifdef _WIN32 265 return _atoi64(aString.c_str()); 266 #else 267 #ifndef __HAIKU__ 268 return strtoq(aString.c_str(), (char **)NULL, 10); 269 #else 270 return strtoll(aString.c_str(), (char **)NULL, 10); 271 #endif 272 #endif 273 } 274 275 static int toInt(const string& aString) { 276 return atoi(aString.c_str()); 277 } 278 static uint32_t toUInt32(const string& str) { 279 return toUInt32(str.c_str()); 280 } 281 static uint32_t toUInt32(const char* c) { 282 #ifdef _MSC_VER 283 /* 284 * MSVC's atoi returns INT_MIN/INT_MAX if out-of-range; hence, a number 285 * between INT_MAX and UINT_MAX can't be converted back to uint32_t. 286 */ 287 uint32_t ret = atoi(c); 288 if(errno == ERANGE) 289 return (uint32_t)_atoi64(c); 290 return ret; 291 #else 292 return (uint32_t)atoi(c); 293 #endif 294 } 295 296 static unsigned toUInt(const string& s) { 297 if(s.empty()) 298 return 0; 299 int ret = toInt(s); 300 if(ret < 0) 301 return 0; 302 return ret; 303 } 304 305 static double toDouble(const string& aString) { 306 // Work-around for atof and locales... 307 lconv* lv = localeconv(); 308 string::size_type i = aString.find_last_of(".,"); 309 if(i != string::npos && aString[i] != lv->decimal_point[0]) { 310 string tmp(aString); 311 tmp[i] = lv->decimal_point[0]; 312 return atof(tmp.c_str()); 313 } 314 return atof(aString.c_str()); 315 } 316 317 static float toFloat(const string& aString) { 318 return (float)toDouble(aString); 319 } 320 321 static string toString(short val) { 322 char buf[8]; 323 snprintf(buf, sizeof(buf), "%d", (int)val); 324 return buf; 325 } 326 static string toString(unsigned short val) { 327 char buf[8]; 328 snprintf(buf, sizeof(buf), "%u", (unsigned int)val); 329 return buf; 330 } 331 static string toString(int val) { 332 char buf[16]; 333 snprintf(buf, sizeof(buf), "%d", val); 334 return buf; 335 } 336 static string toString(unsigned int val) { 337 char buf[16]; 338 snprintf(buf, sizeof(buf), "%u", val); 339 return buf; 340 } 341 static string toString(long val) { 342 char buf[32]; 343 snprintf(buf, sizeof(buf), "%ld", val); 344 return buf; 345 } 346 static string toString(unsigned long val) { 347 char buf[32]; 348 snprintf(buf, sizeof(buf), "%lu", val); 349 return buf; 350 } 351 static string toString(long long val) { 352 char buf[32]; 353 snprintf(buf, sizeof(buf), I64_FMT, val); 354 return buf; 355 } 356 static string toString(unsigned long long val) { 357 char buf[32]; 358 snprintf(buf, sizeof(buf), U64_FMT, val); 359 return buf; 360 } 361 static string toString(double val) { 362 char buf[16]; 363 snprintf(buf, sizeof(buf), "%0.2f", val); 364 return buf; 365 } 366 367 template<typename string_t> 368 static string_t toString(const string_t& sep, const std::vector<string_t>& lst) { 369 string_t ret; 370 for(typename std::vector<string_t>::const_iterator i = lst.begin(), iend = lst.end(); i != iend; ++i) { 371 ret += *i; 372 if(i + 1 != iend) 373 ret += sep; 374 } 375 return ret; 376 } 377 template<typename string_t> 378 static inline string_t toString(const typename string_t::value_type* sep, const std::vector<string_t>& lst) { 379 return toString(string_t(sep), lst); 380 } 381 static string toString(const string& sep, const StringList& lst); 382 static string toString(const StringList& lst); 383 384 static string toHexEscape(char val) { 385 char buf[sizeof(int)*2+1+1]; 386 snprintf(buf, sizeof(buf), "%%%X", val&0x0FF); 387 return buf; 388 } 389 static char fromHexEscape(const string& aString) { 390 unsigned int res = 0; 391 sscanf(aString.c_str(), "%X", &res); 392 return static_cast<char>(res); 393 } 394 395 template<typename T> 396 static T& intersect(T& t1, const T& t2) { 397 for(typename T::iterator i = t1.begin(); i != t1.end();) { 398 if(std::find_if(t2.begin(), t2.end(), bind1st(std::equal_to<typename T::value_type>(), *i)) == t2.end()) 399 i = t1.erase(i); 400 else 401 ++i; 402 } 403 return t1; 404 } 405 406 static string encodeURI(const string& /*aString*/, bool reverse = false); 407 static string getLocalIp(unsigned short sa_family = AF_UNSPEC); 408 static std::vector<string> getLocalIPs(unsigned short sa_family = AF_UNSPEC); 409 static bool isPrivateIp(string const& ip); 410 static string formatAdditionalInfo(const std::string& aIp, bool sIp, bool sCC); 411 /** 412 * Case insensitive substring search. 413 * @return First position found or string::npos 414 */ 415 static string::size_type findSubString(const string& aString, const string& aSubString, string::size_type start = 0) noexcept; 416 static wstring::size_type findSubString(const wstring& aString, const wstring& aSubString, wstring::size_type start = 0) noexcept; 417 418 /* Utf-8 versions of strnicmp and stricmp, unicode char code order (!) */ 419 static int stricmp(const char* a, const char* b); 420 static int strnicmp(const char* a, const char* b, size_t n); 421 422 static int stricmp(const wchar_t* a, const wchar_t* b) { 423 while(*a && Text::toLower(*a) == Text::toLower(*b)) 424 ++a, ++b; 425 return ((int)Text::toLower(*a)) - ((int)Text::toLower(*b)); 426 } 427 static int strnicmp(const wchar_t* a, const wchar_t* b, size_t n) { 428 while(n && *a && Text::toLower(*a) == Text::toLower(*b)) 429 --n, ++a, ++b; 430 431 return n == 0 ? 0 : ((int)Text::toLower(*a)) - ((int)Text::toLower(*b)); 432 } 433 434 static int stricmp(const string& a, const string& b) { return stricmp(a.c_str(), b.c_str()); } 435 static int strnicmp(const string& a, const string& b, size_t n) { return strnicmp(a.c_str(), b.c_str(), n); } 436 static int stricmp(const wstring& a, const wstring& b) { return stricmp(a.c_str(), b.c_str()); } 437 static int strnicmp(const wstring& a, const wstring& b, size_t n) { return strnicmp(a.c_str(), b.c_str(), n); } 438 439 static int strcmp(const wchar_t* a, const wchar_t* b) { 440 while(*a && (*a) == (*b)) 441 ++a, ++b; 442 return ((int)(*a)) - ((int)(*b)); 443 } 444 static int strncmp(const wchar_t* a, const wchar_t* b, size_t n) { 445 while(n && *a && (*a) == (*b)) 446 --n, ++a, ++b; 447 448 return n == 0 ? 0 : ((int)(*a)) - ((int)(*b)); 449 } 450 451 static int strcmp(const wstring& a, const wstring& b) { return strcmp(a.c_str(), b.c_str()); } 452 static int strncmp(const wstring& a, const wstring& b, size_t n) { return strncmp(a.c_str(), b.c_str(), n); } 453 454 static string getIpCountry (string IP); 455 456 static void setLang(const string& lang) { 457 if(!lang.empty()) 458 #ifdef _WIN32 459 putenv((char *)string("LANGUAGE=" + lang).c_str()); 460 #else 461 setenv ("LANGUAGE", lang.c_str(), 1); 462 #endif 463 /* Make change known. */ 464 { 465 ++_nl_msg_cat_cntr; 466 } 467 } 468 469 static bool getAway(); 470 static void setAway(bool aAway); 471 static void switchAway(); 472 473 static bool getManualAway() { return manualAway; } 474 static void setManualAway(bool aManualAway) { manualAway = aManualAway; } 475 476 static string getAwayMessage(); 477 static void setAwayMessage(const string& aMsg) { awayMsg = aMsg; } 478 static bool fileExists(const string &aFile); 479 static uint32_t rand(); 480 static uint32_t rand(uint32_t high) { return rand() % high; } 481 static uint32_t rand(uint32_t low, uint32_t high) { return rand(high-low) + low; } 482 static double randd() { return ((double)rand()) / ((double)0xffffffff); } 483 484 static void parseIpPort(const string &aIpPort, string &ip, uint16_t &port); 485 private: 486 /** In local mode, all config and temp files are kept in the same dir as the executable */ 487 static bool localMode; 488 489 static string paths[PATH_LAST]; 490 491 static bool away; 492 static bool manualAway; 493 static string awayMsg; 494 static time_t awayTime; 495 static time_t startTime; 496 typedef std::map<uint32_t, uint16_t> CountryList; 497 typedef CountryList::iterator CountryIter; 498 499 static CountryList countries; 500 501 static void loadBootConfig(); 502 static string formatBytes(int64_t aBytes, uint8_t base); 503 }; 504 505 /** Case sensitive hash function for strings */ 506 struct CaseStringHash { 507 size_t operator()(const string* s) const { 508 return operator()(*s); 509 } 510 511 size_t operator()(const string& s) const { 512 size_t x = 0; 513 const char* end = s.data() + s.size(); 514 for(const char* str = s.data(); str < end; ) { 515 wchar_t c = 0; 516 int n = Text::utf8ToWc(str, c); 517 if(n < 0) { 518 x = x*32 - x + '_'; 519 str += abs(n); 520 } else { 521 x = x*32 - x + (size_t)(c); 522 str += n; 523 } 524 } 525 return x; 526 } 527 528 size_t operator()(const wstring* s) const { 529 return operator()(*s); 530 } 531 size_t operator()(const wstring& s) const { 532 size_t x = 0; 533 const wchar_t* y = s.data(); 534 wstring::size_type j = s.size(); 535 for(wstring::size_type i = 0; i < j; ++i) { 536 x = x*31 + (size_t)(y[i]); 537 } 538 return x; 539 } 540 541 bool operator()(const string* a, const string* b) const { 542 return ::strcmp((*a).c_str(), (*b).c_str()) < 0; 543 } 544 bool operator()(const string& a, const string& b) const { 545 return ::strcmp(a.c_str(), b.c_str()) < 0; 546 } 547 bool operator()(const wstring* a, const wstring* b) const { 548 return Util::strcmp(*a, *b) < 0; 549 } 550 bool operator()(const wstring& a, const wstring& b) const { 551 return Util::strcmp(a, b) < 0; 552 } 553 }; 554 555 /** Case sensitive string comparison */ 556 struct CaseStringEq { 557 bool operator()(const string* a, const string* b) const { 558 return a == b || ::strcmp((*a).c_str(), (*b).c_str()) == 0; 559 } 560 bool operator()(const string& a, const string& b) const { 561 return ::strcmp(a.c_str(), b.c_str()) == 0; 562 } 563 bool operator()(const wstring* a, const wstring* b) const { 564 return a == b || Util::strcmp(*a, *b) == 0; 565 } 566 bool operator()(const wstring& a, const wstring& b) const { 567 return Util::strcmp(a, b) == 0; 568 } 569 }; 570 571 /** Case sensitive string ordering */ 572 struct CaseStringLess { 573 bool operator()(const string* a, const string* b) const { 574 return ::strcmp((*a).c_str(), (*b).c_str()) < 0; 575 } 576 bool operator()(const string& a, const string& b) const { 577 return ::strcmp(a.c_str(), b.c_str()) < 0; 578 } 579 bool operator()(const wstring* a, const wstring* b) const { 580 return Util::strcmp(*a, *b) < 0; 581 } 582 bool operator()(const wstring& a, const wstring& b) const { 583 return Util::strcmp(a, b) < 0; 584 } 585 }; 586 587 } // namespace dcpp 588