bool LogSilent(const char *szMessage, bool fConsole) { if (!Application.AssertMainThread()) return false; // security if (!szMessage) return false; // add timestamp time_t timenow; time(&timenow); StdStrBuf TimeMessage; TimeMessage.SetLength(11 + SLen(szMessage) + 1); strftime(TimeMessage.getMData(), 11 + 1, "[%H:%M:%S] ", localtime(&timenow)); // output until all data is written const char *pSrc = szMessage; do { // timestamp will always be that length char *pDest = TimeMessage.getMData() + 11; // copy rest of message, skip tags CMarkup Markup(false); while (*pSrc) { Markup.SkipTags(&pSrc); // break on crlf while (*pSrc == '\r') pSrc++; if (*pSrc == '\n') { pSrc++; break; } // copy otherwise if (*pSrc) *pDest++ = *pSrc++; } *pDest++ = '\n'; *pDest = '\0'; #ifdef HAVE_ICONV StdStrBuf Line = Languages.IconvSystem(TimeMessage.getData()); #else StdStrBuf &Line = TimeMessage; #endif // Save into log file if (C4LogFile) { fputs(Line.getData(), C4LogFile); fflush(C4LogFile); } // Write to console if (fConsole || Game.Verbose) { #if defined(_DEBUG) && defined(_WIN32) // debug: output to VC console OutputDebugString(Line.getData()); #endif fputs(Line.getData(), stdout); fflush(stdout); } } while (*pSrc); return true; }
void C4MusicSystem::LoadMoreMusic() { StdStrBuf MoreMusicFile; // load MoreMusic.txt if (!MoreMusicFile.LoadFromFile(Config.AtUserDataPath(C4CFN_MoreMusic))) return; // read contents char *pPos = MoreMusicFile.getMData(); while (pPos && *pPos) { // get line char szLine[1024 + 1]; SCopyUntil(pPos, szLine, '\n', 1024); pPos = strchr(pPos, '\n'); if (pPos) pPos++; // remove leading whitespace char *pLine = szLine; while (*pLine == ' ' || *pLine == '\t' || *pLine == '\r') pLine++; // and whitespace at end char *p = pLine + strlen(pLine) - 1; while (*p == ' ' || *p == '\t' || *p == '\r') { *p = 0; --p; } // comment? if (*pLine == '#') { // might be a "directive" if (SEqual(pLine, "#clear")) ClearSongs(); continue; } // try to load file(s) LoadDir(pLine); } }
BOOL C4UpdatePackageCore::Save(C4Group &hGroup) { try { // decompile data StdStrBuf Core = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(*this, "Update")); char *stupid_buffer = new char[Core.getLength() + 1]; memcpy(stupid_buffer, Core.getMData(), Core.getLength() + 1); // add to group return hGroup.Add(C4CFN_UpdateCore, stupid_buffer, Core.getLength(), FALSE, TRUE); } catch (StdCompiler::Exception *pExc) { delete pExc; return FALSE; } }
bool GetLogSection(size_t iStart, size_t iLength, StdStrBuf &rsOut) { if (!iLength) { rsOut.Clear(); return true; } // read section from log file StdStrBuf BufOrig; if (!BufOrig.LoadFromFile(sLogFileName.getData())) return false; char *szBuf = BufOrig.getMData(); size_t iSize = BufOrig.getSize(); // size excluding terminator // reduce to desired buffer section if (iStart > iSize) iStart = iSize; if (iStart + iLength > iSize) iLength = iSize - iStart; szBuf += iStart; szBuf[iLength] = '\0'; // strip timestamps; convert linebreaks to Clonk-linebreaks '|' char *szPosWrite=szBuf; const char *szPosRead=szBuf; while (*szPosRead) { // skip timestamp if (*szPosRead == '[') while (*szPosRead && *szPosRead != ']') { --iSize; ++szPosRead; } // skip whitespace behind timestamp if (!*szPosRead) break; szPosRead++; // copy data until linebreak size_t iLen=0; while (*szPosRead && *szPosRead != 0x0d && *szPosRead != 0x0a) { ++szPosRead; ++iLen; } if (iLen && szPosRead-iLen != szPosWrite) memmove(szPosWrite, szPosRead-iLen, iLen); szPosWrite += iLen; // skip additional linebreaks while (*szPosRead == 0x0d || *szPosRead == 0x0a) ++szPosRead; // write a Clonk-linebreak if (*szPosRead) *szPosWrite++ = '|'; } // done; create string buffer from data rsOut.Copy(szBuf, szPosWrite - szBuf); // done, success return true; }
bool LogSilent(const char *szMessage, bool fConsole) { if (!Application.AssertMainThread()) return false; // security if (!szMessage) return false; // add timestamp time_t timenow; time(&timenow); StdStrBuf TimeMessage; TimeMessage.SetLength(11 + SLen(szMessage) + 1); strftime(TimeMessage.getMData(), 11 + 1, "[%H:%M:%S] ", localtime(&timenow)); // output until all data is written const char *pSrc = szMessage; do { // timestamp will always be that length char *pDest = TimeMessage.getMData() + 11; // copy rest of message, skip tags C4Markup Markup(false); while (*pSrc) { Markup.SkipTags(&pSrc); // break on crlf while (*pSrc == '\r') pSrc++; if (*pSrc == '\n') { pSrc++; break; } // copy otherwise if (*pSrc) *pDest++ = *pSrc++; } *pDest++='\n'; *pDest = '\0'; // Save into log file if (C4LogFile) { fputs(TimeMessage.getData(),C4LogFile); fflush(C4LogFile); } // Save into record log file, if available if(Control.GetRecord()) { Control.GetRecord()->GetLogFile()->Write(TimeMessage.getData(), TimeMessage.getLength()); #ifdef IMMEDIATEREC Control.GetRecord()->GetLogFile()->Flush(); #endif } // Write to console if (fConsole) { #if defined(_WIN32) // debug: output to VC console OutputDebugString(TimeMessage.GetWideChar()); #endif #if !defined(_WIN32) || defined(USE_CONSOLE) fputs(TimeMessage.getData(),stdout); fflush(stdout); #endif } } while (*pSrc); return true; }
bool ValidateString(StdStrBuf &rsString, ValidationOption eOption) { bool fValid = true; // validation depending on option // check min length if (!rsString.getLength()) { // empty if not allowed? if (eOption != VAL_NameAllowEmpty && eOption != VAL_NameExAllowEmpty && eOption != VAL_Comment) { rsString.Copy("empty"); fValid = false; } } switch (eOption) { case VAL_Filename: // regular filenames only // absolutely no directory traversal if (rsString.ReplaceChar('/', '_')) fValid = false; if (rsString.ReplaceChar('\\', '_')) fValid = false; // fallthrough to general file name validation case VAL_SubPathFilename: // filenames and optional subpath // do not traverse upwards in file hierarchy if (rsString.Replace("..", "__")) fValid = false; if (*rsString.getData() == '/' || *rsString.getData() == '\\') { *rsString.getMData() = '_'; fValid = false; } // fallthrough to general file name validation case VAL_FullPath: // full filename paths // some characters are prohibited in filenames in general if (rsString.ReplaceChar('*', '_')) fValid = false; if (rsString.ReplaceChar('?', '_')) fValid = false; if (rsString.ReplaceChar('<', '_')) fValid = false; if (rsString.ReplaceChar('>', '_')) fValid = false; // ';' and '|' is never allowed in filenames, because it would cause problems in many engine internal file lists if (rsString.ReplaceChar(';', '_')) fValid = false; if (rsString.ReplaceChar('|', '_')) fValid = false; // the colon is generally prohibited except at pos 2 (C:\...), because it could lead to creation of (invisible) streams on NTFS if (rsString.ReplaceChar(':', '_', 2)) fValid = false; if (*rsString.getData() == ':') { *rsString.getMData() = '_'; fValid = false; } // validate drive letter if (rsString.getLength()>=2 && *rsString.getPtr(1) == ':') { if (eOption != VAL_FullPath) { *rsString.getMPtr(1)='_'; fValid = false; } else if (!isalpha((unsigned char)*rsString.getData()) || (*rsString.getPtr(2)!='\\' && *rsString.getPtr(2)!='/')) { *rsString.getMData()=*rsString.getMPtr(1)='_'; fValid = false; } } break; case VAL_NameNoEmpty: case VAL_NameAllowEmpty: // no markup if (CMarkup::StripMarkup(&rsString)) { fValid = false; } // trim spaces if (rsString.TrimSpaces()) fValid = false; // min length if (eOption == VAL_NameNoEmpty) if (!rsString.getLength()) { fValid = false; rsString.Copy("Unknown"); } // max length if (rsString.getLength() > C4MaxName) { fValid = false; rsString.SetLength(C4MaxName); } break; case VAL_NameExNoEmpty: case VAL_NameExAllowEmpty: // trim spaces if (rsString.TrimSpaces()) fValid = false; // min length if (eOption == VAL_NameExNoEmpty) if (!rsString.getLength()) { fValid = false; rsString.Copy("Unknown"); } // max length if (rsString.getLength() > C4MaxLongName) { fValid = false; rsString.SetLength(C4MaxLongName); } break; case VAL_IRCName: // nickname for IRC. a-z, A-Z, _^{[]} only; 0-9|- inbetween; max 30 characters if (rsString.getLength() > 30) fValid = false; if (rsString.getLength() < 2) fValid = false; if (!rsString.ValidateChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_^{[]}", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_^{[]}0123456789|-")) { fValid = false; rsString.Copy("Guest"); } if (SEqualNoCase(rsString.getData(), "NickServ") || SEqualNoCase(rsString.getData(), "ChanServ") || SEqualNoCase(rsString.getData(), "MemoServ") || SEqualNoCase(rsString.getData(), "OperServ") || SEqualNoCase(rsString.getData(), "HelpServ")) fValid = false; if (!fValid) rsString.Copy("Guest"); break; case VAL_IRCPass: // password for IRC; max 31 characters // max length; no spaces if (rsString.getLength() > 31) { fValid = false; rsString.SetLength(31); } if (rsString.getLength() < 2) { fValid = false; rsString.Copy("secret"); } if (rsString.ReplaceChar(' ', '_')) fValid = false; break; case VAL_IRCChannel: // IRC channel name if (rsString.getLength() > 32) { fValid = false; rsString.SetLength(32); } else if (rsString.getLength() < 2) { fValid = false; rsString.Copy("#clonken"); } else if (*rsString.getData() != '#' && *rsString.getData() != '+') { fValid = false; *rsString.getMData() = '#'; } if (rsString.ReplaceChar(' ', '_')) fValid = false; break; case VAL_Comment: // comment - just limit length if (rsString.getLength() > C4MaxComment) { fValid = false; rsString.SetLength(C4MaxComment); } break; default: assert(!"not yet implemented"); } // issue warning for invalid adjustments if (!fValid) { const char *szOption = "unknown"; switch (eOption) { case VAL_Filename: szOption = "filename"; break; case VAL_SubPathFilename: szOption = "(sub-)filename"; break; case VAL_FullPath: szOption = "free filename"; break; case VAL_NameNoEmpty: szOption = "strict name"; break; case VAL_NameExNoEmpty: szOption = "name"; break; case VAL_NameAllowEmpty: szOption = "strict name*"; break; case VAL_NameExAllowEmpty: szOption = "name*"; break; case VAL_IRCName: szOption = "IRC nick"; break; case VAL_IRCPass: szOption = "IRC password"; break; case VAL_IRCChannel: szOption = "IRC channel"; break; case VAL_Comment: szOption = "Comment"; break; } //LogF("WARNING: Adjusted invalid user input for \"%s\" to \"%s\"", szOption, rsString.getData()); } return !fValid; }
CStdWindow *CStdWindow::Init(CStdApp *pApp, const char *Title, CStdWindow *pParent, bool HideCursor) { #ifndef USE_X11 return this; #else Active = true; dpy = pApp->dpy; if (!FindInfo()) return 0; // Various properties XSetWindowAttributes attr; attr.border_pixel = 0; attr.background_pixel = 0; // Which events we want to receive attr.event_mask = // EnterWindowMask | // LeaveWindowMask | StructureNotifyMask | FocusChangeMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask; attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), ((XVisualInfo *)Info)->visual, AllocNone); unsigned long attrmask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; Pixmap bitmap; if (HideCursor) { // Hide the mouse cursor XColor cursor_color; // We do not care what color the invisible cursor has memset(&cursor_color, 0, sizeof(cursor_color)); bitmap = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), "\000", 1, 1); attr.cursor = XCreatePixmapCursor(dpy, bitmap, bitmap, &cursor_color, &cursor_color, 0, 0); attrmask |= CWCursor; } wnd = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 640, 480, 0, ((XVisualInfo *)Info)->depth, InputOutput, ((XVisualInfo *)Info)->visual, attrmask, &attr); if (HideCursor) { XFreeCursor(dpy, attr.cursor); XFreePixmap(dpy, bitmap); } if (!wnd) { Log("Error creating window."); return 0; } // Update the XWindow->CStdWindow-Map CStdAppPrivate::SetWindow(wnd, this); if (!pApp->Priv->xic && pApp->Priv->xim) { pApp->Priv->xic = XCreateIC( pApp->Priv->xim, XNClientWindow, wnd, XNFocusWindow, wnd, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNResourceName, STD_PRODUCT, XNResourceClass, STD_PRODUCT, NULL); if (!pApp->Priv->xic) { Log("Failed to create input context."); XCloseIM(pApp->Priv->xim); pApp->Priv->xim = 0; } else { long ic_event_mask; if (XGetICValues(pApp->Priv->xic, XNFilterEvents, &ic_event_mask, NULL) == NULL) attr.event_mask |= ic_event_mask; XSelectInput(dpy, wnd, attr.event_mask); XSetICFocus(pApp->Priv->xic); } } // We want notification of closerequests and be killed if we hang Atom WMProtocols[2]; char *WMProtocolnames[] = {"WM_DELETE_WINDOW", "_NET_WM_PING"}; XInternAtoms(dpy, WMProtocolnames, 2, false, WMProtocols); XSetWMProtocols(dpy, wnd, WMProtocols, 2); // Let the window manager know our pid so it can kill us Atom PID = XInternAtom(pApp->dpy, "_NET_WM_PID", false); int32_t pid = getpid(); if (PID != None) XChangeProperty(pApp->dpy, wnd, PID, XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<const unsigned char *>(&pid), 1); // Title and stuff XTextProperty title_property; StdStrBuf tbuf; tbuf.Copy(Title ? Title : ""); char *tbufstr = tbuf.getMData(); // char * title = "Clonk Endeavour"; XStringListToTextProperty(&tbufstr, 1, &title_property); // State and Icon XWMHints *wm_hint = XAllocWMHints(); wm_hint->flags = StateHint | InputHint | IconPixmapHint | IconMaskHint; wm_hint->initial_state = NormalState; wm_hint->input = True; // Trust XpmCreatePixmapFromData to not modify the xpm... XpmCreatePixmapFromData(dpy, wnd, const_cast<char **>(c4x_xpm), &wm_hint->icon_pixmap, &wm_hint->icon_mask, 0); // Window class XClassHint *class_hint = XAllocClassHint(); class_hint->res_name = STD_PRODUCT; class_hint->res_class = STD_PRODUCT; XSetWMProperties(dpy, wnd, &title_property, &title_property, pApp->Priv->argv, pApp->Priv->argc, 0, wm_hint, class_hint); // Set "parent". Clonk does not use "real" parent windows, but multiple // toplevel windows. if (pParent) XSetTransientForHint(dpy, wnd, pParent->wnd); // Show window XMapWindow(dpy, wnd); // Clean up // The pixmap has to stay as long as the window exists, so it does not hurt to // never free it. // XFreePixmap(dpy,xwmh->icon_pixmap); // XFreePixmap(dpy,xwmh->icon_mask); XFree(title_property.value); Hints = wm_hint; XFree(class_hint); // Render into whole window renderwnd = wnd; return this; #endif // USE_X11 }