1 #include "Core.h"
2 
3 #ifdef PLATFORM_WIN32
4 #	include <winnls.h>
5 #endif
6 
7 #if defined(PLATFORM_POSIX) && defined(COMPILER_GCC) && !defined(PLATFORM_ANDROID) && defined(flagSTACKTRACE)
8 #	include <execinfo.h>
9 #	include <cxxabi.h>
10 #endif
11 
12 namespace Upp {
13 
14 bool PanicMode;
15 
IsPanicMode()16 bool    IsPanicMode() { return PanicMode; }
17 
18 static  void (*sPanicMessageBox)(const char *title, const char *text);
19 
InstallPanicMessageBox(void (* mb)(const char * title,const char * text))20 void InstallPanicMessageBox(void (*mb)(const char *title, const char *text))
21 {
22 	sPanicMessageBox = mb;
23 }
24 
PanicMessageBox(const char * title,const char * text)25 void PanicMessageBox(const char *title, const char *text)
26 {
27 	PanicMode = true;
28 	if(sPanicMessageBox)
29 		(*sPanicMessageBox)(title, text);
30 	else {
31 		IGNORE_RESULT(
32 			write(2, text, (int)strlen(text))
33 		);
34 		IGNORE_RESULT(
35 			write(2, "\n", 1)
36 		);
37 	}
38 }
39 
40 
41 #if defined(PLATFORM_LINUX) && defined(COMPILER_GCC) && !defined(PLATFORM_ANDROID) && defined(flagSTACKTRACE)
AddStackTrace(char * str,int len)42 void AddStackTrace(char * str, int len)
43 {
44 	const size_t max_depth = 100;
45     void *stack_addrs[max_depth];
46     char **stack_strings;
47     const char msg[] = "\nStack trace:\n";
48 
49     size_t stack_depth = backtrace(stack_addrs, max_depth);
50     stack_strings = backtrace_symbols(stack_addrs, stack_depth);
51 
52 	int space = len - strlen(str);
53 	strncat(str, msg, max(space, 0));
54 	space -= sizeof(msg) - 1;
55 
56     for (size_t i = 0; i < stack_depth && space > 0; i++) {
57 
58 		char * start = strchr(stack_strings[i], '(');
59 		if (start == NULL) continue;
60 
61 		size_t len;
62 		int stat;
63 
64 		char * end = strchr(start, '+');
65 		if (end != NULL) *end = '\0';
66 
67 		char * demangled = abi::__cxa_demangle(start+1, NULL, &len, &stat);
68 
69 		if (stat == 0 && demangled != NULL){
70 			strncat(str, demangled, max(space, 0));
71 			space -= len;
72 		}else{
73 			strncat(str, start, max(space, 0));
74 			space -= strlen(start);
75 		}
76 		if (demangled != NULL) free(demangled);
77 
78 		strncat(str, "\n", max(space, 0));
79 		space -= 1;
80     }
81 
82     free(stack_strings);
83 }
84 #endif
85 
86 
Panic(const char * msg)87 void    Panic(const char *msg)
88 {
89 #ifdef PLATFORM_POSIX
90 	signal(SIGILL, SIG_DFL);
91 	signal(SIGSEGV, SIG_DFL);
92 	signal(SIGBUS, SIG_DFL);
93 	signal(SIGFPE, SIG_DFL);
94 #endif
95 	if(PanicMode)
96 		return;
97 	PanicMode = true;
98 	RLOG("****************** PANIC: " << msg << "\n");
99 	PanicMessageBox("Fatal error", msg);
100 
101 #ifdef PLATFORM_WIN32
102 #	ifdef __NOASSEMBLY__
103 #		if defined(PLATFORM_WINCE) || defined(WIN64)
104 			DebugBreak();
105 #		endif
106 #	else
107 #		if defined(_DEBUG) && defined(CPU_X86)
108 #			ifdef COMPILER_MSC
109 				_asm int 3
110 #			endif
111 #			ifdef COMPILER_GCC
112 				asm("int $3");
113 #			endif
114 #		endif
115 #	endif
116 #else
117 #endif
118 #ifdef _DEBUG
119 	__BREAK__;
120 #endif
121 	abort();
122 }
123 
124 static void (*s_assert_hook)(const char *);
125 
SetAssertFailedHook(void (* h)(const char *))126 void    SetAssertFailedHook(void (*h)(const char *))
127 {
128 	s_assert_hook = h;
129 }
130 
AssertFailed(const char * file,int line,const char * cond)131 void    AssertFailed(const char *file, int line, const char *cond)
132 {
133 	if(PanicMode)
134 		return;
135 	PanicMode = true;
136 	char s[2048];
137 	sprintf(s, "Assertion failed in %s, line %d\n%s\n", file, line, cond);
138 #if defined(PLATFORM_LINUX) && defined(COMPILER_GCC) && defined(flagSTACKTRACE)
139 	AddStackTrace(s, sizeof(s));
140 #endif
141 
142 	if(s_assert_hook)
143 		(*s_assert_hook)(s);
144 	RLOG("****************** ASSERT FAILED: " << s << "\n");
145 #ifdef PLATFORM_POSIX
146 	RLOG("LastErrorMessage: " << strerror(errno)); // do not translate
147 #else
148 	RLOG("LastErrorMessage: " << GetLastErrorMessage());
149 #endif
150 
151 	PanicMessageBox("Fatal error", s);
152 
153 #ifdef PLATFORM_WIN32
154 #	ifdef __NOASSEMBLY__
155 #		if defined(PLATFORM_WINCE) || defined(WIN64)
156 			DebugBreak();
157 #		endif
158 #	else
159 #		if defined(_DEBUG) && defined(CPU_X86)
160 #			ifdef COMPILER_MSC
161 				_asm int 3
162 #			endif
163 #			ifdef COMPILER_GCC
164 				asm("int $3");
165 #			endif
166 #		endif
167 #	endif
168 #else
169 #endif
170 
171 	__BREAK__;
172 	abort();
173 }
174 
175 #ifdef PLATFORM_POSIX
GetTickCount()176 dword GetTickCount() {
177 #if _POSIX_C_SOURCE >= 199309L
178 	struct timespec tp;
179 	if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
180 	{
181 		return (dword)((tp.tv_sec * 1000) + (tp.tv_nsec / 1000000));
182 	}
183 	return 0; // ?? (errno is set)
184 #else
185 	struct timeval tv[1];
186 	struct timezone tz[1];
187 	memset(tz, 0, sizeof(tz));
188 	gettimeofday(tv, tz);
189 	return (dword)tv->tv_sec * 1000 + tv->tv_usec / 1000;
190 #endif
191 }
192 #endif
193 
usecs(int64 prev)194 int64 usecs(int64 prev)
195 {
196 	auto p2 = std::chrono::high_resolution_clock::now();
197 	return std::chrono::duration_cast<std::chrono::microseconds>(p2.time_since_epoch()).count() - prev;
198 }
199 
msecs(int from)200 int msecs(int from) { return GetTickCount() - (dword)from; }
201 
202 /* // it looks like there might be a problem with std::chrono in llvm-mingw, reverting to original implementation for now
203 int msecs(int prev)
204 {
205 	auto p2 = std::chrono::steady_clock::now();
206 	return (int)std::chrono::duration_cast<std::chrono::milliseconds>(p2.time_since_epoch()).count() - prev;
207 }
208 */
209 
Reset()210 void TimeStop::Reset()
211 {
212 	starttime = (double)usecs();
213 }
214 
TimeStop()215 TimeStop::TimeStop()
216 {
217 	Reset();
218 }
219 
ToString() const220 String TimeStop::ToString() const
221 {
222 	double time = Elapsed();
223 	if(time < 1e3)
224 		return String() << time << " us";
225 	if(time < 1e6)
226 		return String() << time / 1e3 << " ms";
227 	return String() << time / 1e6 << " s";
228 }
229 
RegisterTypeNo__(const char * type)230 int RegisterTypeNo__(const char *type)
231 {
232 	INTERLOCKED {
233 		static Index<String> types;
234 		return types.FindAdd(type);
235 	}
236 	return -1;
237 }
238 
PermanentCopy(const char * s)239 char *PermanentCopy(const char *s)
240 {
241 	char *t = (char *)MemoryAllocPermanent(strlen(s) + 1);
242 	strcpy(t, s);
243 	return t;
244 }
245 
246 #ifndef PLATFORM_WIN32
Sleep(int msec)247 void Sleep(int msec)
248 {
249 	::timespec tval;
250 	tval.tv_sec = msec / 1000;
251 	tval.tv_nsec = (msec % 1000) * 1000000;
252 	nanosleep(&tval, NULL);
253 }
254 #endif
255 
MemICmp(const void * dest,const void * src,int count)256 int MemICmp(const void *dest, const void *src, int count)
257 {
258 
259 	const byte *a = (const byte *)dest;
260 	const byte *b = (const byte *)src;
261 	const byte *l = a + count;
262 	while(a < l) {
263 		if(ToUpper(*a) != ToUpper(*b))
264 			return ToUpper(*a) - ToUpper(*b);
265 		a++;
266 		b++;
267 	}
268 	return 0;
269 }
270 
Pack16(Stream & s,Point & p)271 Stream& Pack16(Stream& s, Point& p) {
272 	return Pack16(s, p.x, p.y);
273 }
274 
Pack16(Stream & s,Size & sz)275 Stream& Pack16(Stream& s, Size& sz) {
276 	return Pack16(s, sz.cx, sz.cy);
277 }
278 
Pack16(Stream & s,Rect & r)279 Stream& Pack16(Stream& s, Rect& r) {
280 	return Pack16(s, r.left, r.top, r.right, r.bottom);
281 }
282 
InScListIndex(const char * s,const char * list)283 int InScListIndex(const char *s, const char *list)
284 {
285 	int ii = 0;
286 	for(;;) {
287 		const char *q = s;
288 		for(;;) {
289 			if(*q == '\0' && *list == '\0') return ii;
290 			if(*q != *list) {
291 				if(*q == '\0' && *list == ';') return ii;
292 				if(*list == '\0') return -1;
293 				break;
294 			}
295 			q++;
296 			list++;
297 		}
298 		while(*list && *list != ';') list++;
299 		if(*list == '\0') return -1;
300 		list++;
301 		ii++;
302 	}
303 }
304 
InScList(const char * s,const char * list)305 bool InScList(const char *s, const char *list)
306 {
307 	return InScListIndex(s, list) >= 0;
308 }
309 
timeFormat(double s)310 String timeFormat(double s) {
311 	if(s < 0.000001) return Sprintf("%5.2f ns", s * 1.0e9);
312 	if(s < 0.001) return Sprintf("%5.2f us", s * 1.0e6);
313 	if(s < 1) return Sprintf("%5.2f ms", s * 1.0e3);
314 	return Sprintf("%5.2f s ", s);
315 }
316 
Garble(const char * s,const char * e)317 String Garble(const char *s, const char *e)
318 {
319 	int c = 0xAA;
320 	String result;
321 	if(!e)
322 		e = s + strlen(s);
323 	while(s != e)
324 	{
325 		result.Cat(*s++ ^ (char)c);
326 		if((c <<= 1) & 0x100)
327 			c ^= 0x137;
328 	}
329 	return result;
330 }
331 
Garble(const String & s)332 String Garble(const String& s)
333 {
334 	return Garble(~s, ~s + s.GetLength());
335 }
336 
Encode64(const String & s)337 String Encode64(const String& s)
338 {
339 	String enc;
340 	int l = s.GetLength();
341 	enc << l << ':';
342 	for(int i = 0; i < l;)
343 	{
344 		char a = 0, b = 0, c = 0;
345 		if(i < l) a = s[i++];
346 		if(i < l) b = s[i++];
347 		if(i < l) c = s[i++];
348 		enc.Cat(' ' + 1 + ((a >> 2) & 0x3F));
349 		enc.Cat(' ' + 1 + ((a << 4) & 0x30) + ((b >> 4) & 0x0F));
350 		enc.Cat(' ' + 1 + ((b << 2) & 0x3C) + ((c >> 6) & 0x03));
351 		enc.Cat(' ' + 1 + (c & 0x3F));
352 	}
353 	return enc;
354 }
355 
Decode64(const String & s)356 String Decode64(const String& s)
357 {
358 	if(!IsDigit(*s))
359 		return s;
360 	const char *p = s;
361 	char *h;
362 	int len = strtol(p, &h, 10);
363 	p = h;
364 	if(*p++ != ':' || len < 0 || (len + 2) / 3 * 4 > (s.End() - p))
365 		return s; // invalid encoding
366 	if(len == 0)
367 		return Null;
368 	String dec;
369 	for(;;)
370 	{
371 		byte ea = *p++ - ' ' - 1, eb = *p++ - ' ' - 1, ec = *p++ - ' ' - 1, ed = *p++ - ' ' - 1;
372 		byte out[3] = { byte((ea << 2) | (eb >> 4)), byte((eb << 4) | (ec >> 2)), byte((ec << 6) | (ed >> 0)) };
373 		switch(len)
374 		{
375 		case 1:  dec.Cat(out[0]); return dec;
376 		case 2:  dec.Cat(out, 2); return dec;
377 		case 3:  dec.Cat(out, 3); return dec;
378 		default: dec.Cat(out, 3); len -= 3; break;
379 		}
380 	}
381 }
382 
HexString(const byte * s,int count,int sep,int sepchr)383 String HexString(const byte *s, int count, int sep, int sepchr)
384 {
385 	ASSERT(count >= 0);
386 	if(count == 0)
387 		return String();
388 	StringBuffer b(2 * count + (count - 1) / sep);
389 	static const char itoc[] = "0123456789abcdef";
390 	int i = 0;
391 	char *t = b;
392 	for(;;) {
393 		for(int q = 0; q < sep; q++) {
394 			if(i >= count)
395 				return String(b);
396 			*t++ = itoc[(s[i] & 0xf0) >> 4];
397 			*t++ = itoc[s[i] & 0x0f];
398 			i++;
399 		}
400 		if(i >= count)
401 			return String(b);
402 		*t++ = sepchr;
403 	}
404 }
405 
HexString(const String & s,int sep,int sepchr)406 String HexString(const String& s, int sep, int sepchr)
407 {
408 	return HexString(~s, s.GetCount(), sep, sepchr);
409 }
410 
HexEncode(const byte * s,int count,int sep,int sepchr)411 String HexEncode(const byte *s, int count, int sep, int sepchr)
412 {
413 	return HexString(s, count, sep, sepchr);
414 }
415 
HexEncode(const String & s,int sep,int sepchr)416 String HexEncode(const String& s, int sep, int sepchr)
417 {
418 	return HexString(s, sep, sepchr);
419 }
420 
ScanHexString(const char * s,const char * lim)421 String ScanHexString(const char *s, const char *lim)
422 {
423 	String r;
424 	r.Reserve(int(lim - s) / 2);
425 	for(;;) {
426 		byte b = 0;
427 		while(!IsXDigit(*s)) {
428 			if(s >= lim)
429 				return r;
430 			s++;
431 		}
432 		b = ctoi(*s++);
433 		if(s >= lim)
434 			return r;
435 		while(!IsXDigit(*s)) {
436 			if(s >= lim) {
437 				r.Cat(b);
438 				return r;
439 			}
440 			s++;
441 		}
442 		b = (b << 4) + ctoi(*s++);
443 		r.Cat(b);
444 		if(s >= lim)
445 			return r;
446 	}
447 }
448 
HexDecode(const char * s,const char * lim)449 String HexDecode(const char *s, const char *lim)
450 {
451 	return ScanHexString(s, lim);
452 }
453 
454 
NormalizeSpaces(const char * s)455 String NormalizeSpaces(const char *s)
456 {
457 	StringBuffer r;
458 	while(*s && (byte)*s <= ' ')
459 		s++;
460 	while(*s) {
461 		if((byte)*s <= ' ') {
462 			while(*s && (byte)*s <= ' ')
463 				s++;
464 			if(*s)
465 				r.Cat(' ');
466 		}
467 		else
468 			r.Cat(*s++);
469 	}
470 	return String(r);
471 }
472 
NormalizeSpaces(const char * s,const char * end)473 String NormalizeSpaces(const char *s, const char *end)
474 {
475 	StringBuffer r;
476 	while(*s && (byte)*s <= ' ')
477 		s++;
478 	while(s < end) {
479 		if((byte)*s <= ' ') {
480 			while(s < end && (byte)*s <= ' ')
481 				s++;
482 			if(*s)
483 				r.Cat(' ');
484 		}
485 		else
486 			r.Cat(*s++);
487 	}
488 	return String(r);
489 }
490 
CsvString(const String & text)491 String CsvString(const String& text)
492 {
493 	String r;
494 	r << '\"';
495 	const char *s = text;
496 	while(*s) {
497 		if(*s == '\"')
498 			r << "\"\"";
499 		else
500 			r.Cat(*s);
501 		s++;
502 	}
503 	r << '\"';
504 	return r;
505 }
506 
GetCsvLine(Stream & s,int separator,byte charset)507 Vector<String> GetCsvLine(Stream& s, int separator, byte charset)
508 {
509 	Vector<String> r;
510 	bool instring = false;
511 	String val;
512 	byte dcs = GetDefaultCharset();
513 	for(;;) {
514 		int c = s.Get();
515 		if(c == '\n' && instring)
516 			val.Cat(c);
517 		else
518 		if(c == '\n' || c < 0) {
519 			if(val.GetCount())
520 				r.Add(ToCharset(dcs, val, charset));
521 			return r;
522 		}
523 		else
524 		if(c == separator && !instring) {
525 			r.Add(ToCharset(dcs, val, charset));
526 			val.Clear();
527 		}
528 		else
529 		if(c == '\"') {
530 			if(instring && s.Term() == '\"') {
531 				s.Get();
532 				val.Cat('\"');
533 			}
534 			else
535 				instring = !instring;
536 		}
537 		else
538 		if(c != '\r')
539 			val.Cat(c);
540 	}
541 }
542 
CompressLog(const char * s)543 String CompressLog(const char *s)
544 {
545 	static bool breaker[256];
546 	ONCELOCK {
547 		for(int i = 0; i < 256; i++)
548 		breaker[i] = IsSpace(i) || findarg(i, '<', '>', '\"', '\'', ',', '.', '[', ']', '{', '}', '(', ')') >= 0;
549 	}
550 
551 	StringBuffer result;
552 	while(*s) {
553 		const char *b = s;
554 		while(breaker[(byte)*s])
555 			s++;
556 		result.Cat(b, s);
557 		if(!*s)
558 			break;
559 		b = s;
560 		while(*s && !breaker[(byte)*s])
561 			s++;
562 		if(s - b > 200) {
563 			result.Cat(b, 20);
564 			result.Cat("....", 4);
565 			result << "[" << int(s - b) << " bytes]";
566 			result.Cat("....", 4);
567 			result.Cat(s - 20, 20);
568 		}
569 		else
570 			result.Cat(b, s);
571 	}
572 	return String(result);
573 }
574 
ChNoInvalid(int c)575 int ChNoInvalid(int c)
576 {
577 	return c == DEFAULTCHAR ? '_' : c;
578 }
579 
580 #ifdef PLATFORM_WINCE
ToSystemCharset(const String & src)581 WString ToSystemCharset(const String& src)
582 {
583 	return src.ToWString();
584 }
585 
FromSystemCharset(const WString & src)586 String FromSystemCharset(const WString& src)
587 {
588 	return src.ToString();
589 }
590 #else
591 
592 #ifdef PLATFORM_WIN32
ToSystemCharset(const String & src,int cp)593 String ToSystemCharset(const String& src, int cp)
594 {
595 	WString s = src.ToWString();
596 	int l = s.GetLength() * 5;
597 	StringBuffer b(l);
598 	int q = WideCharToMultiByte(cp, 0, (const WCHAR *)~s, s.GetLength(), b, l, NULL, NULL);
599 	if(q <= 0)
600 		return src;
601 	b.SetCount(q);
602 	return String(b);
603 }
604 
ToSystemCharset(const String & src)605 String ToSystemCharset(const String& src)
606 {
607 	return ToSystemCharset(src, CP_ACP);
608 }
609 
FromWin32Charset(const String & src,int cp)610 String FromWin32Charset(const String& src, int cp)
611 {
612 	WStringBuffer b(src.GetLength());
613 	int q = MultiByteToWideChar(cp, MB_PRECOMPOSED, ~src, src.GetLength(), (WCHAR*)~b, src.GetLength());
614 	if(q <= 0)
615 		return src;
616 	b.SetCount(q);
617 	return WString(b).ToString();
618 }
619 
FromOEMCharset(const String & src)620 String FromOEMCharset(const String& src)
621 {
622 	return FromWin32Charset(src, CP_OEMCP);
623 }
624 
FromSystemCharset(const String & src)625 String FromSystemCharset(const String& src)
626 {
627 	return FromWin32Charset(src, CP_ACP);
628 }
629 
ToSystemCharsetW(const char * src)630 WString ToSystemCharsetW(const char *src)
631 {
632 	return String(src).ToWString();
633 }
634 
FromSystemCharsetW(const wchar * src)635 String FromSystemCharsetW(const wchar *src)
636 {
637 	return WString(src).ToString();
638 }
639 
640 #else
ToSystemCharset(const String & src)641 String ToSystemCharset(const String& src)
642 {
643 	return IsMainRunning() ? Filter(ToCharset(GetLNGCharset(GetSystemLNG()), src), ChNoInvalid)
644 	                       : src;
645 }
646 
FromSystemCharset(const String & src)647 String FromSystemCharset(const String& src)
648 {
649 	return IsMainRunning() ? Filter(ToCharset(CHARSET_DEFAULT, src, GetLNGCharset(GetSystemLNG())), ChNoInvalid) : src;
650 }
651 #endif
652 #endif
653 
654 
655 static StaticMutex sGCfgLock;
656 
sGCfg()657 static VectorMap<String, String>& sGCfg()
658 {
659 	static VectorMap<String, String> h;
660 	return h;
661 }
662 
sGFlush()663 static Vector<Event<>>& sGFlush()
664 {
665 	static Vector<Event<>> h;
666 	return h;
667 }
668 
sGSerialize()669 static VectorMap<String, Event<Stream&>>& sGSerialize()
670 {
671 	static VectorMap<String, Event<Stream&>> h;
672 	return h;
673 }
674 
RegisterGlobalConfig(const char * name)675 void    RegisterGlobalConfig(const char *name)
676 {
677 	Mutex::Lock __(sGCfgLock);
678 	ASSERT(sGCfg().Find(name) < 0);
679 	sGCfg().Add(name);
680 }
681 
RegisterGlobalSerialize(const char * name,Event<Stream &> WhenSerialize)682 void    RegisterGlobalSerialize(const char *name, Event<Stream&> WhenSerialize)
683 {
684 	Mutex::Lock __(sGCfgLock);
685 	RegisterGlobalConfig(name);
686 	sGSerialize().Add(name, WhenSerialize);
687 }
688 
RegisterGlobalConfig(const char * name,Event<> WhenFlush)689 void    RegisterGlobalConfig(const char *name, Event<>  WhenFlush)
690 {
691 	Mutex::Lock __(sGCfgLock);
692 	RegisterGlobalConfig(name);
693 	sGFlush().Add(WhenFlush);
694 }
695 
GetGlobalConfigData(const char * name)696 String GetGlobalConfigData(const char *name)
697 {
698 	Mutex::Lock __(sGCfgLock);
699 	return sGCfg().GetAdd(name);
700 }
701 
SetGlobalConfigData(const char * name,const String & data)702 void SetGlobalConfigData(const char *name, const String& data)
703 {
704 	Mutex::Lock __(sGCfgLock);
705 	sGCfg().GetAdd(name) = data;
706 }
707 
LoadFromGlobal(Event<Stream &> x,const char * name)708 bool LoadFromGlobal(Event<Stream&> x, const char *name)
709 {
710 	StringStream ss(GetGlobalConfigData(name));
711 	return ss.IsEof() || Load(x, ss);
712 }
713 
StoreToGlobal(Event<Stream &> x,const char * name)714 void StoreToGlobal(Event<Stream&> x, const char *name)
715 {
716 	StringStream ss;
717 	Store(x, ss);
718 	SetGlobalConfigData(name, ss);
719 }
720 
SerializeGlobalConfigs(Stream & s)721 void  SerializeGlobalConfigs(Stream& s)
722 {
723 	Mutex::Lock __(sGCfgLock);
724 	for(int i = 0; i < sGFlush().GetCount(); i++)
725 		sGFlush()[i]();
726 	int version = 0;
727 	s / version;
728 	int count = sGCfg().GetCount();
729 	s / count;
730 	for(int i = 0; i < count; i++) {
731 		String name;
732 		if(s.IsStoring())
733 			name = sGCfg().GetKey(i);
734 		s % name;
735 		int q = sGCfg().Find(name);
736 		if(q >= 0) {
737 			int w = sGSerialize().Find(name);
738 			if(w >= 0) {
739 				String h;
740 				if(s.IsStoring()) {
741 					StringStream ss;
742 					sGSerialize()[w](ss);
743 					h = ss;
744 				}
745 				s % h;
746 				if(s.IsLoading()) {
747 					StringStream ss(h);
748 					sGSerialize()[w](ss);
749 				}
750 			}
751 			else
752 				s % sGCfg()[q];
753 		}
754 		else {
755 			String dummy;
756 			s % dummy;
757 		}
758 	}
759 	s.Magic();
760 }
761 
AbortExc()762 AbortExc::AbortExc() :
763 	Exc(t_("Aborted by user.")) {}
764 
765 #ifdef PLATFORM_WIN32
766 
GetErrorMessage(DWORD dwError)767 String GetErrorMessage(DWORD dwError) {
768 	char h[2048];
769 	sprintf(h, "%08x", (int)dwError);
770 #ifdef PLATFORM_WINCE //TODO
771 	return h;
772 #else
773 	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
774 		          NULL, dwError, 0, h, 2048, NULL);
775 	String result = h;
776 	String modf;
777 	const char* s = result;
778 	BYTE c;
779 	while((c = *s++) != 0)
780 		if(c <= ' ') {
781 			if(!modf.IsEmpty() && modf[modf.GetLength() - 1] != ' ')
782 				modf += ' ';
783 		}
784 		else if(c == '%' && *s >= '0' && *s <= '9') {
785 			s++;
786 			modf += "<###>";
787 		}
788 		else
789 			modf += (char)c;
790 	const char* p = modf;
791 	for(s = p + modf.GetLength(); s > p && s[-1] == ' '; s--);
792 	return FromSystemCharset(modf.Left((int)(s - p)));
793 #endif
794 }
795 
GetLastErrorMessage()796 String GetLastErrorMessage() {
797 	return GetErrorMessage(GetLastError()) + " (" + AsString(GetLastError()) + ")";
798 }
799 
800 #endif
801 
802 #ifdef PLATFORM_POSIX
803 
GetErrorMessage(int errorno)804 String GetErrorMessage(int errorno)
805 {
806 	// Linux strerror_r declaration might be different than posix
807 	// hence we are using strerror with mutex... (cxl 2008-07-17)
808 	static StaticMutex m;
809 	Mutex::Lock __(m);
810 	return FromSystemCharset(strerror(errorno));
811 }
812 
GetLastErrorMessage()813 String GetLastErrorMessage() {
814 	return GetErrorMessage(errno) + " (" + AsString(errno) + ")";
815 }
816 
817 #endif
818 
819 #ifdef PLATFORM_POSIX
820 #ifndef PLATFORM_COCOA
821 
822 String CurrentSoundTheme = "freedesktop";
823 
LinuxBeep(const char * name)824 static void LinuxBeep(const char *name)
825 {
826 	static String player;
827 	ONCELOCK {
828 		const char *players[] = { "play", "ogg123", "gst123" };
829 		for(int i = 0; i < __countof(players); i++)
830 			if(Sys("which " + String(players[i])).GetCount()) {
831 				player = players[i];
832 				break;
833 			}
834 	}
835 
836 	if(player.GetCount()) {
837 		String fn = "/usr/share/sounds/" + CurrentSoundTheme + "/stereo/dialog-" + name;
838 		IGNORE_RESULT(system(player + " -q " + fn +
839 		              (FileExists(fn + ".ogg") ? ".ogg" :
840 		               FileExists(fn + ".oga") ? ".oga" :
841 	                   FileExists(fn + ".wav") ? ".wav" :
842 	                   ".*")
843 		              + " >/dev/null 2>/dev/null&"));
844 	}
845 }
846 
847 #endif
848 #endif
849 
850 #ifdef PLATFORM_COCOA
851 void (*CocoBeepFn)();
852 
DoCocoBeep()853 void DoCocoBeep()
854 {
855 	if(CocoBeepFn)
856 		(*CocoBeepFn)();
857 }
858 
859 #endif
860 
BeepInformation()861 void BeepInformation()
862 {
863 #ifdef PLATFORM_WIN32
864 	MessageBeep(MB_ICONINFORMATION);
865 #elif defined(PLATFORM_COCOA)
866 	DoCocoBeep();
867 #else
868 	LinuxBeep("information");
869 #endif
870 }
871 
BeepExclamation()872 void BeepExclamation()
873 {
874 #ifdef PLATFORM_WIN32
875 	MessageBeep(MB_ICONEXCLAMATION);
876 #elif defined(PLATFORM_COCOA)
877 	DoCocoBeep();
878 #else
879 	LinuxBeep("warning");
880 #endif
881 }
882 
BeepError()883 void BeepError()
884 {
885 #ifdef PLATFORM_WIN32
886 	MessageBeep(MB_ICONERROR);
887 #elif defined(PLATFORM_COCOA)
888 	DoCocoBeep();
889 #else
890 	LinuxBeep("error");
891 #endif
892 }
893 
BeepQuestion()894 void BeepQuestion()
895 {
896 #ifdef PLATFORM_WIN32
897 	MessageBeep(MB_ICONQUESTION);
898 #elif defined(PLATFORM_COCOA)
899 	DoCocoBeep();
900 #else
901 	LinuxBeep("question");
902 #endif
903 }
904 
905 #if defined(COMPILER_MSC) && (_MSC_VER < 1300)
906 //hack for linking libraries built using VC7 with VC6 standard lib's
907 extern "C" long _ftol( double );
_ftol2(double dblSource)908 extern "C" long _ftol2( double dblSource ) { return _ftol( dblSource ); }
909 #endif
910 
911 #ifdef PLATFORM_WINCE
912 int errno; // missing and zlib needs it
913 #endif
914 
915 
916 template <class CHR, class T>
Replace__(const T & s,const Vector<T> & find,const Vector<T> & replace)917 T Replace__(const T& s, const Vector<T>& find, const Vector<T>& replace)
918 {
919 	ASSERT(find.GetCount() == replace.GetCount());
920 
921 	T r;
922 	int i = 0;
923 	while(i < s.GetCount()) {
924 		int best = -1;
925 		int bestlen = 0;
926 		int len = s.GetCount() - i;
927 		const CHR *q = ~s + i;
928 		for(int j = 0; j < replace.GetCount(); j++) {
929 			const T& m = find[j];
930 			int l = m.GetCount();
931 			if(l <= len && l > bestlen && memcmp(~m, q, l * sizeof(CHR)) == 0) {
932 				bestlen = l;
933 				best = j;
934 			}
935 		}
936 		if(best >= 0) {
937 			i += bestlen;
938 			r.Cat(replace[best]);
939 		}
940 		else {
941 			r.Cat(*q);
942 			i++;
943 		}
944 	}
945 	return r;
946 }
947 
Replace(const String & s,const Vector<String> & find,const Vector<String> & replace)948 String Replace(const String& s, const Vector<String>& find, const Vector<String>& replace)
949 {
950 	return Replace__<char>(s, find, replace);
951 }
952 
Replace(const String & s,const VectorMap<String,String> & fr)953 String Replace(const String& s, const VectorMap<String, String>& fr)
954 {
955 	return Replace__<char>(s, fr.GetKeys(), fr.GetValues());
956 }
957 
Replace(const WString & s,const Vector<WString> & find,const Vector<WString> & replace)958 WString Replace(const WString& s, const Vector<WString>& find, const Vector<WString>& replace)
959 {
960 	return Replace__<wchar>(s, find, replace);
961 }
962 
Replace(const WString & s,const VectorMap<WString,WString> & fr)963 WString Replace(const WString& s, const VectorMap<WString, WString>& fr)
964 {
965 	return Replace__<wchar>(s, fr.GetKeys(), fr.GetValues());
966 }
967 
968 
969 String (*GetP7Signature__)(const void *data, int length, const String& cert_pem, const String& pkey_pem);
970 
GetP7Signature(const void * data,int length,const String & cert_pem,const String & pkey_pem)971 String GetP7Signature(const void *data, int length, const String& cert_pem, const String& pkey_pem)
972 {
973 	ASSERT_(GetP7Signature__, "Missing SSL support (Core/SSL)");
974 	return (*GetP7Signature__)(data, length, cert_pem, pkey_pem);
975 }
976 
GetP7Signature(const String & data,const String & cert_pem,const String & pkey_pem)977 String GetP7Signature(const String& data, const String& cert_pem, const String& pkey_pem)
978 {
979 	return GetP7Signature(data, data.GetLength(), cert_pem, pkey_pem);
980 }
981 
982 }
983