#include "Core.h" #ifdef PLATFORM_WIN32 #include #endif NAMESPACE_UPP bool PanicMode; bool IsPanicMode() { return PanicMode; } void Panic(const char *msg) { if(PanicMode) return; PanicMode = true; LOG(msg); LOG(GetLastErrorMessage()); BugLog() << "PANIC: " << msg << "\n"; UsrLogT("===== PANIC ================================================"); UsrLogT(msg); #ifdef PLATFORM_WIN32 #ifdef PLATFORM_WINCE MessageBox(::GetActiveWindow(), ToSysChrSet(msg), L"Panic", MB_ICONSTOP | MB_OK | MB_APPLMODAL); #else MessageBox(::GetActiveWindow(), msg, "Panic", MB_ICONSTOP | MB_OK | MB_APPLMODAL); #endif #if defined(_DEBUG) && defined(CPU_X86) #ifdef COMPILER_MSC _asm int 3 #endif #ifdef COMPILER_GCC asm("int $3"); #endif #endif #else write(2, msg, strlen(msg)); write(2, "\n", 1); #endif LOG(GetLastErrorMessage()); abort(); } static void (*s_assert_hook)(const char *); void SetAssertFailedHook(void (*h)(const char *)) { s_assert_hook = h; } void AssertFailed(const char *file, int line, const char *cond) { if(PanicMode) return; PanicMode = true; char s[2048]; sprintf(s, "Assertion failed in %s, line %d\n%s\n", file, line, cond); LOG(s); LOG(GetLastErrorMessage()); if(s_assert_hook) (*s_assert_hook)(s); BugLog() << "ASSERT FAILED: " << s << "\n"; UsrLogT("===== ASSERT FAILED ================================================"); UsrLogT(s); #ifdef PLATFORM_WIN32 #ifdef PLATFORM_WINCE MessageBox(::GetActiveWindow(), ToSysChrSet(s), L"Assertion failed", MB_ICONSTOP | MB_OK | MB_APPLMODAL); #else MessageBox(::GetActiveWindow(), s, "Assertion failed", MB_ICONSTOP | MB_OK | MB_APPLMODAL); #endif #ifdef CPU_X86 #ifdef COMPILER_MSC _asm int 3 #endif #ifdef COMPILER_GCC asm("int $3"); #endif #endif #else write(2, s, strlen(s)); #endif abort(); } #ifdef PLATFORM_POSIX int GetTickCount() { struct timeval tv[1]; struct timezone tz[1]; memset(tz, 0, sizeof(tz)); gettimeofday(tv, tz); return tv->tv_sec % 1000000 * 1000 + tv->tv_usec / 1000; } #endif TimeStop::TimeStop() { starttime = GetTickCount(); } String TimeStop::ToString() const { dword time = Elapsed(); return Format("%d.%03d", int(time / 1000), int(time % 1000)); } int RegisterTypeNo__(const char *type) { INTERLOCKED { static Index types; return types.FindAdd(type); } return -1; } char *PermanentCopy(const char *s) { char *t = (char *)MemoryAllocPermanent(strlen(s) + 1); strcpy(t, s); return t; } #ifndef CPU_X86 int PeekIW(const void *ptr) { const byte *p = (const byte *)ptr; return (p[0] << 8 * 0) | (p[1] << 8 * 1); } #endif #ifndef CPU_X86 int PeekIL(const void *ptr) { const byte *p = (const byte *)ptr; return (p[0] << 8 * 0) | (p[1] << 8 * 1) | (p[2] << 8 * 2) | (p[3] << 8 * 3); } #endif #ifndef CPU_X86 int64 PeekI64(const void *ptr) { const byte *p = (const byte *)ptr; dword a = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); dword b = p[4] | (p[5] << 8) | (p[6] << 16) | (p[7] << 24); return (int64)a | ((int64)b << 32); } #endif int PeekMW(const void *ptr) { const byte *p = (const byte *)ptr; return (p[1] << 8 * 0) | (p[0] << 8 * 1); } int PeekML(const void *ptr) { const byte *p = (const byte *)ptr; return (p[3] << 8 * 0) | (p[2] << 8 * 1) | (p[1] << 8 * 2) | (p[0] << 8 * 3); } #ifndef CPU_X86 void PokeIW(void *ptr, int value) { byte *p = (byte *)ptr; p[0] = (byte)(value >> 0); p[1] = (byte)(value >> 8); } #endif #ifndef CPU_X86 void PokeIL(void *ptr, int value) { byte *p = (byte *)ptr; p[0] = (byte)(value >> 0); p[1] = (byte)(value >> 8); p[2] = (byte)(value >> 16); p[3] = (byte)(value >> 24); } #endif #ifndef CPU_X86 void PokeI64(void *ptr, int64 value) { byte *p = (byte *)ptr; p[0] = (byte)(value >> 8 * 0); p[1] = (byte)(value >> 8 * 1); p[2] = (byte)(value >> 8 * 2); p[3] = (byte)(value >> 8 * 3); p[4] = (byte)(value >> 8 * 4); p[5] = (byte)(value >> 8 * 5); p[6] = (byte)(value >> 8 * 6); p[7] = (byte)(value >> 8 * 7); } #endif #ifndef CPU_X86 void PokeIF4(void *ptr, float value) { ASSERT(sizeof(float) == 4); union { float f; byte b[4]; }; f = value; #ifdef CPU_LE memcpy(ptr, b, 4); #else ((byte *)ptr)[0] = b[3]; ((byte *)ptr)[1] = b[2]; ((byte *)ptr)[2] = b[1]; ((byte *)ptr)[3] = b[0]; #endif } #endif #ifndef CPU_X86 float PeekIF4(const void *ptr) { ASSERT(sizeof(float) == 4); union { float f; byte b[4]; }; #ifdef CPU_LE memcpy(b, ptr, 4); #else b[3] = ((byte *)ptr)[0]; b[2] = ((byte *)ptr)[1]; b[1] = ((byte *)ptr)[2]; b[0] = ((byte *)ptr)[3]; #endif return f; } #endif #ifndef CPU_X86 void PokeID8(void *ptr, double value) { ASSERT(sizeof(double) == 8); union { double d; byte b[8]; }; d = value; #ifdef CPU_LE memcpy(ptr, b, 8); #else ((byte *)ptr)[0] = b[7]; ((byte *)ptr)[1] = b[6]; ((byte *)ptr)[2] = b[5]; ((byte *)ptr)[3] = b[4]; ((byte *)ptr)[0] = b[3]; ((byte *)ptr)[1] = b[2]; ((byte *)ptr)[2] = b[1]; ((byte *)ptr)[3] = b[0]; #endif } #endif #ifndef CPU_X86 double PeekID8(const void *ptr) { ASSERT(sizeof(double) == 8); union { double d; byte b[8]; }; #ifdef CPU_LE memcpy(b, ptr, 8); #else b[7] = ((byte *)ptr)[0]; b[6] = ((byte *)ptr)[1]; b[5] = ((byte *)ptr)[2]; b[4] = ((byte *)ptr)[3]; b[3] = ((byte *)ptr)[4]; b[2] = ((byte *)ptr)[5]; b[1] = ((byte *)ptr)[6]; b[0] = ((byte *)ptr)[7]; #endif return d; } #endif void PokeMW(void *ptr, int value) { byte *p = (byte *)ptr; p[1] = (byte)(value >> 0); p[0] = (byte)(value >> 8); } void PokeML(void *ptr, int value) { byte *p = (byte *)ptr; p[3] = (byte)(value >> 0); p[2] = (byte)(value >> 8); p[1] = (byte)(value >> 16); p[0] = (byte)(value >> 24); } #define ENDIAN_SWAP { while(count--) { EndianSwap(*v++); } } void EndianSwap(word *v, int count) ENDIAN_SWAP void EndianSwap(int16 *v, int count) ENDIAN_SWAP void EndianSwap(dword *v, int count) ENDIAN_SWAP void EndianSwap(int *v, int count) ENDIAN_SWAP //void EndianSwap(long *v, int count) ENDIAN_SWAP void EndianSwap(int64 *v, int count) ENDIAN_SWAP void EndianSwap(uint64 *v, int count) ENDIAN_SWAP #ifndef PLATFORM_WIN32 void Sleep(int msec) { timespec tval; tval.tv_sec = msec / 1000; tval.tv_nsec = (msec % 1000) * 1000000; nanosleep(&tval, NULL); } #endif int MemICmp(const void *dest, const void *src, int count) { const byte *a = (const byte *)dest; const byte *b = (const byte *)src; const byte *l = a + count; while(a < l) { if(ToUpper(*a) != ToUpper(*b)) return ToUpper(*a) - ToUpper(*b); a++; b++; } return 0; } Stream& Pack16(Stream& s, Point& p) { return Pack16(s, p.x, p.y); } Stream& Pack16(Stream& s, Size& sz) { return Pack16(s, sz.cx, sz.cy); } Stream& Pack16(Stream& s, Rect& r) { return Pack16(s, r.left, r.top, r.right, r.bottom); } void StringC::Free() { if(IsString()) delete (String *) bap.GetPtr(); } StringC::~StringC() { Free(); } StringC::operator const char *() const { if(IsEmpty()) return NULL; if(IsString()) return *(String *) bap.GetPtr(); return (const char *)bap.GetPtr(); } StringC::operator String() const { if(IsEmpty()) return (const char *)NULL; if(IsString()) return *(String *) bap.GetPtr(); return (const char *)bap.GetPtr(); } bool StringC::IsEmpty() const { if(IsString()) return (*(String *) bap.GetPtr()).IsEmpty(); if(!bap.GetPtr()) return true; return !*(const char *)bap.GetPtr(); } void StringC::SetString(const String& s) { Free(); String *ptr = new String; *ptr = s; bap.Set1(ptr); } void StringC::SetCharPtr(const char *s) { Free(); bap.Set0((void *)s); } CharFilterTextTest::CharFilterTextTest(int (*filter)(int)) : filter(filter) {} CharFilterTextTest::~CharFilterTextTest() {} const char *CharFilterTextTest::Accept(const char *s) const { if(!(*filter)((byte)*s++)) return NULL; return s; } Vector Split(const char *s, const TextTest& delim, bool ignoreempty) { Vector r; const char *t = s; while(*t) { const char *q = delim.Accept(t); if(q) { if(!ignoreempty || t > s) r.Add(String(s, t)); t = s = q; } else t++; } if(!ignoreempty || t > s) r.Add(String(s, t)); return r; } Vector Split(const char *s, int (*filter)(int), bool ignoreempty) { return Split(s, CharFilterTextTest(filter), ignoreempty); } struct chrTextTest : public TextTest { int chr; virtual const char *Accept(const char *s) const { return chr == *s ? s + 1 : NULL; } }; Vector Split(const char *s, int chr, bool ignoreempty) { chrTextTest ct; ct.chr = chr; return Split(s, ct, ignoreempty); } String Join(const Vector& im, const String& delim) { String r; for(int i = 0; i < im.GetCount(); i++) { if(i) r.Cat(delim); r.Cat(im[i]); } return r; } // --------------------------- VectorMap LoadIniFile(const char *filename) { VectorMap key; FileIn in(filename); if(!in) return key; int c; if((c = in.Get()) < 0) return key; for(;;) { String k, v; for(;;) { if(IsAlNum(c) || c == '_') k.Cat(c); else break; if((c = in.Get()) < 0) return key; } for(;;) { if(c != '=' && c != ' ') break; if((c = in.Get()) < 0) return key; } for(;;) { if(c < ' ') break; v.Cat(c); if((c = in.Get()) < 0) break; } if(!k.IsEmpty()) key.Add(k, v); if(k == "LINK") { in.Close(); if(!in.Open(v) || (c = in.Get()) < 0) return key; } else for(;;) { if(IsAlNum(c)) break; if((c = in.Get()) < 0) return key; } } } const char *sIniFile; void SetIniFile(const char *name) { sIniFile = name; } #ifdef PLATFORM_WIN32 String GetIniKey(const char *name) { static bool loaded; static VectorMap key; if(!loaded) { loaded = true; key = LoadIniFile(sIniFile ? sIniFile : ~GetExeDirFile("Q.INI")); if(key.GetCount() == 0) key = LoadIniFile("C:\\Q.INI"); } int i = key.Find(name); if(i < 0) return String(); return key[i]; } #endif #ifdef PLATFORM_POSIX String GetIniKey(const char *name) { static bool loaded; static VectorMap key; if(!loaded) { loaded = true; key = LoadIniFile(GetHomeDirFile("Q.INI")); } int i = key.Find(name); if(i < 0) return String(); return key[i]; } #endif void TextSettings::Load(const char *filename) { FileIn in(filename); int themei = 0; settings.Add(""); while(!in.IsEof()) { String ln = in.GetLine(); const char *s = ln; if(*s == '[') { s++; String theme; while(*s && *s != ']') theme.Cat(*s++); themei = settings.FindAdd(theme); } else { if(themei >= 0) { String key; while(*s && *s != '=') { key.Cat(*s++); } if(*s == '=') s++; String value; while(*s) { value.Cat(*s++); } if(!IsEmpty(key)) settings[themei].GetAdd(key) = value; } } } } String TextSettings::Get(const char *group, const char *key) const { int itemi = settings.Find(group); return itemi < 0 ? Null : settings.Get(group).Get(key, Null); } // -------------------------------------------------------------- String timeFormat(double s) { if(s < 0.001) return Sprintf("%5.1f us", s * 1.0e6); if(s < 1) return Sprintf("%5.1f ms", s * 1.0e3); return Sprintf("%5.1f s ", s); } String Garble(const char *s, const char *e) { int c = 0xAA; String result; if(!e) e = s + strlen(s); while(s != e) { result.Cat(*s++ ^ (char)c); if((c <<= 1) & 0x100) c ^= 0x137; } return result; } String Garble(const String& s) { return Garble(~s, ~s + s.GetLength()); } String Encode64(const String& s) { String enc; int l = s.GetLength(); enc << l << ':'; for(int i = 0; i < l;) { char a = 0, b = 0, c = 0; if(i < l) a = s[i++]; if(i < l) b = s[i++]; if(i < l) c = s[i++]; enc.Cat(' ' + 1 + ((a >> 2) & 0x3F)); enc.Cat(' ' + 1 + ((a << 4) & 0x30) + ((b >> 4) & 0x0F)); enc.Cat(' ' + 1 + ((b << 2) & 0x3C) + ((c >> 6) & 0x03)); enc.Cat(' ' + 1 + (c & 0x3F)); } return enc; } String Decode64(const String& s) { if(!IsDigit(*s)) return s; const char *p = s; char *h; int len = strtol(p, &h, 10); p = h; if(*p++ != ':' || len < 0 || (len + 2) / 3 * 4 > (s.End() - p)) return s; // invalid encoding if(len == 0) return Null; String dec; for(;;) { byte ea = *p++ - ' ' - 1, eb = *p++ - ' ' - 1, ec = *p++ - ' ' - 1, ed = *p++ - ' ' - 1; byte out[3] = { (ea << 2) | (eb >> 4), (eb << 4) | (ec >> 2), (ec << 6) | (ed >> 0) }; switch(len) { case 1: dec.Cat(out[0]); return dec; case 2: dec.Cat(out, 2); return dec; case 3: dec.Cat(out, 3); return dec; default: dec.Cat(out, 3); len -= 3; break; } } } String NormalizeSpaces(const char *s) { StringBuffer r; while(*s && (byte)*s <= ' ') s++; while(*s) { if((byte)*s <= ' ') { while(*s && (byte)*s <= ' ') s++; if(*s) r.Cat(' '); } else r.Cat(*s++); } return r; } String NormalizeSpaces(const char *s, const char *end) { StringBuffer r; while(*s && (byte)*s <= ' ') s++; while(s < end) { if((byte)*s <= ' ') { while(s < end && (byte)*s <= ' ') s++; if(*s) r.Cat(' '); } else r.Cat(*s++); } return r; } int ChNoInvalid(int c) { return c == DEFAULTCHAR ? '_' : c; } #ifdef PLATFORM_WINCE WString ToSystemCharset(const String& src) { return src.ToWString(); } String FromSystemCharset(const WString& src) { return src.ToString(); } #else #ifdef PLATFORM_WIN32 String ToSystemCharset(const String& src) { WString s = src.ToWString(); int l = s.GetLength() * 5; StringBuffer b(l); int q = WideCharToMultiByte(CP_ACP, 0, (const WCHAR *)~s, s.GetLength(), b, l, NULL, NULL); if(q <= 0) return src; b.SetCount(q); return b; } String FromSystemCharset(const String& src) { WStringBuffer b(src.GetLength()); int q = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ~src, src.GetLength(), (WCHAR*)~b, src.GetLength()); if(q <= 0) return src; b.SetCount(q); return WString(b).ToString(); } #else String ToSystemCharset(const String& src) { return IsMainRunning() ? Filter(ToCharset(GetLNGCharset(GetSystemLNG()), src), ChNoInvalid) : src; } String FromSystemCharset(const String& src) { return IsMainRunning() ? Filter(ToCharset(CHARSET_DEFAULT, src, GetLNGCharset(GetSystemLNG())), ChNoInvalid) : src; } #endif #endif static VectorMap& sGCfg() { static VectorMap m; return m; } static StaticCriticalSection sGCfgLock; static Vector& sGFlush() { static Vector m; return m; } static StaticCriticalSection sGFlushLock; void RegisterGlobalConfig(const char *name) { INTERLOCKED_(sGCfgLock) { ASSERT(sGCfg().Find(name) < 0); sGCfg().Add(name); } } void RegisterGlobalConfig(const char *name, Callback WhenFlush) { RegisterGlobalConfig(name); INTERLOCKED_(sGFlushLock) { sGFlush().Add(WhenFlush); } } String GetGlobalConfigData(const char *name) { INTERLOCKED_(sGCfgLock) { return sGCfg().GetAdd(name); } return String(); } void SetGlobalConfigData(const char *name, const String& data) { INTERLOCKED_(sGCfgLock) { sGCfg().GetAdd(name) = data; } } void SerializeGlobalConfigs(Stream& s) { INTERLOCKED_(sGFlushLock) { for(int i = 0; i < sGFlush().GetCount(); i++) sGFlush()[i](); } INTERLOCKED_(sGCfgLock) { VectorMap& cfg = sGCfg(); int version = 0; s / version; int count = cfg.GetCount(); s / count; for(int i = 0; i < count; i++) { String name; if(s.IsStoring()) name = cfg.GetKey(i); s % name; int q = cfg.Find(name); if(q >= 0) s % cfg[q]; else { String dummy; s % dummy; } } s.Magic(); } } Exc::Exc() : String(GetLastErrorMessage()) {} /* #ifdef PLATFORM_WIN32 void Exc::Show() const { if(IsEmpty()) return; MessageBox(GetActiveWindow(), *this, "Chyba", MB_OK); } #endif #ifdef PLATFORM_POSIX void Exc::Show() const { printf(*this); } #endif */ AbortExc::AbortExc() : Exc(t_("Aborted by user.")) {} #ifdef PLATFORM_WIN32 String GetErrorMessage(DWORD dwError) { char h[2048]; sprintf(h, "%08x", dwError); #ifdef PLATFORM_WINCE //TODO return h; #else FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, 0, h, 2048, NULL); String result = h; String modf; const char* s = result; BYTE c; while((c = *s++) != 0) if(c <= ' ') { if(!modf.IsEmpty() && modf[modf.GetLength() - 1] != ' ') modf += ' '; } else if(c == '%' && *s >= '0' && *s <= '9') { s++; modf += "<###>"; } else modf += (char)c; const char* p = modf; for(s = p + modf.GetLength(); s > p && s[-1] == ' '; s--); return FromSystemCharset(modf.Left(s - p)); #endif } String GetLastErrorMessage() { return GetErrorMessage(GetLastError()); } #endif #ifdef PLATFORM_POSIX String GetErrorMessage(int errorno) { enum { MAX_ERROR_LEN = 1000000 }; int len = 1024; Buffer buffer(len); while(strerror_r(errorno, buffer, len)) if(errno == ERANGE && len < MAX_ERROR_LEN) buffer.Alloc(len <<= 1); else return NFormat("strerror_r(%d, %d) -> errno = %d", errorno, len, errno); return FromSystemCharset(~buffer); } String GetLastErrorMessage() { return GetErrorMessage(errno); } #endif #ifdef PLATFORM_POSIX static void LinuxBeep(const char *fn) { return; // This is not the right way to do that... (causes zombies, ignores Gnome settings) char h[100]; strcpy(h, "aplay /usr/share/sounds/"); strcat(h, fn); if(fork()) return; system(h); _exit(EXIT_SUCCESS); } #endif void BeepInformation() { #ifdef PLATFORM_WIN32 MessageBeep(MB_ICONINFORMATION); #else LinuxBeep("info.wav"); #endif } void BeepExclamation() { #ifdef PLATFORM_WIN32 MessageBeep(MB_ICONEXCLAMATION); #else LinuxBeep("warning.wav"); #endif } void BeepQuestion() { #ifdef PLATFORM_WIN32 MessageBeep(MB_ICONQUESTION); #else LinuxBeep("question.wav"); // write(1, "\a", 1); //?? #endif } #if defined(COMPILER_MSC) && (_MSC_VER < 1300) //hack for linking libraries built using VC7 with VC6 standard lib's extern "C" long _ftol( double ); extern "C" long _ftol2( double dblSource ) { return _ftol( dblSource ); } #endif #ifdef PLATFORM_WINCE int errno; // missing and zlib needs it #endif END_UPP_NAMESPACE