1 //------------------------------------------------------------------------------
2 // emStd2.cpp
3 //
4 // Copyright (C) 2004-2012,2014-2020 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20 
21 #if defined(_WIN32)
22 #	include <ctype.h>
23 #	include <direct.h>
24 #	include <io.h>
25 #	include <windows.h>
26 #	ifndef F_OK
27 #		define F_OK 0
28 #	endif
29 #	ifndef W_OK
30 #		define W_OK 2
31 #	endif
32 #	ifndef R_OK
33 #		define R_OK 4
34 #	endif
35 #else
36 #	include <dirent.h>
37 #	include <fcntl.h>
38 #	include <pwd.h>
39 #	include <sched.h>
40 #	include <signal.h>
41 #	include <sys/times.h>
42 #	include <sys/wait.h>
43 #	include <unistd.h>
44 #	include <dlfcn.h>
45 #endif
46 #if defined(_MSC_VER)
47 #	include <isa_availability.h>
48 	extern "C" int __isa_available;
49 #endif
50 #include <emCore/emStd2.h>
51 #include <emCore/emInstallInfo.h>
52 #include <emCore/emThread.h>
53 
54 
55 //==============================================================================
56 //================================ emException =================================
57 //==============================================================================
58 
emException(const char * format,...)59 emException::emException(const char * format, ...)
60 {
61 	va_list args;
62 
63 	va_start(args,format);
64 	Text=emString::VFormat(format,args);
65 	va_end(args);
66 }
67 
68 
~emException()69 emException::~emException()
70 {
71 }
72 
73 
74 //==============================================================================
75 //=========================== Host, user, process id ===========================
76 //==============================================================================
77 
emGetHostName()78 emString emGetHostName()
79 {
80 #if defined(_WIN32)
81 	char tmp[512];
82 	DWORD sz;
83 
84 	sz=sizeof(tmp)-1;
85 	if (!GetComputerName(tmp,&sz)) {
86 		emFatalError(
87 			"emGetHostName: GetComputerName failed: %s",
88 			emGetErrorText(GetLastError()).Get()
89 		);
90 	}
91 	tmp[sizeof(tmp)-1]=0;
92 	return emString(tmp);
93 #else
94 	char tmp[512];
95 
96 	if (gethostname(tmp,sizeof(tmp))!=0) {
97 		emFatalError(
98 			"emGetHostName: gethostname failed: %s",
99 			emGetErrorText(errno).Get()
100 		);
101 	}
102 	tmp[sizeof(tmp)-1]=0;
103 	return emString(tmp);
104 #endif
105 }
106 
107 
emGetUserName()108 emString emGetUserName()
109 {
110 #if defined(_WIN32)
111 	char tmp[512];
112 	DWORD sz;
113 
114 	sz=sizeof(tmp)-1;
115 	if (!GetUserName(tmp,&sz)) {
116 		emFatalError(
117 			"emGetUserName: GetUserName failed: %s",
118 			emGetErrorText(GetLastError()).Get()
119 		);
120 	}
121 	tmp[sizeof(tmp)-1]=0;
122 	return emString(tmp);
123 #elif defined(ANDROID)
124 	struct passwd * pw;
125 	int i;
126 
127 	errno=0;
128 	pw=getpwuid(getuid());
129 	if (!pw || !pw->pw_name) {
130 		emFatalError(
131 			"emGetUserName: getpwuid failed: %s",
132 			emGetErrorText(errno).Get()
133 		);
134 	}
135 	return emString(pw->pw_name);
136 #else
137 	char tmp[1024];
138 	struct passwd pwbuf;
139 	struct passwd * pw;
140 	int i;
141 
142 	errno=0;
143 	i=getpwuid_r(getuid(),&pwbuf,tmp,sizeof(tmp),&pw);
144 	if (i!=0 || !pw || !pw->pw_name) {
145 		emFatalError(
146 			"emGetUserName: getpwuid_r failed: %s",
147 			emGetErrorText(errno).Get()
148 		);
149 	}
150 	return emString(pw->pw_name);
151 #endif
152 }
153 
154 
emGetProcessId()155 int emGetProcessId()
156 {
157 #if defined(_WIN32)
158 	return GetCurrentProcessId();
159 #else
160 	return getpid();
161 #endif
162 }
163 
164 
165 //==============================================================================
166 //================================ Error Texts =================================
167 //==============================================================================
168 
169 #if !defined(_WIN32)
emGetErrorText_strerror_r_helper(int res,const char * buf)170 const char * emGetErrorText_strerror_r_helper(int res, const char * buf)
171 {
172 	return res==0 ? buf : NULL;
173 }
emGetErrorText_strerror_r_helper(const char * res,const char * buf)174 const char * emGetErrorText_strerror_r_helper(const char * res, const char * buf)
175 {
176 	return res;
177 }
178 #endif
179 
180 
emGetErrorText(int errorNumber)181 emString emGetErrorText(int errorNumber)
182 {
183 #if defined(_WIN32)
184 	char tmp[512];
185 
186 	if (!FormatMessage(
187 		FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
188 		NULL,
189 		(DWORD)errorNumber,
190 		0,
191 		tmp,
192 		sizeof(tmp)-1,
193 		NULL
194 	)) {
195 		sprintf(tmp,"error #%d",errorNumber);
196 	}
197 	return emString(tmp);
198 #else
199 	char tmp[512];
200 	const char * p;
201 
202 	memset(tmp,0,sizeof(tmp));
203 	p=emGetErrorText_strerror_r_helper(strerror_r(errorNumber,tmp,sizeof(tmp)),tmp);
204 	tmp[sizeof(tmp)-1]=0;
205 	if (!p) {
206 		sprintf(tmp,"error #%d",errorNumber);
207 		p=tmp;
208 	}
209 	return emString(p);
210 #endif
211 }
212 
213 
214 //==============================================================================
215 //================================ SIMD support ================================
216 //==============================================================================
217 
emCanCpuDoAvx2()218 bool emCanCpuDoAvx2()
219 {
220 	static const struct Detector {
221 
222 		bool canCpuDoAvx2;
223 
224 		Detector()
225 		{
226 #			if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
227 #				if !defined(__clang__)
228 					__builtin_cpu_init();
229 #				endif
230 				canCpuDoAvx2=
231 					__builtin_cpu_supports("avx2") &&
232 					__builtin_cpu_supports("avx") &&
233 					__builtin_cpu_supports("sse4.1") &&
234 #					if !defined(__clang__)
235 						__builtin_cpu_supports("ssse3") &&
236 #					endif
237 					__builtin_cpu_supports("sse3") &&
238 					__builtin_cpu_supports("sse2") &&
239 					__builtin_cpu_supports("sse") &&
240 					__builtin_cpu_supports("mmx")
241 				;
242 #			elif defined(_MSC_VER)
243 				canCpuDoAvx2=(__isa_available >= __ISA_AVAILABLE_AVX2);
244 #			else
245 				canCpuDoAvx2=false;
246 #			endif
247 		}
248 
249 	} detector;
250 
251 	return detector.canCpuDoAvx2;
252 }
253 
254 
255 //==============================================================================
256 //==================================== Time ====================================
257 //==============================================================================
258 
emSleepMS(int millisecs)259 void emSleepMS(int millisecs)
260 {
261 #if defined(_WIN32)
262 	if (millisecs<0) millisecs=0;
263 	Sleep((DWORD)millisecs);
264 #else
265 	// usleep(0) is unlike sched_yield() on some systems.
266 	if (millisecs<=0) sched_yield();
267 	else if ((unsigned long)millisecs>ULONG_MAX/1000) sleep(millisecs/1000);
268 	else usleep(((unsigned long)millisecs)*1000);
269 #endif
270 }
271 
272 
emGetClockMS()273 emUInt64 emGetClockMS()
274 {
275 #if defined(_WIN32)
276 	static emThreadMiniMutex mutex;
277 	static emUInt64 ms64=0;
278 	static DWORD tcks=0;
279 	DWORD t;
280 	emUInt64 res;
281 
282 	mutex.Lock();
283 	t=GetTickCount();
284 	ms64+=(DWORD)(t-tcks);
285 	tcks=t;
286 	res=ms64;
287 	mutex.Unlock();
288 	return res;
289 #else
290 	static emThreadMiniMutex mutex;
291 	static clock_t tcks=0;
292 	static unsigned long tps=0;
293 	static unsigned long rem=0;
294 	static emUInt64 ms64=0;
295 	emUInt64 t,res;
296 	clock_t d;
297 	tms tb;
298 
299 	mutex.Lock();
300 	d=times(&tb)-tcks;
301 	if (d) {
302 		tcks+=d;
303 		if (tps<=0) {
304 			tps=(unsigned long)sysconf(_SC_CLK_TCK);
305 			if (((long)tps)<=0) {
306 				emFatalError("sysconf(_SC_CLK_TCK) failed");
307 			}
308 		}
309 		t=((emUInt64)d)*1000+rem;
310 		rem=(unsigned long)(t%tps);
311 		ms64+=(emUInt64)(t/tps);
312 	}
313 	res=ms64;
314 	mutex.Unlock();
315 	return res;
316 #endif
317 }
318 
319 
emGetCPUTSC()320 emUInt64 emGetCPUTSC()
321 {
322 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
323 	static const struct Detector {
324 
325 		bool haveRDTSC;
326 
327 		Detector()
328 		{
329 			emUInt32 d;
330 			asm volatile (
331 #				if defined(__x86_64__)
332 					"push %%rbx\n"
333 					"pushfq\n"
334 					"movl (%%rsp),%%eax\n"
335 					"movl %%eax,%%ebx\n"
336 					"xorl $0x00200000,%%eax\n"
337 					"movl %%eax,(%%rsp)\n"
338 					"popfq\n"
339 					"pushfq\n"
340 					"movl (%%rsp),%%eax\n"
341 					"xorl %%ebx,%%eax\n"
342 					"movl %%ebx,(%%rsp)\n"
343 					"popfq\n"
344 #				else
345 					"push %%ebx\n"
346 					"pushfl\n"
347 					"popl %%eax\n"
348 					"movl %%eax,%%ebx\n"
349 					"xorl $0x00200000,%%eax\n"
350 					"pushl %%eax\n"
351 					"popfl\n"
352 					"pushfl\n"
353 					"popl %%eax\n"
354 					"xorl %%ebx,%%eax\n"
355 					"pushl %%ebx\n"
356 					"popfl\n"
357 #				endif
358 				"testl $0x00200000,%%eax\n"
359 				"je 3f\n"
360 				"xorl %%eax,%%eax\n"
361 				"cpuid\n"
362 				"cmpl $0x756e6547,%%ebx\n"
363 				"jne 1f\n"
364 				"cmpl $0x49656e69,%%edx\n"
365 				"jne 1f\n"
366 				"cmpl $0x6c65746e,%%ecx\n"
367 				"je 2f\n"
368 				"1:\n"
369 				"cmpl $0x68747541,%%ebx\n"
370 				"jne 3f\n"
371 				"cmpl $0x69746e65,%%edx\n"
372 				"jne 3f\n"
373 				"cmpl $0x444d4163,%%ecx\n"
374 				"jne 3f\n"
375 				"2:\n"
376 				"movl $1,%%eax\n"
377 				"cpuid\n"
378 				"jmp 4f\n"
379 				"3:\n"
380 				"xorl %%edx,%%edx\n"
381 				"4:\n"
382 #				if defined(__x86_64__)
383 					"pop %%rbx\n"
384 #				else
385 					"pop %%ebx\n"
386 #				endif
387 				: "=d"(d) : : "eax","ecx","cc"
388 			);
389 			haveRDTSC=((d>>4)&1)!=0;
390 		}
391 
392 	} detector;
393 
394 	emUInt32 a,d;
395 
396 	if (detector.haveRDTSC) {
397 		asm volatile (
398 			"rdtsc\n"
399 			: "=a"(a),"=d"(d) : : "cc"
400 		);
401 		return (((emUInt64)d)<<32)|a;
402 	}
403 #endif
404 	return 0;
405 }
406 
407 
408 //==============================================================================
409 //============================ Files & Directories =============================
410 //==============================================================================
411 
emGetParentPath(const char * path)412 emString emGetParentPath(const char * path)
413 {
414 	int i;
415 
416 	i=strlen(path);
417 #if defined(_WIN32)
418 	while (i>0 && (path[i-1]=='\\' || path[i-1]=='/' || path[i-1]==':')) i--;
419 	while (i>0 && path[i-1]!='\\' && path[i-1]!='/' &&  path[i-1]!=':') i--;
420 	while (i>0 && (path[i-1]=='\\' || path[i-1]=='/' || path[i-1]==':')) i--;
421 	if (i<=1) {
422 		if (path[0]=='\\') {
423 			if (path[1]=='\\') i=2; else i=1;
424 		}
425 		else if (path[0] && path[1]==':') {
426 			if (path[2]=='\\' || path[2]=='/') i=3; else i=2;
427 		}
428 	}
429 #else
430 	while (i>0 && path[i-1]=='/') i--;
431 	while (i>0 && path[i-1]!='/') i--;
432 	while (i>0 && path[i-1]=='/') i--;
433 	if (i==0 && path[0]=='/') i++;
434 #endif
435 	return emString(path,i);
436 }
437 
438 
emGetChildPath(const char * path,const char * name)439 emString emGetChildPath(const char * path, const char * name)
440 {
441 	emString subPath;
442 	char * subPathPtr;
443 	int pathLen,nameLen;
444 
445 	pathLen=strlen(path);
446 #if defined(_WIN32)
447 	if (pathLen>0 && (path[pathLen-1]=='\\' || path[pathLen-1]=='/')) pathLen--;
448 	if (name[0]=='\\' || name[0]=='/') name++;
449 	if (pathLen==0 && name[0]!=0 && name[1]==':') return emString(name);
450 #else
451 	if (pathLen>0 && path[pathLen-1]=='/') pathLen--;
452 	if (name[0]=='/') name++;
453 #endif
454 	nameLen=strlen(name);
455 	subPathPtr=subPath.SetLenGetWritable(pathLen+1+nameLen);
456 	memcpy(subPathPtr,path,pathLen);
457 #if defined(_WIN32)
458 	subPathPtr[pathLen]='\\';
459 #else
460 	subPathPtr[pathLen]='/';
461 #endif
462 	memcpy(subPathPtr+pathLen+1,name,nameLen);
463 	return subPath;
464 }
465 
466 
emGetAbsolutePath(const emString & path,const char * cwd)467 emString emGetAbsolutePath(const emString & path, const char * cwd)
468 {
469 	emString absPath;
470 	const char * p;
471 	int i, j;
472 	bool cool;
473 
474 	p=path;
475 #if defined(_WIN32)
476 	if (p[0] && p[1]==':') {
477 		if (p[2]=='\\' || p[2]=='/') {
478 			absPath=path;
479 			cool=true;
480 			i=3;
481 		}
482 		else {
483 			if (cwd) absPath=cwd;
484 			else absPath=emGetCurrentDirectory();
485 			if (tolower(absPath[0])!=tolower(p[0]) || absPath[1]!=':') {
486 				emFatalError("emGetAbsolutePath impossible for: %s", path.Get());
487 			}
488 			cool=false;
489 			i=2;
490 		}
491 	}
492 	else if (p[0]=='\\' || p[0]=='/') {
493 		if (p[1]=='\\' || p[1]=='/') {
494 			absPath=path;
495 			cool=true;
496 			i=2;
497 		}
498 		else {
499 			if (cwd) {
500 				if (cwd[0] && cwd[1]==':') {
501 					absPath=emString(cwd,2);
502 					absPath+="\\";
503 				}
504 				else {
505 					emFatalError("emGetAbsolutePath for %s impossible with cwd %s", path.Get(), cwd);
506 				}
507 			}
508 			else {
509 				absPath=emGetCurrentDirectory().GetSubString(0,3);
510 			}
511 			cool=false;
512 			i=1;
513 		}
514 	}
515 #else
516 	if (p[0]=='/') {
517 		absPath=path;
518 		cool=true;
519 		i=1;
520 	}
521 #endif
522 	else {
523 		if (cwd) absPath=cwd;
524 		else absPath=emGetCurrentDirectory();
525 		cool=false;
526 		i=0;
527 	}
528 	while (p[i]) {
529 #if defined(_WIN32)
530 		for (j=i; p[j]!=0 && p[j]!='\\' && p[j]!='/'; j++);
531 #else
532 		for (j=i; p[j]!=0 && p[j]!='/'; j++);
533 #endif
534 		if (j==i || (j==i+1 && p[i]=='.')) {
535 			if (cool) {
536 				absPath=emString(p,i);
537 				cool=false;
538 			}
539 		}
540 		else if (j==i+2 && p[i]=='.' && p[i+1]=='.') {
541 			if (cool) {
542 				absPath=emString(p,i);
543 				cool=false;
544 			}
545 			absPath=emGetParentPath(absPath);
546 		}
547 		else if (!cool) {
548 			absPath=emGetChildPath(absPath,emString(p+i,j-i));
549 		}
550 		if (!p[j]) break;
551 		i=j+1;
552 	}
553 
554 	return absPath;
555 }
556 
557 
emGetNameInPath(const char * path)558 const char * emGetNameInPath(const char * path)
559 {
560 	int i;
561 
562 	i=strlen(path);
563 #if defined(_WIN32)
564 	while (i>0 && (path[i-1]=='\\' || path[i-1]=='/' || path[i-1]==':')) i--;
565 	while (i>0 && path[i-1]!='\\' && path[i-1]!='/' &&  path[i-1]!=':') i--;
566 #else
567 	while (i>0 && path[i-1]=='/') i--;
568 	while (i>0 && path[i-1]!='/') i--;
569 #endif
570 	return path+i;
571 }
572 
573 
emGetExtensionInPath(const char * path)574 const char * emGetExtensionInPath(const char * path)
575 {
576 	const char * name, * end, * p;
577 
578 	name=emGetNameInPath(path);
579 	end=name+strlen(name);
580 	p=end;
581 	while (p>name && *p!='.') p--;
582 	if (*p!='.') p=end;
583 	return p;
584 }
585 
586 
emIsExistingPath(const char * path)587 bool emIsExistingPath(const char * path)
588 {
589 	return access(path,F_OK)==0;
590 }
591 
592 
emIsReadablePath(const char * path)593 bool emIsReadablePath(const char * path)
594 {
595 	return access(path,R_OK)==0;
596 }
597 
598 
emIsWritablePath(const char * path)599 bool emIsWritablePath(const char * path)
600 {
601 	return access(path,W_OK)==0;
602 }
603 
604 
emIsDirectory(const char * path)605 bool emIsDirectory(const char * path)
606 {
607 	struct em_stat st;
608 
609 #if defined(_WIN32)
610 	int i=strlen(path);
611 	while (i>0 && (path[i-1]=='\\' || path[i-1]=='/')) i--;
612 	if (
613 		i==2 && path[1]==':' && (
614 			(path[0]>='A' && path[0]<='Z') ||
615 			(path[0]>='a' && path[0]<='z')
616 		)
617 	) return true;
618 #endif
619 
620 	if (em_stat(path,&st)!=0) return false;
621 	if ((st.st_mode&S_IFMT)!=S_IFDIR)  return false;
622 	return true;
623 }
624 
625 
emIsRegularFile(const char * path)626 bool emIsRegularFile(const char * path)
627 {
628 	struct em_stat st;
629 
630 	if (em_stat(path,&st)!=0) return false;
631 	if ((st.st_mode&S_IFMT)!=S_IFREG)  return false;
632 	return true;
633 }
634 
635 
emIsSymLinkPath(const char * path)636 bool emIsSymLinkPath(const char * path)
637 {
638 #if defined(_WIN32)
639 	return false;
640 #else
641 	struct em_stat st;
642 
643 	if (em_lstat(path,&st)!=0) return false;
644 	if ((st.st_mode&S_IFMT)!=S_IFLNK)  return false;
645 	return true;
646 #endif
647 }
648 
649 
emIsHiddenPath(const char * path)650 bool emIsHiddenPath(const char * path)
651 {
652 #if defined(_WIN32)
653 	DWORD d;
654 
655 	d=GetFileAttributes(path);
656 	return d!=0xFFFFFFFF && (d&FILE_ATTRIBUTE_HIDDEN)!=0;
657 #else
658 	return emGetNameInPath(path)[0] == '.';
659 #endif
660 }
661 
662 
emTryGetFileSize(const char * path)663 emUInt64 emTryGetFileSize(const char * path)
664 {
665 	struct em_stat st;
666 
667 	if (em_stat(path,&st)!=0) {
668 		throw emException(
669 			"Failed to get size of \"%s\": %s",
670 			path,
671 			emGetErrorText(errno).Get()
672 		);
673 	}
674 	return st.st_size;
675 }
676 
677 
emTryGetFileTime(const char * path)678 time_t emTryGetFileTime(const char * path)
679 {
680 	struct em_stat st;
681 
682 	if (em_stat(path,&st)!=0) {
683 		throw emException(
684 			"Failed to get modification time of \"%s\": %s",
685 			path,
686 			emGetErrorText(errno).Get()
687 		);
688 	}
689 	return st.st_mtime;
690 }
691 
692 
emGetCurrentDirectory()693 emString emGetCurrentDirectory()
694 {
695 	char tmp[1024];
696 
697 	if (getcwd(tmp,sizeof(tmp))==NULL) {
698 		emFatalError("getcwd failed: %s",emGetErrorText(errno).Get());
699 	}
700 	return emString(tmp);
701 }
702 
703 
704 #if defined(_WIN32)
705 struct emDirHandleContent {
706 	HANDLE handle;
707 	WIN32_FIND_DATA data;
708 	bool first;
709 };
710 #endif
711 
712 
emTryOpenDir(const char * path)713 emDirHandle emTryOpenDir(const char * path)
714 {
715 #if defined(_WIN32)
716 	emDirHandleContent * hc;
717 	DWORD d;
718 
719 	hc=new emDirHandleContent;
720 	hc->handle=FindFirstFile(
721 		emGetChildPath(path,"*.*"),
722 		&hc->data
723 	);
724 	if (hc->handle==INVALID_HANDLE_VALUE) {
725 		d=GetLastError();
726 		if (d!=ERROR_NO_MORE_FILES) {
727 			delete hc;
728 			throw emException(
729 				"Failed to read directory \"%s\": %s",
730 				path,
731 				emGetErrorText(d).Get()
732 			);
733 		}
734 	}
735 	hc->first=true;
736 	return hc;
737 #else
738 	DIR * dir;
739 
740 	dir=opendir(path);
741 	if (!dir) {
742 		throw emException(
743 			"Failed to read directory \"%s\": %s",
744 			path,
745 			emGetErrorText(errno).Get()
746 		);
747 	}
748 
749 	return (emDirHandle)dir;
750 #endif
751 }
752 
753 
emTryReadDir(emDirHandle dirHandle)754 emString emTryReadDir(emDirHandle dirHandle)
755 {
756 #if defined(_WIN32)
757 	emDirHandleContent * hc;
758 
759 	hc=(emDirHandleContent*)dirHandle;
760 	for (;;) {
761 		if (hc->handle==INVALID_HANDLE_VALUE) return emString();
762 		if (hc->first) {
763 			hc->first=false;
764 		}
765 		else {
766 			if (!FindNextFile(hc->handle,&hc->data)) {
767 				if (GetLastError()!=ERROR_NO_MORE_FILES) {
768 					throw emException(
769 						"Failed to read directory: %s",
770 						emGetErrorText(GetLastError()).Get()
771 					);
772 				}
773 				FindClose(hc->handle);
774 				hc->handle=INVALID_HANDLE_VALUE;
775 				return emString();
776 			}
777 		}
778 		if (
779 			hc->data.cFileName[0] &&
780 			strcmp(hc->data.cFileName,".")!=0 &&
781 			strcmp(hc->data.cFileName,"..")!=0
782 		) return emString(hc->data.cFileName);
783 	}
784 #else
785 	struct dirent * de;
786 	emString res;
787 
788 	for (;;) {
789 		errno=0;
790 		de=readdir((DIR*)dirHandle);
791 		if (!de) {
792 			if (errno) {
793 				throw emException(
794 					"Failed to read directory: %s",
795 					emGetErrorText(errno).Get()
796 				);
797 			}
798 			break;
799 		}
800 		if (
801 			de->d_name[0] &&
802 			strcmp(de->d_name,".")!=0 &&
803 			strcmp(de->d_name,"..")!=0
804 		) {
805 			res=emString(de->d_name);
806 			break;
807 		}
808 	}
809 	return res;
810 #endif
811 }
812 
813 
emCloseDir(emDirHandle dirHandle)814 void emCloseDir(emDirHandle dirHandle)
815 {
816 #if defined(_WIN32)
817 	emDirHandleContent * hc;
818 
819 	hc=(emDirHandleContent*)dirHandle;
820 	if (hc->handle!=INVALID_HANDLE_VALUE) {
821 		FindClose(hc->handle);
822 	}
823 	delete hc;
824 #else
825 	closedir((DIR*)dirHandle);
826 #endif
827 }
828 
829 
emTryLoadDir(const char * path)830 emArray<emString> emTryLoadDir(const char * path)
831 {
832 	emDirHandle dirHandle;
833 	emArray<emString> names;
834 	emString name;
835 
836 	names.SetTuningLevel(1);
837 	dirHandle=emTryOpenDir(path);
838 	for (;;) {
839 		try {
840 			name=emTryReadDir(dirHandle);
841 		}
842 		catch (const emException & exception) {
843 			emCloseDir(dirHandle);
844 			throw exception;
845 		}
846 		if (name.IsEmpty()) break;
847 		names+=name;
848 	}
849 	emCloseDir(dirHandle);
850 	names.Compact();
851 	return names;
852 }
853 
854 
emTryLoadFile(const char * path)855 emArray<char> emTryLoadFile(const char * path)
856 {
857 	emArray<char> buf;
858 	FILE * f;
859 	emInt64 l;
860 	int i,j;
861 
862 	buf.SetTuningLevel(4);
863 	f=fopen(path,"rb");
864 	if (!f) goto L_Err;
865 	if (fseek(f,0,SEEK_END)!=0) goto L_Err;
866 	l=ftell(f);
867 	if (l<0) goto L_Err;
868 	if (l>INT_MAX) { errno=EFBIG; goto L_Err; }
869 	buf.SetCount((int)l,true);
870 	if (fseek(f,0,SEEK_SET)!=0) goto L_Err;
871 	for (i=0; i<buf.GetCount(); i+=j) {
872 		j=fread(buf.GetWritable()+i,1,buf.GetCount()-i,f);
873 		if (j<=0) goto L_Err;
874 	}
875 	fclose(f);
876 	return buf;
877 L_Err:
878 	if (f) fclose(f);
879 	throw emException(
880 		"Failed to read file \"%s\": %s",
881 		path,
882 		emGetErrorText(errno).Get()
883 	);
884 }
885 
886 
emTrySaveFile(const char * path,const char * data,int len)887 void emTrySaveFile(const char * path, const char * data, int len)
888 {
889 	FILE * f;
890 	int i;
891 
892 	f=fopen(path,"wb");
893 	if (!f) goto L_Err;
894 	while (len>0) {
895 		i=fwrite(data,1,len,f);
896 		if (i<=0) goto L_Err;
897 		data+=i;
898 		len-=i;
899 	}
900 	fclose(f);
901 	return;
902 L_Err:
903 	if (f) fclose(f);
904 	throw emException(
905 		"Failed to write file \"%s\": %s",
906 		path,
907 		emGetErrorText(errno).Get()
908 	);
909 }
910 
911 
emTrySaveFile(const char * path,const emArray<char> & data)912 void emTrySaveFile(const char * path, const emArray<char> & data)
913 {
914 	emTrySaveFile(path,data,data.GetCount());
915 }
916 
917 
emTryMakeDirectories(const char * path,int mode)918 void emTryMakeDirectories(const char * path, int mode)
919 {
920 	emString parentPath;
921 
922 	if (*path && access(path,F_OK)!=0) {
923 		parentPath=emGetParentPath(path);
924 		if (parentPath!=path) emTryMakeDirectories(parentPath,mode);
925 #if defined(_WIN32)
926 		if (mkdir(path)!=0) {
927 #else
928 		if (mkdir(path,mode)!=0) {
929 #endif
930 			throw emException(
931 				"Failed to create directory \"%s\": %s",
932 				path,
933 				emGetErrorText(errno).Get()
934 			);
935 		}
936 	}
937 }
938 
939 
940 void emTryRemoveFile(const char * path)
941 {
942 	if (!*path) {
943 		throw emException("Cannot to remove file: empty path");
944 	}
945 	if (unlink(path)!=0) {
946 		throw emException(
947 			"Failed to remove \"%s\": %s",
948 			path,
949 			emGetErrorText(errno).Get()
950 		);
951 	}
952 }
953 
954 
955 void emTryRemoveDirectory(const char * path)
956 {
957 	if (!*path) {
958 		throw emException("Cannot to remove directory: empty path");
959 	}
960 	if (rmdir(path)!=0) {
961 		throw emException(
962 			"Failed to remove directory \"%s\": %s",
963 			path,
964 			emGetErrorText(errno).Get()
965 		);
966 	}
967 }
968 
969 
970 #ifdef _WIN32
971 static emString emW2A(const wchar_t * w)
972 {
973 	emString str;
974 	char * p;
975 	int i,l;
976 
977 	l=WideCharToMultiByte(CP_ACP,0,w,-1,NULL,0,NULL,NULL);
978 	if (l>0) {
979 		p=str.SetLenGetWritable(l);
980 		l=WideCharToMultiByte(CP_ACP,0,w,-1,p,l,NULL,NULL);
981 	}
982 	if (l<=0) {
983 		str.Clear();
984 		for (i=0; w[i]; i++) str.Add(w[i]>=32 && w[i]<=126 ? (char)w[i] : '?');
985 	}
986 	return str;
987 }
988 #endif
989 
990 
991 #ifdef _WIN32
992 static void emTryRemoveFileOrTreeW(const wchar_t * path, bool force)
993 {
994 	emArray<wchar_t> subPath;
995 	WIN32_FIND_DATAW data;
996 	HANDLE h;
997 	DWORD d;
998 
999 	if (!*path) {
1000 		throw emException("Cannot remove file or directory: empty path");
1001 	}
1002 
1003 	d=GetFileAttributesW(path);
1004 	if (d==INVALID_FILE_ATTRIBUTES) {
1005 		// Yes, even do not simply return successful on ERROR_FILE_NOT_FOUND,
1006 		// because we don't want to miss path conversion errors.
1007 		throw emException(
1008 			"Failed to get file attributes of \"%s\": %s",
1009 			emW2A(path).Get(),
1010 			emGetErrorText(GetLastError()).Get()
1011 		);
1012 	}
1013 	if (force && (d&FILE_ATTRIBUTE_READONLY)!=0) {
1014 		SetFileAttributesW(path,d&~FILE_ATTRIBUTE_READONLY);
1015 	}
1016 	if (d&FILE_ATTRIBUTE_DIRECTORY) {
1017 		subPath=emArray<wchar_t>(path,lstrlenW(path));
1018 		subPath.Add(L"\\*.*\0",5);
1019 		h=FindFirstFileW(subPath.Get(),&data);
1020 		if (h==INVALID_HANDLE_VALUE) {
1021 			d=GetLastError();
1022 			if (d!=ERROR_NO_MORE_FILES) {
1023 				throw emException(
1024 					"Failed to read directory \"%s\": %s",
1025 					emW2A(path).Get(),
1026 					emGetErrorText(d).Get()
1027 				);
1028 			}
1029 		}
1030 		else {
1031 			do {
1032 				if (
1033 					data.cFileName[0] &&
1034 					lstrcmpW(data.cFileName,L".")!=0 &&
1035 					lstrcmpW(data.cFileName,L"..")!=0
1036 				) {
1037 					subPath=emArray<wchar_t>(path,lstrlenW(path));
1038 					subPath.Add(L"\\",1);
1039 					subPath.Add(data.cFileName,lstrlenW(data.cFileName)+1);
1040 					emTryRemoveFileOrTreeW(subPath,force);
1041 				}
1042 			} while(FindNextFileW(h,&data));
1043 			if (GetLastError()!=ERROR_NO_MORE_FILES) {
1044 				FindClose(h);
1045 				throw emException(
1046 					"Failed to read directory: %s",
1047 					emGetErrorText(GetLastError()).Get()
1048 				);
1049 			}
1050 			FindClose(h);
1051 		}
1052 		if (!RemoveDirectoryW(path)) {
1053 			throw emException(
1054 				"Failed to remove directory \"%s\": %s",
1055 				emW2A(path).Get(),
1056 				emGetErrorText(GetLastError()).Get()
1057 			);
1058 		}
1059 	}
1060 	else {
1061 		if (!DeleteFileW(path)) {
1062 			throw emException(
1063 				"Failed to remove \"%s\": %s",
1064 				emW2A(path).Get(),
1065 				emGetErrorText(GetLastError()).Get()
1066 			);
1067 		}
1068 	}
1069 }
1070 #endif
1071 
1072 
1073 void emTryRemoveFileOrTree(const char * path, bool force)
1074 {
1075 #ifdef _WIN32
1076 	emArray<wchar_t> wPath;
1077 	emString absPath;
1078 	int i,l;
1079 
1080 	// For the (indirect) use by emTmpConv, removal of trees must be quite
1081 	// reliable. But on Windows, "normal" removal fails if:
1082 	//  - A path is longer than 260 bytes.
1083 	//  - A path contains Unicode characters not in the active code page.
1084 	//  - A file name equals a device name (aux, con, com1, com2, ...).
1085 	// All these problems can be solved by using wide char functions and
1086 	// prefixing the absolute path with "\\?\". But care must be taken
1087 	// because "\\?\" brings some certain behavior:
1088 	//  - Slashes are not implicitly converted to backslashes.
1089 	//  - "." and ".." are losing their meaning.
1090 	//  - File names can contain characters like "<", ">" and "|"
1091 	// (Hint: There is the alternative prefix "\\.\", but that one does not
1092 	// help with long paths.)
1093 
1094 	static const struct VersionTester {
1095 		bool result;
1096 		VersionTester()
1097 		{
1098 			// From which Windows version on is the \\?\ path prefix
1099 			// supported? I could not find it out, but I could test
1100 			// XP (5.1).
1101 			static const unsigned long minWinVer[2] = { 5, 1 };
1102 			OSVERSIONINFO osvi;
1103 			memset(&osvi,0,sizeof(osvi));
1104 			osvi.dwOSVersionInfoSize=sizeof(osvi);
1105 			GetVersionEx(&osvi);
1106 			result=
1107 				osvi.dwMajorVersion > minWinVer[0] || (
1108 					osvi.dwMajorVersion == minWinVer[0] &&
1109 					osvi.dwMinorVersion >= minWinVer[1]
1110 				)
1111 			;
1112 		}
1113 	} versionTester;
1114 
1115 	absPath=emGetAbsolutePath(path);
1116 
1117 	if (versionTester.result) {
1118 		if (absPath[0] && absPath[1]==':' && (absPath[2]=='\\' || absPath[2]=='/')) {
1119 			for (i=0; absPath[i]; i++) {
1120 				if (absPath[i]=='/') absPath.Replace(i,1,"\\");
1121 			}
1122 			absPath.Insert(0,"\\\\?\\");
1123 		}
1124 	}
1125 
1126 	SetLastError(ERROR_SUCCESS);
1127 	l=MultiByteToWideChar(CP_ACP,0,absPath.Get(),-1,NULL,0);
1128 	if (l>0) {
1129 		wPath.SetCount(l+1);
1130 		wPath.Set(l,0);
1131 		l=MultiByteToWideChar(CP_ACP,0,absPath.Get(),-1,wPath.GetWritable(),l);
1132 	}
1133 	if (l<=0 || GetLastError()!=ERROR_SUCCESS) {
1134 		throw emException(
1135 			"Failed to convert path \"%s\" to wide char: %s",
1136 			absPath.Get(),emGetErrorText(GetLastError()).Get()
1137 		);
1138 	}
1139 
1140 	emTryRemoveFileOrTreeW(wPath,force);
1141 
1142 #else
1143 
1144 	emArray<emString> list;
1145 	struct em_stat st;
1146 	int i;
1147 
1148 	if (!*path) {
1149 		throw emException("Cannot remove file or directory: empty path");
1150 	}
1151 
1152 	if (em_lstat(path,&st)!=0) {
1153 		throw emException(
1154 			"Failed to get file information of \"%s\": %s",
1155 			path,
1156 			emGetErrorText(errno).Get()
1157 		);
1158 	}
1159 
1160 	if ((st.st_mode&S_IFMT)==S_IFDIR) {
1161 		if (force && (st.st_mode&0700)!=0700) {
1162 			chmod(path,(st.st_mode&07777)|0700);
1163 		}
1164 		list=emTryLoadDir(path);
1165 		for (i=0; i<list.GetCount(); i++) {
1166 			emTryRemoveFileOrTree(emGetChildPath(path,list[i]),force);
1167 		}
1168 		if (rmdir(path)!=0) {
1169 			throw emException(
1170 				"Failed to remove directory \"%s\": %s",
1171 				path,
1172 				emGetErrorText(errno).Get()
1173 			);
1174 		}
1175 	}
1176 	else {
1177 		if (unlink(path)!=0) {
1178 			throw emException(
1179 				"Failed to remove \"%s\": %s",
1180 				path,
1181 				emGetErrorText(errno).Get()
1182 			);
1183 		}
1184 	}
1185 #endif
1186 }
1187 
1188 
1189 void emTryCopyFileOrTree(const char * targetPath, const char * sourcePath)
1190 {
1191 	emDirHandle dh;
1192 	emString nm;
1193 	FILE * sf, * tf;
1194 	char buf[8192];
1195 	int bufFill,len;
1196 
1197 	if (emIsDirectory(sourcePath)) {
1198 		emTryMakeDirectories(targetPath);
1199 		dh=emTryOpenDir(sourcePath);
1200 		try {
1201 			for (;;) {
1202 				nm=emTryReadDir(dh);
1203 				if (nm.IsEmpty()) break;
1204 				emTryCopyFileOrTree(
1205 					emGetChildPath(targetPath,nm),
1206 					emGetChildPath(sourcePath,nm)
1207 				);
1208 			}
1209 		}
1210 		catch (const emException & exception) {
1211 			emCloseDir(dh);
1212 			throw exception;
1213 		}
1214 		emCloseDir(dh);
1215 	}
1216 	else if (emIsExistingPath(targetPath)) {
1217 		errno=EEXIST;
1218 		goto L_Throw_per_errno;
1219 	}
1220 	else {
1221 		sf=fopen(sourcePath,"rb");
1222 		if (!sf) {
1223 			goto L_Throw_per_errno;
1224 		}
1225 		tf=fopen(targetPath,"wb");
1226 		if (!tf) {
1227 			fclose(sf);
1228 			goto L_Throw_per_errno;
1229 		}
1230 		bufFill=0;
1231 		do {
1232 			if (sf) {
1233 				len=sizeof(buf)-bufFill;
1234 				if (len>0) {
1235 					len=fread(buf+bufFill,1,len,sf);
1236 					if (ferror(sf)) {
1237 						fclose(sf);
1238 						fclose(tf);
1239 						goto L_Throw_per_errno;
1240 					}
1241 					if (feof(sf)) {
1242 						fclose(sf);
1243 						sf=NULL;
1244 					}
1245 					bufFill+=len;
1246 				}
1247 			}
1248 			if (bufFill>0) {
1249 				len=fwrite(buf,1,bufFill,tf);
1250 				if (ferror(tf)) {
1251 					if (sf) fclose(sf);
1252 					fclose(tf);
1253 					goto L_Throw_per_errno;
1254 				}
1255 				bufFill-=len;
1256 				if (bufFill>0) memmove(buf,buf+len,bufFill);
1257 			}
1258 		} while (sf || bufFill>0);
1259 		fclose(tf);
1260 	}
1261 	return;
1262 
1263 L_Throw_per_errno:
1264 	throw emException(
1265 		"Failed to copy \"%s\" to \"%s\": %s",
1266 		sourcePath,
1267 		targetPath,
1268 		emGetErrorText(errno).Get()
1269 	);
1270 }
1271 
1272 
1273 //==============================================================================
1274 //======================== Accessing Dynamic Libraries =========================
1275 //==============================================================================
1276 
1277 struct emLibTableEntry {
1278 	emString Filename;
1279 	emUInt64 RefCount; // Zero means infinite.
1280 #if defined(_WIN32)
1281 	HMODULE HModule;
1282 #else
1283 	void * DLHandle;
1284 #endif
1285 };
1286 
1287 static emThreadMiniMutex emLibTableMutex;
1288 static emArray<emLibTableEntry*> emLibTable;
1289 
1290 
1291 static int emCompareLibEntryFilename(
1292 	emLibTableEntry * const * entry, void * filename, void * context
1293 )
1294 {
1295 	return strcmp((*entry)->Filename.Get(),(const char*)filename);
1296 }
1297 
1298 
1299 emLibHandle emTryOpenLib(const char * libName, bool isFilename)
1300 {
1301 	emLibTableEntry * e;
1302 	emString filename;
1303 	int idx;
1304 #if defined(_WIN32)
1305 	HMODULE hModule;
1306 #else
1307 	void * dlHandle;
1308 #endif
1309 
1310 	if (isFilename) {
1311 		filename=libName;
1312 	}
1313 	else {
1314 #if defined(_WIN32) || defined(__CYGWIN__)
1315 		filename=emString::Format("%s.dll",libName);
1316 #elif defined(__APPLE__)
1317 		filename=emString::Format("lib%s.dylib",libName);
1318 #else
1319 		filename=emString::Format("lib%s.so",libName);
1320 #endif
1321 	}
1322 
1323 	emLibTableMutex.Lock();
1324 
1325 	idx=emLibTable.BinarySearchByKey(
1326 		(void*)filename.Get(),
1327 		emCompareLibEntryFilename
1328 	);
1329 	if (idx>=0) {
1330 		e=emLibTable[idx];
1331 		if (e->RefCount) e->RefCount++;
1332 		emLibTableMutex.Unlock();
1333 		return e;
1334 	}
1335 #if defined(_WIN32)
1336 	hModule=LoadLibrary(filename.Get());
1337 	if (!hModule) {
1338 		emLibTableMutex.Unlock();
1339 		throw emException(
1340 			"Failed to load library \"%s\": %s",
1341 			filename.Get(),
1342 			emGetErrorText(GetLastError()).Get()
1343 		);
1344 	}
1345 #else
1346 	dlHandle=dlopen(filename,RTLD_NOW|RTLD_GLOBAL);
1347 	if (!dlHandle) {
1348 		emLibTableMutex.Unlock();
1349 #		if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)
1350 			throw emException("%s",dlerror());
1351 #		else
1352 			throw emException(
1353 				"Failed to load library \"%s\": %s",
1354 				filename.Get(),
1355 				dlerror()
1356 			);
1357 #		endif
1358 	}
1359 #endif
1360 	e=new emLibTableEntry;
1361 	e->Filename=filename;
1362 	e->RefCount=1;
1363 #if defined(_WIN32)
1364 	e->HModule=hModule;
1365 #else
1366 	e->DLHandle=dlHandle;
1367 #endif
1368 	emLibTable.Insert(~idx,e);
1369 
1370 	filename.Clear();
1371 	e->Filename.MakeNonShared();
1372 
1373 	emLibTableMutex.Unlock();
1374 	return e;
1375 }
1376 
1377 
1378 void * emTryResolveSymbolFromLib(emLibHandle handle, const char * symbol)
1379 {
1380 	emLibTableEntry * e;
1381 	void * r;
1382 #if defined(_WIN32)
1383 #else
1384 	const char * err;
1385 #endif
1386 
1387 	e=(emLibTableEntry*)handle;
1388 #if defined(_WIN32)
1389 	r=(void*)GetProcAddress(e->HModule,symbol);
1390 	if (!r) {
1391 		throw emException(
1392 			"Failed to get address of \"%s\" in \"%s\": %s",
1393 			symbol,
1394 			e->Filename.Get(),
1395 			emGetErrorText(GetLastError()).Get()
1396 		);
1397 	}
1398 #else
1399 	dlerror();
1400 	r=dlsym(e->DLHandle,symbol);
1401 	err=dlerror();
1402 	if (err) {
1403 #		if defined(ANDROID)
1404 			throw emException(
1405 				"Failed to get address of \"%s\" in \"%s\".",
1406 				symbol,
1407 				e->Filename.Get()
1408 			);
1409 #		elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)
1410 			throw emException("%s",err);
1411 #		else
1412 			throw emException(
1413 				"Failed to get address of \"%s\" in \"%s\": %s",
1414 				symbol,
1415 				e->Filename.Get(),
1416 				err
1417 			);
1418 #		endif
1419 	}
1420 #endif
1421 	return r;
1422 }
1423 
1424 
1425 void emCloseLib(emLibHandle handle)
1426 {
1427 	emLibTableEntry * e;
1428 
1429 	emLibTableMutex.Lock();
1430 	e=(emLibTableEntry*)handle;
1431 	if (e->RefCount && !e->RefCount--) {
1432 #if defined(_WIN32)
1433 		FreeLibrary(e->HModule);
1434 		e->HModule=NULL;
1435 #else
1436 		dlclose(e->DLHandle);
1437 		e->DLHandle=NULL;
1438 #endif
1439 		emLibTable.BinaryRemoveByKey(
1440 			(void*)e->Filename.Get(),
1441 			emCompareLibEntryFilename
1442 		);
1443 		delete e;
1444 	}
1445 	emLibTableMutex.Unlock();
1446 }
1447 
1448 
1449 void * emTryResolveSymbol(
1450 	const char * libName, bool isFilename, const char * symbol
1451 )
1452 {
1453 	emLibTableEntry * e;
1454 	void * r;
1455 
1456 	e=(emLibTableEntry*)emTryOpenLib(libName,isFilename);
1457 	r=emTryResolveSymbolFromLib(e,symbol);
1458 	emLibTableMutex.Lock();
1459 	e->RefCount=0;
1460 	emLibTableMutex.Unlock();
1461 	return r;
1462 }
1463 
1464 
1465 //==============================================================================
1466 //=========================== Pseudo Random Numbers ============================
1467 //==============================================================================
1468 
1469 int emGetIntRandom(int minimum, int maximum)
1470 {
1471 	return (int)emGetInt64Random(minimum,maximum);
1472 }
1473 
1474 
1475 unsigned int emGetUIntRandom(unsigned int minimum, unsigned int maximum)
1476 {
1477 	return (unsigned int)emGetUInt64Random(minimum,maximum);
1478 }
1479 
1480 
1481 emInt64 emGetInt64Random(emInt64 minimum, emInt64 maximum)
1482 {
1483 	return (emInt64)(emGetUInt64Random(
1484 		((emUInt64)minimum)^(((emUInt64)1)<<63),
1485 		((emUInt64)maximum)^(((emUInt64)1)<<63)
1486 	)^(((emUInt64)1)<<63));
1487 }
1488 
1489 
1490 emUInt64 emGetUInt64Random(emUInt64 minimum, emUInt64 maximum)
1491 {
1492 	static emUInt32 seedLo=0x302D9934U;
1493 	static emUInt32 seedHi=0xD5441C6EU;
1494 	static emUInt32 count=0;
1495 	emUInt32 a,b,c;
1496 	emUInt64 r;
1497 
1498 	if (!count) {
1499 		a=(emUInt32)time(NULL);
1500 		b=(emUInt32)emGetClockMS();
1501 		c=(emUInt32)emGetProcessId();
1502 		seedLo^=(a+b*1321+c*1231277)*0x106F68F6U+0x0723BF76U;
1503 		seedHi^=(a*9601769+b*5099+c)*0xA0ECFAC5U+0x1840E54BU;
1504 	}
1505 	count++;
1506 	seedLo=seedLo*0xC78D632DU+0xBDFAAE3BU;
1507 	seedHi=seedHi*0xAC7D7A21U+0x2FF59947U;
1508 	r=maximum-minimum+1;
1509 	if (r>(emUInt64)0xffffffff) r=((((emUInt64)seedHi)<<32)|seedLo)%r;
1510 	else if (r) r=((seedLo>>16)^seedHi)%((emUInt32)r);
1511 	else r=(((emUInt64)seedHi)<<32)|seedLo;
1512 	return r+minimum;
1513 }
1514 
1515 
1516 double emGetDblRandom(double minimum, double maximum)
1517 {
1518 	return emGetUInt64Random(
1519 		0,(emUInt64)(emInt64)-1
1520 	)/((double)(emUInt64)(emInt64)-1)*(maximum-minimum)+minimum;
1521 }
1522 
1523 
1524 //==============================================================================
1525 //========================== Checksums and hash codes ==========================
1526 //==============================================================================
1527 
1528 emUInt32 emCalcAdler32(const char * src, int srcLen, emUInt32 start)
1529 {
1530 	const char * brk, * end;
1531 	emUInt32 lo, hi;
1532 
1533 	lo=start&0xffff;
1534 	hi=start>>16;
1535 	end=src+srcLen;
1536 	while (src<end) {
1537 		if (end-src<=5552) brk=end;
1538 		else brk=src+5552;
1539 		do {
1540 			lo+=(emUInt8)*src++;
1541 			hi+=lo;
1542 		} while(src<brk);
1543 		lo%=65521;
1544 		hi%=65521;
1545 	}
1546 	return (hi<<16)|lo;
1547 }
1548 
1549 
1550 emUInt32 emCalcCRC32(const char * src, int srcLen, emUInt32 start)
1551 {
1552 	static const struct CRC32Table {
1553 
1554 		emUInt32 tab[256];
1555 
1556 		CRC32Table()
1557 		{
1558 			emUInt32 r;
1559 			int i,j;
1560 			for (i=0; i<256; i++) {
1561 				for (r=i, j=0; j<8; j++) {
1562 					if ((r&1)!=0) r=(r>>1)^0xEDB88320; else r>>=1;
1563 				}
1564 				tab[i]=r;
1565 			}
1566 		}
1567 
1568 	} crc32Table;
1569 
1570 	const char * end;
1571 	emUInt32 r;
1572 
1573 	r=start;
1574 	if (srcLen>0) {
1575 		r=~r;
1576 		end=src+srcLen;
1577 		do {
1578 			r=crc32Table.tab[((emUInt8)*src++)^((emUInt8)r)]^(r>>8);
1579 		} while (src<end);
1580 		r=~r;
1581 	}
1582 	return r;
1583 }
1584 
1585 
1586 emUInt64 emCalcCRC64(const char * src, int srcLen, emUInt64 start)
1587 {
1588 	static const struct CRC64Table {
1589 
1590 		emUInt64 tab[256];
1591 
1592 		CRC64Table()
1593 		{
1594 			emUInt64 r;
1595 			int i,j;
1596 			for (i=0; i<256; i++) {
1597 				for (r=i, j=0; j<8; j++) {
1598 					if ((r&1)!=0) r=(r>>1)^(((emUInt64)0xD8000000)<<32);
1599 					else r>>=1;
1600 				}
1601 				tab[i]=r;
1602 			}
1603 		}
1604 
1605 	} crc64Table;
1606 
1607 	const char * end;
1608 	emUInt64 r;
1609 
1610 	r=start;
1611 	if (srcLen>0) {
1612 		r=~r;
1613 		end=src+srcLen;
1614 		do {
1615 			r=crc64Table.tab[((emUInt8)*src++)^((emUInt8)r)]^(r>>8);
1616 		} while (src<end);
1617 		r=~r;
1618 	}
1619 	return r;
1620 }
1621 
1622 
1623 int emCalcHashCode(const char * str, int start)
1624 {
1625 	unsigned int r,c;
1626 
1627 	r=(unsigned int)start;
1628 	c=(unsigned char)*str++;
1629 	if (c) {
1630 		do {
1631 			r=r*335171+c;
1632 			c=(unsigned char)*str++;
1633 		} while (c);
1634 	}
1635 	return (int)r;
1636 }
1637 
1638 
1639 emString emCalcHashName(const char * src, int srcLen, int hashLen)
1640 {
1641 	emString hash;
1642 	char * hashPtr;
1643 	unsigned int a;
1644 	emUInt64 b;
1645 	int i,j,k;
1646 
1647 	// Part 1: Prepare the hash name consisting of digits and non-capital
1648 	// letters only.
1649 	//
1650 	// For this algorithm, it has been proved with a test program, that the
1651 	// prime number 6795413 produces the theoretical minimum possible number
1652 	// of collisions for all possible sources with all combinations of
1653 	// srcLen = 1 to 3 (256 combinations per source byte) and hashLen = 1 to
1654 	// 5 (36 combinations per hash byte). About 50 different prime numbers
1655 	// have been tested, three of them resulted best, 6795413 is one of
1656 	// those three. But it is still not proved that the results are even an
1657 	// optimum for greater srcLen and hashLen.
1658 	hashPtr=hash.SetLenGetWritable(hashLen);
1659 	memset(hashPtr,0,hashLen);
1660 	for (i=0; i<srcLen; i++) {
1661 		for (j=0; j<hashLen; j++) {
1662 			a=(unsigned char)hashPtr[j];
1663 			if (j==hashLen-1) a+=(unsigned char)src[i];
1664 			a*=6795413;
1665 			hashPtr[j]=(char)(a%36);
1666 			a/=36;
1667 			for (k=j-1; k>=0 && a!=0; k--) {
1668 				a+=hashPtr[k];
1669 				hashPtr[k]=(char)(a%36);
1670 				a/=36;
1671 			}
1672 		}
1673 	}
1674 	for (i=0; i<hashLen; i++) {
1675 		a=(unsigned char)hashPtr[i];
1676 		if (a<10) a+='0';
1677 		else a+='a'-10;
1678 		hashPtr[i]=(char)a;
1679 	}
1680 
1681 	// Part 2: Improve the hash name a little bit through capitalization.
1682 	// This is an extra algorithm because it could happen that the user
1683 	// performs comparisons ignoring the capitalization, for example when
1684 	// using the name as a DOS file name.
1685 	for (i=0, j=0; i<hashLen; i++) {
1686 		if (hashPtr[i]>='a' && hashPtr[i]<='z') j++;
1687 	}
1688 	if (j<=32) b=emCalcCRC32(src,srcLen);
1689 	else b=emCalcCRC64(src,srcLen);
1690 	if (j<=16) b^=b>>16;
1691 	if (j<=8) b^=b>>8;
1692 	if (j<=4) b^=b>>4;
1693 	if (j<=2) b^=b>>2;
1694 	if (j<=1) b^=b>>1;
1695 	for (i=0; i<hashLen; i++) {
1696 		if (hashPtr[i]>='a' && hashPtr[i]<='z') {
1697 			if ((b&1)!=0) hashPtr[i]+=(char)('A'-'a');
1698 			b>>=1;
1699 		}
1700 	}
1701 
1702 	return hash;
1703 }
1704