1 #include "stdafx.h"
2 #include "Helper.h"
3 #include "Logger.h"
4 #ifdef WIN32
5 #include "dirent_windows.h"
6 #include <direct.h>
7 #else
8 #include <dirent.h>
9 #include <unistd.h>
10 #endif
11 #if !defined(WIN32)
12 #include <sys/ptrace.h>
13 #endif
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <fstream>
18 #include <math.h>
19 #include <algorithm>
20 #include "../main/localtime_r.h"
21 #include <sstream>
22 #include <openssl/md5.h>
23 #include <chrono>
24 #include <limits.h>
25 #include <cstring>
26
27 #if defined WIN32
28 #include "../msbuild/WindowsHelper.h"
29 #endif
30
31 #include "RFXtrx.h"
32 #include "../hardware/hardwaretypes.h"
33
34 // Includes for SystemUptime()
35 #if defined(__linux__) || defined(__linux) || defined(linux)
36 #include <sys/sysinfo.h>
37 #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
38 #include <time.h>
39 #include <errno.h>
40 #include <sys/sysctl.h>
41 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
42 #include <time.h>
43 #endif
44
45 #if defined(__FreeBSD__) || defined(__DragonFly__)
46 // Check if OpenBSD or DragonFly need that at well? DragonFly - yes.
47 #include <pthread_np.h>
48 #ifndef PTHREAD_MAX_MAMELEN_NP
49 #define PTHREAD_MAX_NAMELEN_NP 32 // Arbitrary
50 #endif
51 #endif
52
53 static unsigned int crc32_tab[] = {
54 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
55 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
56 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
57 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
58 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
59 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
60 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
61 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
62 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
63 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
64 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
65 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
66 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
67 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
68 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
69 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
70 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
71 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
72 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
73 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
74 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
75 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
76 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
77 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
78 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
79 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
80 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
81 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
82 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
83 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
84 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
85 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
86 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
87 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
88 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
89 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
90 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
91 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
92 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
93 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
94 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
95 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
96 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
97 };
98
Crc32(unsigned int crc,const unsigned char * buf,size_t size)99 unsigned int Crc32(unsigned int crc, const unsigned char* buf, size_t size)
100 {
101 const unsigned char* p = buf;
102 crc = crc ^ ~0U;
103 while (size--)
104 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
105 return crc ^ ~0U;
106 }
107
StringSplit(std::string str,const std::string & delim,std::vector<std::string> & results)108 void StringSplit(std::string str, const std::string &delim, std::vector<std::string> &results)
109 {
110 results.clear();
111 size_t cutAt;
112 while( (cutAt = str.find(delim)) != std::string::npos )
113 {
114 results.push_back(str.substr(0,cutAt));
115 str = str.substr(cutAt+ delim.size());
116 }
117 if (!str.empty())
118 {
119 results.push_back(str);
120 }
121 }
122
hexstrtoui64(const std::string & str)123 uint64_t hexstrtoui64(const std::string &str)
124 {
125 uint64_t ul;
126 std::stringstream ss;
127 ss << std::hex << str;
128 ss >> ul;
129 return ul;
130 }
131
ToHexString(const uint8_t * pSource,const size_t length)132 std::string ToHexString(const uint8_t* pSource, const size_t length)
133 {
134 if (pSource == nullptr)
135 return "";
136 std::string ret;
137 char szTmp[10];
138 size_t index = 0;
139 while (index < length)
140 {
141 sprintf(szTmp, "0x%02X", pSource[index]);
142 if (index)
143 ret += " ";
144 ret += szTmp;
145 index++;
146 }
147 return ret;
148 }
149
stdreplace(std::string & inoutstring,const std::string & replaceWhat,const std::string & replaceWithWhat)150 void stdreplace(
151 std::string &inoutstring,
152 const std::string& replaceWhat,
153 const std::string& replaceWithWhat)
154 {
155 size_t pos = 0;
156 while (std::string::npos != (pos = inoutstring.find(replaceWhat, pos)))
157 {
158 inoutstring.replace(pos, replaceWhat.size(), replaceWithWhat);
159 pos += replaceWithWhat.size();
160 }
161 }
162
stdupper(std::string & inoutstring)163 void stdupper(std::string &inoutstring)
164 {
165 for (size_t i = 0; i < inoutstring.size(); ++i)
166 inoutstring[i] = toupper(inoutstring[i]);
167 }
168
stdlower(std::string & inoutstring)169 void stdlower(std::string &inoutstring)
170 {
171 std::transform(inoutstring.begin(), inoutstring.end(), inoutstring.begin(), ::tolower);
172 }
173
stdupper(std::wstring & inoutstring)174 void stdupper(std::wstring& inoutstring)
175 {
176 for (size_t i = 0; i < inoutstring.size(); ++i)
177 inoutstring[i] = towupper(inoutstring[i]);
178 }
179
stdlower(std::wstring & inoutstring)180 void stdlower(std::wstring& inoutstring)
181 {
182 std::transform(inoutstring.begin(), inoutstring.end(), inoutstring.begin(), ::towlower);
183 }
184
GetSerialPorts(bool & bUseDirectPath)185 std::vector<std::string> GetSerialPorts(bool &bUseDirectPath)
186 {
187 bUseDirectPath=false;
188
189 std::vector<std::string> ret;
190 #if defined WIN32
191 //windows
192
193 std::vector<int> ports;
194 std::vector<std::string> friendlyNames;
195 char szPortName[40];
196
197 EnumSerialFromWMI(ports, friendlyNames);
198
199 bool bFoundPort = false;
200 if (!ports.empty())
201 {
202 bFoundPort = true;
203 for (const auto & itt : ports)
204 {
205 sprintf(szPortName, "COM%d", itt);
206 ret.push_back(szPortName);
207 }
208 }
209
210 if (bFoundPort)
211 return ret;
212
213 for (int ii = 1; ii < 255; ii++) // checking ports from COM0 to COM255
214 {
215 sprintf(szPortName, "COM%d", ii);
216
217 TCHAR lpTargetPath[200]; // buffer to store the path of the COMPORTS
218 if (QueryDosDevice(szPortName, (LPSTR)lpTargetPath, sizeof(lpTargetPath)))
219 {
220 ret.push_back(szPortName);
221 }
222 }
223
224 if (bFoundPort)
225 return ret;
226
227 typedef ULONG(__stdcall GETCOMMPORTS)(PULONG, ULONG, PULONG);
228 HMODULE hDLL = LoadLibrary("api-ms-win-core-comm-l1-1-0.dll");
229 if (hDLL != nullptr)
230 {
231 //Running Windows 10+
232 GETCOMMPORTS* pGetCommPorts = reinterpret_cast<GETCOMMPORTS*>(GetProcAddress(hDLL, "GetCommPorts"));
233 if (pGetCommPorts != nullptr)
234 {
235 std::vector<ULONG> intPorts;
236 intPorts.resize(255);
237 ULONG nPortNumbersFound = 0;
238 const ULONG nReturn = pGetCommPorts(&(intPorts[0]), static_cast<ULONG>(intPorts.size()), &nPortNumbersFound);
239 if (nReturn == ERROR_SUCCESS)
240 {
241 for (ULONG i = 0; i < nPortNumbersFound; i++)
242 {
243 sprintf(szPortName, "COM%d", intPorts[i]);
244 ret.push_back(szPortName);
245 }
246 }
247 }
248 FreeLibrary(hDLL);
249 }
250
251 if (bFoundPort)
252 return ret;
253
254 /*
255 //Scan old fashion way (SLOW!)
256 COMMCONFIG cc;
257 DWORD dwSize = sizeof(COMMCONFIG);
258 for (int ii = 0; ii < 256; ii++)
259 {
260 sprintf(szPortName, "COM%d", ii);
261 if (GetDefaultCommConfig(szPortName, &cc, &dwSize))
262 {
263 bFoundPort = true;
264 sprintf(szPortName, "COM%d", ii);
265
266 //Check if we did not already have it
267 bool bFound = false;
268 for (const auto & itt : ret)
269 {
270 if (itt == szPortName)
271 {
272 bFound = true;
273 break;
274 }
275 }
276 if (!bFound)
277 ret.push_back(szPortName); // add port
278 }
279 }
280 // Method 2: CreateFile, slow
281 // ---------
282 if (!bFoundPort) {
283 for (int ii = 0; ii < 256; ii++)
284 {
285 sprintf(szPortName, "\\\\.\\COM%d", ii);
286 bool bSuccess = false;
287 HANDLE hPort = ::CreateFile(szPortName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
288 if (hPort == INVALID_HANDLE_VALUE) {
289 DWORD dwError = GetLastError();
290 //Check to see if the error was because some other app had the port open
291 if (dwError == ERROR_ACCESS_DENIED)
292 bSuccess = TRUE;
293 }
294 else {
295 //The port was opened successfully
296 bSuccess = TRUE;
297 //Don't forget to close the port, since we are going to do nothing with it anyway
298 CloseHandle(hPort);
299 }
300 if (bSuccess) {
301 bFoundPort = true;
302 sprintf(szPortName, "COM%d", ii);
303 ret.push_back(szPortName); // add port
304 }
305 // --------------
306 }
307 }
308 */
309 // Method 3: EnumSerialPortsWindows, often fails
310 // ---------
311 if (!bFoundPort) {
312 std::vector<SerialPortInfo> serialports;
313 EnumSerialPortsWindows(serialports);
314 if (!serialports.empty())
315 {
316 for (const auto & itt : serialports)
317 {
318 ret.push_back(itt.szPortName); // add port
319 }
320 }
321 }
322
323 #else
324 //scan /dev for /dev/ttyUSB* or /dev/ttyS* or /dev/tty.usbserial* or /dev/ttyAMA* or /dev/ttySAC* or /dev/ttymxc*
325 //also scan /dev/serial/by-id/* on Linux
326
327 bool bHaveTtyAMAfree=false;
328 std::string sLine = "";
329 std::ifstream infile;
330
331 infile.open("/boot/cmdline.txt");
332 if (infile.is_open())
333 {
334 if (!infile.eof())
335 {
336 getline(infile, sLine);
337 bHaveTtyAMAfree=(sLine.find("ttyAMA0")==std::string::npos);
338 }
339 }
340
341 DIR *d=NULL;
342 d=opendir("/dev");
343 if (d != NULL)
344 {
345 struct dirent *de=NULL;
346 // Loop while not NULL
347 while ((de = readdir(d)))
348 {
349 // Only consider character devices and symbolic links
350 if ((de->d_type == DT_CHR) || (de->d_type == DT_LNK))
351 {
352 std::string fname = de->d_name;
353 if (fname.find("ttyUSB")!=std::string::npos)
354 {
355 ret.push_back("/dev/" + fname);
356 }
357 else if (fname.find("tty.usbserial")!=std::string::npos)
358 {
359 bUseDirectPath=true;
360 ret.push_back("/dev/" + fname);
361 }
362 else if (fname.find("ttyACM")!=std::string::npos)
363 {
364 bUseDirectPath=true;
365 ret.push_back("/dev/" + fname);
366 }
367 else if (fname.find("ttySAC") != std::string::npos)
368 {
369 bUseDirectPath = true;
370 ret.push_back("/dev/" + fname);
371 }
372 else if (fname.find("ttymxc") != std::string::npos)
373 {
374 bUseDirectPath = true;
375 ret.push_back("/dev/" + fname);
376 }
377 #if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) || defined(__DragonFly__)
378 else if (fname.find("ttyU")!=std::string::npos)
379 {
380 bUseDirectPath=true;
381 ret.push_back("/dev/" + fname);
382 }
383 else if (fname.find("cuaU")!=std::string::npos)
384 {
385 bUseDirectPath=true;
386 ret.push_back("/dev/" + fname);
387 }
388 #endif
389 #ifdef __APPLE__
390 else if (fname.find("cu.")!=std::string::npos)
391 {
392 bUseDirectPath=true;
393 ret.push_back("/dev/" + fname);
394 }
395 #endif
396 if (bHaveTtyAMAfree)
397 {
398 if (fname.find("ttyAMA0")!=std::string::npos)
399 {
400 ret.push_back("/dev/" + fname);
401 bUseDirectPath=true;
402 }
403 // By default, this is the "small UART" on Rasberry 3 boards
404 if (fname.find("ttyS0")!=std::string::npos)
405 {
406 ret.push_back("/dev/" + fname);
407 bUseDirectPath=true;
408 }
409 // serial0 and serial1 are new with Rasbian Jessie
410 // Avoids confusion between Raspberry 2 and 3 boards
411 // More info at http://spellfoundry.com/2016/05/29/configuring-gpio-serial-port-raspbian-jessie-including-pi-3/
412 if (fname.find("serial")!=std::string::npos)
413 {
414 ret.push_back("/dev/" + fname);
415 bUseDirectPath=true;
416 }
417 }
418 }
419 }
420 closedir(d);
421 }
422 //also scan in /dev/usb
423 d=opendir("/dev/usb");
424 if (d != NULL)
425 {
426 struct dirent *de=NULL;
427 // Loop while not NULL
428 while ((de = readdir(d)))
429 {
430 std::string fname = de->d_name;
431 if (fname.find("ttyUSB")!=std::string::npos)
432 {
433 bUseDirectPath=true;
434 ret.push_back("/dev/usb/" + fname);
435 }
436 }
437 closedir(d);
438 }
439
440 #if defined(__linux__) || defined(__linux) || defined(linux)
441 d=opendir("/dev/serial/by-id");
442 if (d != NULL)
443 {
444 struct dirent *de=NULL;
445 // Loop while not NULL
446 while ((de = readdir(d)))
447 {
448 // Only consider symbolic links
449 if (de->d_type == DT_LNK)
450 {
451 std::string fname = de->d_name;
452 ret.push_back("/dev/serial/by-id/" + fname);
453 }
454 }
455 closedir(d);
456 }
457
458 #endif
459 #endif
460 return ret;
461 }
462
file_exist(const char * filename)463 bool file_exist (const char *filename)
464 {
465 struct stat sbuffer;
466 return (stat(filename, &sbuffer) == 0);
467 }
468
CalculateAltitudeFromPressure(double pressure)469 double CalculateAltitudeFromPressure(double pressure)
470 {
471 double seaLevelPressure=101325.0;
472 double altitude = 44330.0 * (1.0 - pow( (pressure / seaLevelPressure), 0.1903));
473 return altitude;
474 }
475
476 /**************************************************************************/
477 /*!
478 Calculates the altitude (in meters) from the specified atmospheric
479 pressure (in hPa), sea-level pressure (in hPa), and temperature (in °C)
480 @param seaLevel Sea-level pressure in hPa
481 @param atmospheric Atmospheric pressure in hPa
482 @param temp Temperature in degrees Celsius
483 */
484 /**************************************************************************/
pressureToAltitude(float seaLevel,float atmospheric,float temp)485 float pressureToAltitude(float seaLevel, float atmospheric, float temp)
486 {
487 /* Hyposometric formula: */
488 /* */
489 /* ((P0/P)^(1/5.257) - 1) * (T + 273.15) */
490 /* h = ------------------------------------- */
491 /* 0.0065 */
492 /* */
493 /* where: h = height (in meters) */
494 /* P0 = sea-level pressure (in hPa) */
495 /* P = atmospheric pressure (in hPa) */
496 /* T = temperature (in °C) */
497 return (((float)pow((seaLevel / atmospheric), 0.190223F) - 1.0F)
498 * (temp + 273.15F)) / 0.0065F;
499 }
500
501 /**************************************************************************/
502 /*!
503 Calculates the sea-level pressure (in hPa) based on the current
504 altitude (in meters), atmospheric pressure (in hPa), and temperature
505 (in °C)
506 @param altitude altitude in meters
507 @param atmospheric Atmospheric pressure in hPa
508 @param temp Temperature in degrees Celsius
509 */
510 /**************************************************************************/
pressureSeaLevelFromAltitude(float altitude,float atmospheric,float temp)511 float pressureSeaLevelFromAltitude(float altitude, float atmospheric, float temp)
512 {
513 /* Sea-level pressure: */
514 /* */
515 /* 0.0065*h */
516 /* P0 = P * (1 - ----------------- ) ^ -5.257 */
517 /* T+0.0065*h+273.15 */
518 /* */
519 /* where: P0 = sea-level pressure (in hPa) */
520 /* P = atmospheric pressure (in hPa) */
521 /* h = altitude (in meters) */
522 /* T = Temperature (in °C) */
523 return atmospheric * (float)pow((1.0F - (0.0065F * altitude) /
524 (temp + 0.0065F * altitude + 273.15F)), -5.257F);
525 }
526
527
stdstring_ltrim(std::string & s)528 std::string &stdstring_ltrim(std::string &s)
529 {
530 while (!s.empty())
531 {
532 if (s[0] != ' ')
533 return s;
534 s = s.substr(1);
535 }
536 // s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
537 return s;
538 }
539
stdstring_rtrim(std::string & s)540 std::string &stdstring_rtrim(std::string &s)
541 {
542 while (!s.empty())
543 {
544 if (s[s.size() - 1] != ' ')
545 return s;
546 s = s.substr(0, s.size() - 1);
547 }
548 //s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
549 return s;
550 }
551
552 // trim from both ends
stdstring_trim(std::string & s)553 std::string &stdstring_trim(std::string &s)
554 {
555 return stdstring_ltrim(stdstring_rtrim(s));
556 }
557
CalculateDewPoint(double temp,int humidity)558 double CalculateDewPoint(double temp, int humidity)
559 {
560 if (humidity==0)
561 return temp;
562 double dew_numer = 243.04*(log(double(humidity)/100.0)+((17.625*temp)/(temp+243.04)));
563 double dew_denom = 17.625-log(double(humidity)/100.0)-((17.625*temp)/(temp+243.04));
564 if (dew_numer==0)
565 dew_numer=1;
566 return dew_numer/dew_denom;
567 }
568
IPToUInt(const std::string & ip)569 uint32_t IPToUInt(const std::string &ip)
570 {
571 int a, b, c, d;
572 uint32_t addr = 0;
573
574 if (sscanf(ip.c_str(), "%d.%d.%d.%d", &a, &b, &c, &d) != 4)
575 return 0;
576
577 addr = a << 24;
578 addr |= b << 16;
579 addr |= c << 8;
580 addr |= d;
581 return addr;
582 }
583
isInt(const std::string & s)584 bool isInt(const std::string &s)
585 {
586 for(size_t i = 0; i < s.length(); i++){
587 if(!isdigit(s[i]))
588 return false;
589 }
590 return true;
591 }
592
sleep_seconds(const long seconds)593 void sleep_seconds(const long seconds)
594 {
595 std::this_thread::sleep_for(std::chrono::seconds(seconds));
596 }
597
sleep_milliseconds(const long milliseconds)598 void sleep_milliseconds(const long milliseconds)
599 {
600 std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
601 }
602
createdir(const char * szDirName,int secattr)603 int createdir(const char *szDirName, int secattr)
604 {
605 int ret = 0;
606 #ifdef WIN32
607 ret = _mkdir(szDirName);
608 #else
609 ret = mkdir(szDirName, secattr);
610 #endif
611 return ret;
612 }
613
mkdir_deep(const char * szDirName,int secattr)614 int mkdir_deep(const char *szDirName, int secattr)
615 {
616 char DirName[260];
617 DirName[0] = 0;
618 const char* p = szDirName;
619 char* q = DirName;
620 int ret = 0;
621 while(*p)
622 {
623 if (('\\' == *p) || ('/' == *p))
624 {
625 if ((p > szDirName) && (':' != *(p-1)))
626 {
627 ret = createdir(DirName, secattr);
628 }
629 }
630 *q++ = *p++;
631 *q = '\0';
632 }
633 if (DirName[0])
634 {
635 ret = createdir(DirName, secattr);
636 }
637 return ret;
638 }
639
RemoveDir(const std::string & dirnames,std::string & errorPath)640 int RemoveDir(const std::string &dirnames, std::string &errorPath)
641 {
642 std::vector<std::string> splitresults;
643 StringSplit(dirnames, "|", splitresults);
644 int returncode = 0;
645 if (!splitresults.empty())
646 {
647 #ifdef WIN32
648 for (size_t i = 0; i < splitresults.size(); i++)
649 {
650 if (!file_exist(splitresults[i].c_str()))
651 continue;
652 size_t s_szLen = strlen(splitresults[i].c_str());
653 if (s_szLen < MAX_PATH)
654 {
655 char deletePath[MAX_PATH + 1];
656 strcpy_s(deletePath, splitresults[i].c_str());
657 deletePath[s_szLen + 1] = '\0'; // SHFILEOPSTRUCT needs an additional null char
658
659 SHFILEOPSTRUCT shfo = { NULL, FO_DELETE, deletePath, NULL, FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMATION, FALSE, NULL, NULL };
660 if (returncode = SHFileOperation(&shfo))
661 {
662 errorPath = splitresults[i];
663 break;
664 }
665 }
666 }
667 #else
668 for (size_t i = 0; i < splitresults.size(); i++)
669 {
670 if (!file_exist(splitresults[i].c_str()))
671 continue;
672 ExecuteCommandAndReturn("rm -rf \"" + splitresults[i] + "\"", returncode);
673 if (returncode)
674 {
675 errorPath = splitresults[i];
676 break;
677 }
678 }
679 #endif
680 }
681 return returncode;
682 }
683
ConvertToCelsius(const double Fahrenheit)684 double ConvertToCelsius(const double Fahrenheit)
685 {
686 return (Fahrenheit-32.0) * 0.5556;
687 }
688
ConvertToFahrenheit(const double Celsius)689 double ConvertToFahrenheit(const double Celsius)
690 {
691 return (Celsius*1.8)+32.0;
692 }
693
RoundDouble(const long double invalue,const short numberOfPrecisions)694 double RoundDouble(const long double invalue, const short numberOfPrecisions)
695 {
696 long long p = (long long) pow(10.0L, numberOfPrecisions);
697 double ret= (long long)(invalue * p + 0.5L) / (double)p;
698 return ret;
699 }
700
ConvertTemperature(const double tValue,const unsigned char tSign)701 double ConvertTemperature(const double tValue, const unsigned char tSign)
702 {
703 if (tSign=='C')
704 return tValue;
705 return RoundDouble(ConvertToFahrenheit(tValue),1);
706 }
707
ExecuteCommandAndReturn(const std::string & szCommand,int & returncode)708 std::vector<std::string> ExecuteCommandAndReturn(const std::string &szCommand, int &returncode)
709 {
710 std::vector<std::string> ret;
711
712 try
713 {
714 FILE *fp;
715
716 /* Open the command for reading. */
717 #ifdef WIN32
718 fp = _popen(szCommand.c_str(), "r");
719 #else
720 fp = popen(szCommand.c_str(), "r");
721 #endif
722 if (fp != NULL)
723 {
724 char path[1035];
725 /* Read the output a line at a time - output it. */
726 while (fgets(path, sizeof(path) - 1, fp) != NULL)
727 {
728 ret.push_back(path);
729 }
730 /* close */
731 #ifdef WIN32
732 returncode = _pclose(fp);
733 #else
734 returncode = pclose(fp);
735 #endif
736 }
737 }
738 catch (...)
739 {
740
741 }
742 return ret;
743 }
744
TimeToString(const time_t * ltime,const _eTimeFormat format)745 std::string TimeToString(const time_t *ltime, const _eTimeFormat format)
746 {
747 struct tm timeinfo;
748 struct timeval tv;
749 std::stringstream sstr;
750 if (ltime == NULL) // current time
751 {
752 #ifdef CLOCK_REALTIME
753 struct timespec ts;
754 if (!clock_gettime(CLOCK_REALTIME, &ts))
755 {
756 tv.tv_sec = ts.tv_sec;
757 tv.tv_usec = ts.tv_nsec / 1000;
758 }
759 else
760 #endif
761 gettimeofday(&tv, NULL);
762 #ifdef WIN32
763 time_t tv_sec = tv.tv_sec;
764 localtime_r(&tv_sec, &timeinfo);
765 #else
766 localtime_r(&tv.tv_sec, &timeinfo);
767 #endif
768 }
769 else
770 localtime_r(ltime, &timeinfo);
771
772 if (format > TF_Time)
773 {
774 //Date
775 sstr << (timeinfo.tm_year + 1900) << "-"
776 << std::setw(2) << std::setfill('0') << (timeinfo.tm_mon + 1) << "-"
777 << std::setw(2) << std::setfill('0') << timeinfo.tm_mday;
778 }
779
780 if (format != TF_Date)
781 {
782 //Time
783 if (format > TF_Time)
784 sstr << " ";
785 sstr
786 << std::setw(2) << std::setfill('0') << timeinfo.tm_hour << ":"
787 << std::setw(2) << std::setfill('0') << timeinfo.tm_min << ":"
788 << std::setw(2) << std::setfill('0') << timeinfo.tm_sec;
789 }
790
791 if (format > TF_DateTime && ltime == NULL)
792 sstr << "." << std::setw(3) << std::setfill('0') << ((int)tv.tv_usec / 1000);
793
794 return sstr.str();
795 }
796
GenerateMD5Hash(const std::string & InputString,const std::string & Salt)797 std::string GenerateMD5Hash(const std::string &InputString, const std::string &Salt)
798 {
799 std::string cstring = InputString + Salt;
800 unsigned char digest[MD5_DIGEST_LENGTH + 1];
801 digest[MD5_DIGEST_LENGTH] = 0;
802 MD5((const unsigned char*)cstring.c_str(), cstring.size(), (unsigned char*)&digest);
803 char mdString[(MD5_DIGEST_LENGTH * 2) + 1];
804 mdString[MD5_DIGEST_LENGTH * 2] = 0;
805 for (int i = 0; i < 16; i++)
806 sprintf(&mdString[i * 2], "%02x", (unsigned int)digest[i]);
807 return mdString;
808 }
809
hsb2rgb(const float hue,const float saturation,const float vlue,int & outR,int & outG,int & outB,const double maxValue)810 void hsb2rgb(const float hue, const float saturation, const float vlue, int &outR, int &outG, int &outB, const double maxValue/* = 100.0 */)
811 {
812 double hh, p, q, t, ff;
813 long i;
814
815 if(saturation <= 0.0) {
816 outR = int(vlue*maxValue);
817 outG = int(vlue*maxValue);
818 outB = int(vlue*maxValue);
819 }
820 hh = hue;
821 if (hh >= 360.0) hh = 0.0;
822 hh /= 60.0;
823 i = (long)hh;
824 ff = hh - i;
825 p = vlue * (1.0 - saturation);
826 q = vlue * (1.0 - (saturation * ff));
827 t = vlue * (1.0 - (saturation * (1.0 - ff)));
828
829 switch (i) {
830 case 0:
831 outR = int(vlue*maxValue);
832 outG = int(t*maxValue);
833 outB = int(p*maxValue);
834 break;
835 case 1:
836 outR = int(q*maxValue);
837 outG = int(vlue*maxValue);
838 outB = int(p*maxValue);
839 break;
840 case 2:
841 outR = int(p*maxValue);
842 outG = int(vlue*maxValue);
843 outB = int(t*maxValue);
844 break;
845
846 case 3:
847 outR = int(p*maxValue);
848 outG = int(q*maxValue);
849 outB = int(vlue*maxValue);
850 break;
851 case 4:
852 outR = int(t*maxValue);
853 outG = int(p*maxValue);
854 outB = int(vlue*maxValue);
855 break;
856 case 5:
857 default:
858 outR = int(vlue*maxValue);
859 outG = int(p*maxValue);
860 outB = int(q*maxValue);
861 break;
862 }
863 }
864
rgb2hsb(const int r,const int g,const int b,float hsbvals[3])865 void rgb2hsb(const int r, const int g, const int b, float hsbvals[3])
866 {
867 float hue, saturation, brightness;
868 if (hsbvals == NULL)
869 return;
870 int cmax = (r > g) ? r : g;
871 if (b > cmax) cmax = b;
872 int cmin = (r < g) ? r : g;
873 if (b < cmin) cmin = b;
874
875 brightness = ((float)cmax) / 255.0f;
876 if (cmax != 0)
877 saturation = ((float)(cmax - cmin)) / ((float)cmax);
878 else
879 saturation = 0;
880 if (saturation == 0)
881 hue = 0;
882 else {
883 float redc = ((float)(cmax - r)) / ((float)(cmax - cmin));
884 float greenc = ((float)(cmax - g)) / ((float)(cmax - cmin));
885 float bluec = ((float)(cmax - b)) / ((float)(cmax - cmin));
886 if (r == cmax)
887 hue = bluec - greenc;
888 else if (g == cmax)
889 hue = 2.0f + redc - bluec;
890 else
891 hue = 4.0f + greenc - redc;
892 hue = hue / 6.0f;
893 if (hue < 0)
894 hue = hue + 1.0f;
895 }
896 hsbvals[0] = hue;
897 hsbvals[1] = saturation;
898 hsbvals[2] = brightness;
899 }
900
is_number(const std::string & s)901 bool is_number(const std::string& s)
902 {
903 std::string::const_iterator it = s.begin();
904 while (it != s.end() && (isdigit(*it) || (*it == '.') || (*it == '-') || (*it == ' ') || (*it == 0x00))) ++it;
905 return !s.empty() && it == s.end();
906 }
907
padLeft(std::string & str,const size_t num,const char paddingChar)908 void padLeft(std::string &str, const size_t num, const char paddingChar)
909 {
910 if (num > str.size())
911 str.insert(0, num - str.size(), paddingChar);
912 }
913
IsLightOrSwitch(const int devType,const int subType)914 bool IsLightOrSwitch(const int devType, const int subType)
915 {
916 bool bIsLightSwitch = false;
917 switch (devType)
918 {
919 case pTypeLighting1:
920 case pTypeLighting2:
921 case pTypeLighting3:
922 case pTypeLighting4:
923 case pTypeLighting5:
924 case pTypeLighting6:
925 case pTypeFan:
926 case pTypeColorSwitch:
927 case pTypeSecurity1:
928 case pTypeSecurity2:
929 case pTypeCurtain:
930 case pTypeBlinds:
931 case pTypeRFY:
932 case pTypeThermostat2:
933 case pTypeThermostat3:
934 case pTypeThermostat4:
935 case pTypeRemote:
936 case pTypeGeneralSwitch:
937 case pTypeHomeConfort:
938 case pTypeFS20:
939 case pTypeHunter:
940 bIsLightSwitch = true;
941 break;
942 case pTypeRadiator1:
943 bIsLightSwitch = (subType == sTypeSmartwaresSwitchRadiator);
944 break;
945 }
946 return bIsLightSwitch;
947 }
948
MStoBeaufort(const float ms)949 int MStoBeaufort(const float ms)
950 {
951 if (ms < 0.3f)
952 return 0;
953 if (ms < 1.5f)
954 return 1;
955 if (ms < 3.3f)
956 return 2;
957 if (ms < 5.5f)
958 return 3;
959 if (ms < 8.0f)
960 return 4;
961 if (ms < 10.8f)
962 return 5;
963 if (ms < 13.9f)
964 return 6;
965 if (ms < 17.2f)
966 return 7;
967 if (ms < 20.7f)
968 return 8;
969 if (ms < 24.5f)
970 return 9;
971 if (ms < 28.4f)
972 return 10;
973 if (ms < 32.6f)
974 return 11;
975 return 12;
976 }
977
FixFolderEnding(std::string & folder)978 void FixFolderEnding(std::string &folder)
979 {
980 #if defined(WIN32)
981 if (folder.at(folder.length() - 1) != '\\')
982 folder += "\\";
983 #else
984 if (folder.at(folder.length() - 1) != '/')
985 folder += "/";
986 #endif
987 }
988
dirent_is_directory(const std::string & dir,struct dirent * ent)989 bool dirent_is_directory(const std::string &dir, struct dirent *ent)
990 {
991 if (ent->d_type == DT_DIR)
992 return true;
993 #ifndef WIN32
994 if (ent->d_type == DT_LNK)
995 return true;
996 if (ent->d_type == DT_UNKNOWN) {
997 std::string fname = dir + "/" + ent->d_name;
998 struct stat st;
999 if (!lstat(fname.c_str(), &st))
1000 return S_ISDIR(st.st_mode);
1001 }
1002 #endif
1003 return false;
1004 }
1005
dirent_is_file(const std::string & dir,struct dirent * ent)1006 bool dirent_is_file(const std::string &dir, struct dirent *ent)
1007 {
1008 if (ent->d_type == DT_REG)
1009 return true;
1010 #ifndef WIN32
1011 if (ent->d_type == DT_UNKNOWN) {
1012 std::string fname = dir + "/" + ent->d_name;
1013 struct stat st;
1014 if (!lstat(fname.c_str(), &st))
1015 return S_ISREG(st.st_mode);
1016 }
1017 #endif
1018 return false;
1019 }
1020
1021 /*!
1022 * List entries of a directory.
1023 * @param entries A string vector containing the result
1024 * @param dir Target directory for listing
1025 * @param bInclDirs Boolean flag to include directories in the result
1026 * @param bInclFiles Boolean flag to include regular files in the result
1027 */
DirectoryListing(std::vector<std::string> & entries,const std::string & dir,bool bInclDirs,bool bInclFiles)1028 void DirectoryListing(std::vector<std::string>& entries, const std::string &dir, bool bInclDirs, bool bInclFiles)
1029 {
1030 DIR *d = NULL;
1031 struct dirent *ent;
1032 if ((d = opendir(dir.c_str())) != NULL)
1033 {
1034 while ((ent = readdir(d)) != NULL) {
1035 std::string name = ent->d_name;
1036 if (bInclDirs && dirent_is_directory(dir, ent) && name != "." && name != "..") {
1037 entries.push_back(name);
1038 continue;
1039 }
1040 if (bInclFiles && dirent_is_file(dir, ent)) {
1041 entries.push_back(name);
1042 continue;
1043 }
1044 }
1045 closedir(d);
1046 }
1047 return;
1048 }
1049
GenerateUserAgent()1050 std::string GenerateUserAgent()
1051 {
1052 int cversion = rand() % 0xFFFF;
1053 int mversion = rand() % 3;
1054 int sversion = rand() % 3;
1055 std::stringstream sstr;
1056 sstr << "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/" << (601 + sversion) << "." << (36+mversion) << " (KHTML, like Gecko) Chrome/" << (53 + mversion) << ".0." << cversion << ".0 Safari/" << (601 + sversion) << "." << (36+sversion);
1057 return sstr.str();
1058 }
1059
MakeHtml(const std::string & txt)1060 std::string MakeHtml(const std::string &txt)
1061 {
1062 std::string sRet = txt;
1063
1064 stdreplace(sRet, "&", "&");
1065 stdreplace(sRet, "\"", """);
1066 stdreplace(sRet, "'", "'");
1067 stdreplace(sRet, "<", "<");
1068 stdreplace(sRet, ">", ">");
1069 stdreplace(sRet, "\r\n", "<br/>");
1070 return sRet;
1071 }
1072
1073 //Prevent against XSS (Cross Site Scripting)
SafeHtml(const std::string & txt)1074 std::string SafeHtml(const std::string &txt)
1075 {
1076 std::string sRet = txt;
1077
1078 stdreplace(sRet, "\"", """);
1079 stdreplace(sRet, "'", "'");
1080 stdreplace(sRet, "<", "<");
1081 stdreplace(sRet, ">", ">");
1082 return sRet;
1083 }
1084
1085
1086 #if defined WIN32
1087 //FILETIME of Jan 1 1970 00:00:00
1088 static const uint64_t epoch = (const uint64_t)(116444736000000000);
1089
gettimeofday(timeval * tp,void * tzp)1090 int gettimeofday( timeval * tp, void * tzp)
1091 {
1092 FILETIME file_time;
1093 SYSTEMTIME system_time;
1094 ULARGE_INTEGER ularge;
1095 GetSystemTime(&system_time);
1096 SystemTimeToFileTime(&system_time, &file_time);
1097 ularge.LowPart = file_time.dwLowDateTime;
1098 ularge.HighPart = file_time.dwHighDateTime;
1099 tp->tv_sec = (long)((ularge.QuadPart - epoch) / 10000000L);
1100 tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
1101 return 0;
1102 }
1103 #endif
1104
getclock(struct timeval * tv)1105 int getclock(struct timeval *tv) {
1106 #ifdef CLOCK_MONOTONIC
1107 struct timespec ts;
1108 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
1109 tv->tv_sec = ts.tv_sec;
1110 tv->tv_usec = ts.tv_nsec / 1000;
1111 return 0;
1112 }
1113 #endif
1114 return gettimeofday(tv, NULL);
1115 }
timeval_subtract(struct timeval * result,struct timeval * x,struct timeval * y)1116 int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) {
1117 /* Perform the carry for the later subtraction by updating y. */
1118 if (x->tv_usec < y->tv_usec) {
1119 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
1120 y->tv_usec -= 1000000 * nsec;
1121 y->tv_sec += nsec;
1122 }
1123 if (x->tv_usec - y->tv_usec > 1000000) {
1124 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
1125 y->tv_usec += 1000000 * nsec;
1126 y->tv_sec -= nsec;
1127 }
1128
1129 /* Compute the time remaining to wait.
1130 tv_usec is certainly positive. */
1131 result->tv_sec = x->tv_sec - y->tv_sec;
1132 result->tv_usec = x->tv_usec - y->tv_usec;
1133
1134 /* Return 1 if result is negative. */
1135 return x->tv_sec < y->tv_sec;
1136 }
1137
1138 const char *szInsecureArgumentOptions[] = {
1139 "import",
1140 "socket",
1141 "process",
1142 "os",
1143 "|",
1144 ";",
1145 "&",
1146 "$",
1147 "<",
1148 ">",
1149 "`",
1150 "\n",
1151 "\r",
1152 NULL
1153 };
1154
IsArgumentSecure(const std::string & arg)1155 bool IsArgumentSecure(const std::string &arg)
1156 {
1157 std::string larg(arg);
1158 std::transform(larg.begin(), larg.end(), larg.begin(), ::tolower);
1159
1160 int ii = 0;
1161 while (szInsecureArgumentOptions[ii] != NULL)
1162 {
1163 if (larg.find(szInsecureArgumentOptions[ii]) != std::string::npos)
1164 return false;
1165 ii++;
1166 }
1167 return true;
1168 }
1169
SystemUptime()1170 uint32_t SystemUptime()
1171 {
1172 #if defined(WIN32)
1173 return static_cast<uint32_t>(GetTickCount64() / 1000u);
1174 #elif defined(__linux__) || defined(__linux) || defined(linux)
1175 struct sysinfo info;
1176 if (sysinfo(&info) != 0)
1177 return -1;
1178 return info.uptime;
1179 #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
1180 struct timeval boottime;
1181 std::size_t len = sizeof(boottime);
1182 int mib[2] = { CTL_KERN, KERN_BOOTTIME };
1183 if (sysctl(mib, 2, &boottime, &len, NULL, 0) < 0)
1184 return -1;
1185 return time(NULL) - boottime.tv_sec;
1186 #elif (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) && defined(CLOCK_UPTIME)
1187 struct timespec ts;
1188 if (clock_gettime(CLOCK_UPTIME, &ts) != 0)
1189 return -1;
1190 return ts.tv_sec;
1191 #else
1192 return 0;
1193 #endif
1194 }
1195
1196 // True random number generator (source: http://www.azillionmonkeys.com/qed/random.html)
1197 static struct
1198 {
1199 int which;
1200 time_t t;
1201 clock_t c;
1202 int counter;
1203 } entropy = { 0, (time_t) 0, (clock_t) 0, 0 };
1204
1205 static unsigned char * p = (unsigned char *) (&entropy + 1);
1206 static int accSeed = 0;
1207
GenerateRandomNumber(const int range)1208 int GenerateRandomNumber(const int range)
1209 {
1210 if (p == ((unsigned char *) (&entropy + 1)))
1211 {
1212 switch (entropy.which)
1213 {
1214 case 0:
1215 entropy.t += time (NULL);
1216 accSeed ^= entropy.t;
1217 break;
1218 case 1:
1219 entropy.c += clock();
1220 break;
1221 case 2:
1222 entropy.counter++;
1223 break;
1224 }
1225 entropy.which = (entropy.which + 1) % 3;
1226 p = (unsigned char *) &entropy.t;
1227 }
1228 accSeed = ((accSeed * (UCHAR_MAX + 2U)) | 1) + (int) *p;
1229 p++;
1230 srand (accSeed);
1231 return (rand() / (RAND_MAX / range));
1232 }
1233
GetDirFilesRecursive(const std::string & DirPath,std::map<std::string,int> & _Files)1234 int GetDirFilesRecursive(const std::string &DirPath, std::map<std::string, int> &_Files)
1235 {
1236 DIR* dir;
1237 if ((dir = opendir(DirPath.c_str())) != NULL)
1238 {
1239 struct dirent *ent;
1240 while ((ent = readdir(dir)) != NULL)
1241 {
1242 if (dirent_is_directory(DirPath, ent))
1243 {
1244 if ((strcmp(ent->d_name, ".") != 0) && (strcmp(ent->d_name, "..") != 0) && (strcmp(ent->d_name, ".svn") != 0))
1245 {
1246 std::string nextdir = DirPath + ent->d_name + "/";
1247 if (GetDirFilesRecursive(nextdir.c_str(), _Files))
1248 {
1249 closedir(dir);
1250 return 1;
1251 }
1252 }
1253 }
1254 else
1255 {
1256 std::string fname = DirPath + ent->d_name;
1257 _Files[fname] = 1;
1258 }
1259 }
1260 }
1261 closedir(dir);
1262 return 0;
1263 }
1264
1265 #ifdef WIN32
1266 // From https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
1267 const DWORD MS_VC_EXCEPTION = 0x406D1388;
1268 #pragma pack(push,8)
1269 typedef struct tagTHREADNAME_INFO
1270 {
1271 DWORD dwType; // Must be 0x1000.
1272 LPCSTR szName; // Pointer to name (in user addr space).
1273 DWORD dwThreadID; // Thread ID (-1=caller thread).
1274 DWORD dwFlags; // Reserved for future use, must be zero.
1275 } THREADNAME_INFO;
1276 #pragma pack(pop)
SetThreadName(const std::thread::native_handle_type & thread,const char * threadName)1277 int SetThreadName(const std::thread::native_handle_type &thread, const char* threadName) {
1278 DWORD dwThreadID = ::GetThreadId( static_cast<HANDLE>( thread ) );
1279 THREADNAME_INFO info;
1280 info.dwType = 0x1000;
1281 info.szName = threadName;
1282 info.dwThreadID = dwThreadID;
1283 info.dwFlags = 0;
1284 #pragma warning(push)
1285 #pragma warning(disable: 6320 6322)
1286 __try{
1287 RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
1288 }
1289 __except (EXCEPTION_EXECUTE_HANDLER){
1290 }
1291 #pragma warning(pop)
1292 return 0;
1293 }
1294 #else
1295 // Based on https://stackoverflow.com/questions/2369738/how-to-set-the-name-of-a-thread-in-linux-pthreads
SetThreadName(const std::thread::native_handle_type & thread,const char * name)1296 int SetThreadName(const std::thread::native_handle_type &thread, const char *name)
1297 {
1298 #if defined(__linux__) || defined(__linux) || defined(linux)
1299 char name_trunc[16];
1300 strncpy(name_trunc, name, sizeof(name_trunc));
1301 name_trunc[sizeof(name_trunc)-1] = '\0';
1302 return pthread_setname_np(thread, name_trunc);
1303 #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
1304 // Not possible to set name of other thread: https://stackoverflow.com/questions/2369738/how-to-set-the-name-of-a-thread-in-linux-pthreads
1305 return 0;
1306 #elif defined(__NetBSD__)
1307 char name_trunc[PTHREAD_MAX_NAMELEN_NP];
1308 strncpy(name_trunc, name, sizeof(name_trunc));
1309 name_trunc[sizeof(name_trunc)-1] = '\0';
1310 return pthread_setname_np(thread, "%s", (void *)name_trunc);
1311 #elif defined(__OpenBSD__)
1312 char name_trunc[PTHREAD_MAX_NAMELEN_NP];
1313 strncpy(name_trunc, name, sizeof(name_trunc));
1314 name_trunc[sizeof(name_trunc)-1] = '\0';
1315 pthread_setname_np(thread, name_trunc);
1316 return 0;
1317 #elif defined(__FreeBSD__) || defined(__DragonFly__)
1318 char name_trunc[PTHREAD_MAX_NAMELEN_NP];
1319 strncpy(name_trunc, name, sizeof(name_trunc));
1320 name_trunc[sizeof(name_trunc)-1] = '\0';
1321 pthread_set_name_np(thread, name_trunc);
1322 return 0;
1323 #endif
1324 }
1325 #endif
1326
1327 #if !defined(WIN32)
IsDebuggerPresent(void)1328 bool IsDebuggerPresent(void)
1329 {
1330 #if defined(__linux__)
1331 // Linux implementation: Search for 'TracerPid:' in /proc/self/status
1332 char buf[4096];
1333
1334 const int status_fd = ::open("/proc/self/status", O_RDONLY);
1335 if (status_fd == -1)
1336 return false;
1337
1338 const ssize_t num_read = ::read(status_fd, buf, sizeof(buf) - 1);
1339 if (num_read <= 0)
1340 return false;
1341
1342 buf[num_read] = '\0';
1343 constexpr char tracerPidString[] = "TracerPid:";
1344 const auto tracer_pid_ptr = ::strstr(buf, tracerPidString);
1345 if (!tracer_pid_ptr)
1346 return false;
1347
1348 for (const char* characterPtr = tracer_pid_ptr + sizeof(tracerPidString) - 1; characterPtr <= buf + num_read; ++characterPtr)
1349 {
1350 if (::isspace(*characterPtr))
1351 continue;
1352 else
1353 return ::isdigit(*characterPtr) != 0 && *characterPtr != '0';
1354 }
1355
1356 return false;
1357 #else
1358 // MacOS X / BSD: TODO
1359 # ifdef _DEBUG
1360 return true;
1361 # else
1362 return false;
1363 # endif
1364 #endif
1365 }
1366 #endif
1367
1368 #if defined(__linux__)
IsWSL(void)1369 bool IsWSL(void)
1370 {
1371 // Detect WSL according to https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364
1372 bool is_wsl = false;
1373
1374 char buf[1024];
1375
1376 int status_fd = open("/proc/sys/kernel/osrelease", O_RDONLY);
1377 if (status_fd == -1)
1378 return is_wsl;
1379
1380 ssize_t num_read = read(status_fd, buf, sizeof(buf) - 1);
1381
1382 if (num_read > 0)
1383 {
1384 buf[num_read] = 0;
1385 is_wsl |= (strstr(buf, "Microsoft") != NULL);
1386 is_wsl |= (strstr(buf, "WSL") != NULL);
1387 }
1388
1389 status_fd = open("/proc/version", O_RDONLY);
1390 if (status_fd == -1)
1391 return is_wsl;
1392
1393 num_read = read(status_fd, buf, sizeof(buf) - 1);
1394
1395 if (num_read > 0)
1396 {
1397 buf[num_read] = 0;
1398 is_wsl |= (strstr(buf, "Microsoft") != NULL);
1399 is_wsl |= (strstr(buf, "WSL") != NULL);
1400 }
1401
1402 return is_wsl;
1403 }
1404 #endif
1405
1406 const std::string hexCHARS = "0123456789abcdef";
GenerateUUID()1407 std::string GenerateUUID() // DCE/RFC 4122
1408 {
1409 std::string uuid = std::string(36, ' ');
1410
1411 uuid[8] = '-';
1412 uuid[13] = '-';
1413 uuid[14] = '4'; //M
1414 uuid[18] = '-';
1415 //uuid[19] = ' '; //N Variant 1 UUIDs (10xx N=8..b, 2 bits)
1416 uuid[23] = '-';
1417
1418 for (size_t ii = 0; ii < uuid.size(); ii++)
1419 {
1420 if (uuid[ii] == ' ')
1421 {
1422 uuid[ii] = hexCHARS[(ii == 19) ? (8 + (std::rand() & 0x03)) : std::rand() & 0x0F];
1423 }
1424 }
1425 return uuid;
1426 }
1427
round_digits(double dIn,const int totDigits)1428 double round_digits(double dIn, const int totDigits)
1429 {
1430 std::stringstream sstr;
1431 sstr << std::setprecision(totDigits) << std::fixed << dIn;
1432 return std::stod(sstr.str());
1433 }
1434