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, "&", "&amp;");
1065         stdreplace(sRet, "\"", "&quot;");
1066         stdreplace(sRet, "'", "&apos;");
1067         stdreplace(sRet, "<", "&lt;");
1068         stdreplace(sRet, ">", "&gt;");
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, "\"", "&quot;");
1079     stdreplace(sRet, "'", "&apos;");
1080     stdreplace(sRet, "<", "&lt;");
1081     stdreplace(sRet, ">", "&gt;");
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