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