From 12e3e7f057bdb3d965a944d6c97fe7f222158eee Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Thu, 25 Dec 2014 19:42:00 +0000 Subject: files structure changed git-svn-id: http://svn.miranda-ng.org/main/trunk@11638 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/mir_core/cmdline.cpp | 89 --- src/mir_core/commonheaders.h | 69 --- src/mir_core/db.cpp | 370 ------------- src/mir_core/http.cpp | 168 ------ src/mir_core/icons.cpp | 77 --- src/mir_core/json/JSONChildren.cpp | 98 ---- src/mir_core/json/JSONChildren.h | 232 -------- src/mir_core/json/JSONDebug.cpp | 66 --- src/mir_core/json/JSONDebug.h | 68 --- src/mir_core/json/JSONDefs.h | 83 --- src/mir_core/json/JSONIterators.cpp | 240 -------- src/mir_core/json/JSONMemory.cpp | 107 ---- src/mir_core/json/JSONMemory.h | 134 ----- src/mir_core/json/JSONNode.cpp | 312 ----------- src/mir_core/json/JSONNode.h | 851 ----------------------------- src/mir_core/json/JSONNode_Mutex.cpp | 214 -------- src/mir_core/json/JSONOptions.h | 188 ------- src/mir_core/json/JSONWorker.cpp | 698 ----------------------- src/mir_core/json/JSONWorker.h | 46 -- src/mir_core/json/JSONWriter.cpp | 174 ------ src/mir_core/json/NumberToString.h | 104 ---- src/mir_core/json/internalJSONNode.cpp | 568 ------------------- src/mir_core/json/internalJSONNode.h | 452 --------------- src/mir_core/json/libJSON.cpp | 457 ---------------- src/mir_core/langpack.cpp | 734 ------------------------- src/mir_core/lists.cpp | 247 --------- src/mir_core/logger.cpp | 228 -------- src/mir_core/mc.cpp | 188 ------- src/mir_core/md5.cpp | 358 ------------ src/mir_core/memory.cpp | 285 ---------- src/mir_core/mir_core.def | 282 ---------- src/mir_core/mir_core_10.vcxproj | 144 ++--- src/mir_core/mir_core_10.vcxproj.filters | 86 +-- src/mir_core/mir_core_12.vcxproj | 135 ++--- src/mir_core/mir_core_12.vcxproj.filters | 84 +-- src/mir_core/miranda.cpp | 128 ----- src/mir_core/miranda.h | 138 ----- src/mir_core/modules.cpp | 662 ---------------------- src/mir_core/mstring.cpp | 118 ---- src/mir_core/path.cpp | 210 ------- src/mir_core/protos.cpp | 264 --------- src/mir_core/sha1.cpp | 193 ------- src/mir_core/src/cmdline.cpp | 89 +++ src/mir_core/src/commonheaders.h | 69 +++ src/mir_core/src/db.cpp | 370 +++++++++++++ src/mir_core/src/http.cpp | 168 ++++++ src/mir_core/src/icons.cpp | 77 +++ src/mir_core/src/json/JSONChildren.cpp | 98 ++++ src/mir_core/src/json/JSONChildren.h | 232 ++++++++ src/mir_core/src/json/JSONDebug.cpp | 66 +++ src/mir_core/src/json/JSONDebug.h | 68 +++ src/mir_core/src/json/JSONDefs.h | 83 +++ src/mir_core/src/json/JSONIterators.cpp | 240 ++++++++ src/mir_core/src/json/JSONMemory.cpp | 107 ++++ src/mir_core/src/json/JSONMemory.h | 134 +++++ src/mir_core/src/json/JSONNode.cpp | 312 +++++++++++ src/mir_core/src/json/JSONNode.h | 851 +++++++++++++++++++++++++++++ src/mir_core/src/json/JSONNode_Mutex.cpp | 214 ++++++++ src/mir_core/src/json/JSONOptions.h | 188 +++++++ src/mir_core/src/json/JSONWorker.cpp | 698 +++++++++++++++++++++++ src/mir_core/src/json/JSONWorker.h | 46 ++ src/mir_core/src/json/JSONWriter.cpp | 174 ++++++ src/mir_core/src/json/NumberToString.h | 104 ++++ src/mir_core/src/json/internalJSONNode.cpp | 568 +++++++++++++++++++ src/mir_core/src/json/internalJSONNode.h | 452 +++++++++++++++ src/mir_core/src/json/libJSON.cpp | 457 ++++++++++++++++ src/mir_core/src/langpack.cpp | 734 +++++++++++++++++++++++++ src/mir_core/src/lists.cpp | 247 +++++++++ src/mir_core/src/logger.cpp | 228 ++++++++ src/mir_core/src/mc.cpp | 188 +++++++ src/mir_core/src/md5.cpp | 358 ++++++++++++ src/mir_core/src/memory.cpp | 285 ++++++++++ src/mir_core/src/mir_core.def | 282 ++++++++++ src/mir_core/src/miranda.cpp | 128 +++++ src/mir_core/src/miranda.h | 138 +++++ src/mir_core/src/modules.cpp | 662 ++++++++++++++++++++++ src/mir_core/src/mstring.cpp | 118 ++++ src/mir_core/src/path.cpp | 210 +++++++ src/mir_core/src/protos.cpp | 264 +++++++++ src/mir_core/src/sha1.cpp | 193 +++++++ src/mir_core/src/stdafx.cpp | 18 + src/mir_core/src/subclass.cpp | 178 ++++++ src/mir_core/src/threads.cpp | 364 ++++++++++++ src/mir_core/src/utf.cpp | 452 +++++++++++++++ src/mir_core/src/utils.cpp | 411 ++++++++++++++ src/mir_core/src/winver.cpp | 93 ++++ src/mir_core/stdafx.cpp | 18 - src/mir_core/subclass.cpp | 178 ------ src/mir_core/threads.cpp | 364 ------------ src/mir_core/utf.cpp | 452 --------------- src/mir_core/utils.cpp | 411 -------------- src/mir_core/winver.cpp | 93 ---- 92 files changed, 11612 insertions(+), 11669 deletions(-) delete mode 100644 src/mir_core/cmdline.cpp delete mode 100644 src/mir_core/commonheaders.h delete mode 100644 src/mir_core/db.cpp delete mode 100644 src/mir_core/http.cpp delete mode 100644 src/mir_core/icons.cpp delete mode 100644 src/mir_core/json/JSONChildren.cpp delete mode 100644 src/mir_core/json/JSONChildren.h delete mode 100644 src/mir_core/json/JSONDebug.cpp delete mode 100644 src/mir_core/json/JSONDebug.h delete mode 100644 src/mir_core/json/JSONDefs.h delete mode 100644 src/mir_core/json/JSONIterators.cpp delete mode 100644 src/mir_core/json/JSONMemory.cpp delete mode 100644 src/mir_core/json/JSONMemory.h delete mode 100644 src/mir_core/json/JSONNode.cpp delete mode 100644 src/mir_core/json/JSONNode.h delete mode 100644 src/mir_core/json/JSONNode_Mutex.cpp delete mode 100644 src/mir_core/json/JSONOptions.h delete mode 100644 src/mir_core/json/JSONWorker.cpp delete mode 100644 src/mir_core/json/JSONWorker.h delete mode 100644 src/mir_core/json/JSONWriter.cpp delete mode 100644 src/mir_core/json/NumberToString.h delete mode 100644 src/mir_core/json/internalJSONNode.cpp delete mode 100644 src/mir_core/json/internalJSONNode.h delete mode 100644 src/mir_core/json/libJSON.cpp delete mode 100644 src/mir_core/langpack.cpp delete mode 100644 src/mir_core/lists.cpp delete mode 100644 src/mir_core/logger.cpp delete mode 100644 src/mir_core/mc.cpp delete mode 100644 src/mir_core/md5.cpp delete mode 100644 src/mir_core/memory.cpp delete mode 100644 src/mir_core/mir_core.def delete mode 100644 src/mir_core/miranda.cpp delete mode 100644 src/mir_core/miranda.h delete mode 100644 src/mir_core/modules.cpp delete mode 100644 src/mir_core/mstring.cpp delete mode 100644 src/mir_core/path.cpp delete mode 100644 src/mir_core/protos.cpp delete mode 100644 src/mir_core/sha1.cpp create mode 100644 src/mir_core/src/cmdline.cpp create mode 100644 src/mir_core/src/commonheaders.h create mode 100644 src/mir_core/src/db.cpp create mode 100644 src/mir_core/src/http.cpp create mode 100644 src/mir_core/src/icons.cpp create mode 100644 src/mir_core/src/json/JSONChildren.cpp create mode 100644 src/mir_core/src/json/JSONChildren.h create mode 100644 src/mir_core/src/json/JSONDebug.cpp create mode 100644 src/mir_core/src/json/JSONDebug.h create mode 100644 src/mir_core/src/json/JSONDefs.h create mode 100644 src/mir_core/src/json/JSONIterators.cpp create mode 100644 src/mir_core/src/json/JSONMemory.cpp create mode 100644 src/mir_core/src/json/JSONMemory.h create mode 100644 src/mir_core/src/json/JSONNode.cpp create mode 100644 src/mir_core/src/json/JSONNode.h create mode 100644 src/mir_core/src/json/JSONNode_Mutex.cpp create mode 100644 src/mir_core/src/json/JSONOptions.h create mode 100644 src/mir_core/src/json/JSONWorker.cpp create mode 100644 src/mir_core/src/json/JSONWorker.h create mode 100644 src/mir_core/src/json/JSONWriter.cpp create mode 100644 src/mir_core/src/json/NumberToString.h create mode 100644 src/mir_core/src/json/internalJSONNode.cpp create mode 100644 src/mir_core/src/json/internalJSONNode.h create mode 100644 src/mir_core/src/json/libJSON.cpp create mode 100644 src/mir_core/src/langpack.cpp create mode 100644 src/mir_core/src/lists.cpp create mode 100644 src/mir_core/src/logger.cpp create mode 100644 src/mir_core/src/mc.cpp create mode 100644 src/mir_core/src/md5.cpp create mode 100644 src/mir_core/src/memory.cpp create mode 100644 src/mir_core/src/mir_core.def create mode 100644 src/mir_core/src/miranda.cpp create mode 100644 src/mir_core/src/miranda.h create mode 100644 src/mir_core/src/modules.cpp create mode 100644 src/mir_core/src/mstring.cpp create mode 100644 src/mir_core/src/path.cpp create mode 100644 src/mir_core/src/protos.cpp create mode 100644 src/mir_core/src/sha1.cpp create mode 100644 src/mir_core/src/stdafx.cpp create mode 100644 src/mir_core/src/subclass.cpp create mode 100644 src/mir_core/src/threads.cpp create mode 100644 src/mir_core/src/utf.cpp create mode 100644 src/mir_core/src/utils.cpp create mode 100644 src/mir_core/src/winver.cpp delete mode 100644 src/mir_core/stdafx.cpp delete mode 100644 src/mir_core/subclass.cpp delete mode 100644 src/mir_core/threads.cpp delete mode 100644 src/mir_core/utf.cpp delete mode 100644 src/mir_core/utils.cpp delete mode 100644 src/mir_core/winver.cpp (limited to 'src') diff --git a/src/mir_core/cmdline.cpp b/src/mir_core/cmdline.cpp deleted file mode 100644 index 1b9bc11c20..0000000000 --- a/src/mir_core/cmdline.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-14 Miranda NG project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -/* command line support */ - -struct CmdLineParam -{ - __inline CmdLineParam(LPCTSTR _name, LPCTSTR _value) : - name(_name), value(_value) - {} - - LPCTSTR name, value; -}; - -static int CompareParams(const CmdLineParam *p1, const CmdLineParam *p2) -{ - return _tcscmp(p1->name, p2->name); -} - -static OBJLIST arParams(5, CompareParams); - -MIR_CORE_DLL(void) CmdLine_Parse(LPTSTR ptszCmdLine) -{ - bool bPrevSpace = true; - for (LPTSTR p = ptszCmdLine; *p; p++) { - if ( *p == ' ' || *p == '\t') { - *p = 0; - bPrevSpace = true; - continue; - } - - // new word beginning - if (bPrevSpace) { - bPrevSpace = false; - if (*p != '/' && *p != '-') // not an option - skip it - continue; - } - else continue; // skip a text that isn't an option - - TCHAR *pOptionName = p+1; - if ((p = _tcspbrk(pOptionName, _T(" \t=:"))) == NULL) { // no more text in string - arParams.insert(new CmdLineParam(pOptionName, _T(""))); - break; - } - - if (*p == ' ' || *p == '\t') { - arParams.insert(new CmdLineParam(pOptionName, _T(""))); - p--; // the cycle will wipe this space automatically - continue; - } - - // parameter with value - *p = 0; - arParams.insert(new CmdLineParam(pOptionName, ++p)); - if ((p = _tcspbrk(p, _T(" \t"))) == NULL) // no more text in string - break; - - p--; // the cycle will wipe this space automatically - } -} - -MIR_CORE_DLL(LPCTSTR) CmdLine_GetOption(const TCHAR* ptszParameter) -{ - CmdLineParam tmp(ptszParameter, 0); - int idx = arParams.getIndex(&tmp); - return (idx == -1) ? NULL : arParams[idx].value; -} diff --git a/src/mir_core/commonheaders.h b/src/mir_core/commonheaders.h deleted file mode 100644 index 083ccd8e87..0000000000 --- a/src/mir_core/commonheaders.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#define WINVER 0x0700 -#define _WIN32_WINNT 0x0700 -#define _WIN32_IE 0x0601 - -#define INCL_WINSOCK_API_TYPEDEFS 1 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "miranda.h" - -#include -#include - - -extern TCHAR tszDefaultLang[100]; - -void GetDefaultLang(); \ No newline at end of file diff --git a/src/mir_core/db.cpp b/src/mir_core/db.cpp deleted file mode 100644 index 079225682a..0000000000 --- a/src/mir_core/db.cpp +++ /dev/null @@ -1,370 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -MIDatabase *currDb = NULL; - -///////////////////////////////////////////////////////////////////////////////////////// -// getting data - -MIR_CORE_DLL(int) db_get_b(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) -{ - if (currDb != NULL) { - DBVARIANT dbv; - if (!currDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) - { - switch(dbv.type) { - case DBVT_BYTE: return dbv.bVal; - case DBVT_WORD: return BYTE(dbv.wVal); - case DBVT_DWORD: return BYTE(dbv.dVal); - } - currDb->FreeVariant(&dbv); - } - } - return errorValue; -} - -MIR_CORE_DLL(int) db_get_w(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) -{ - if (currDb != NULL) { - DBVARIANT dbv; - if (!currDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { - switch(dbv.type) { - case DBVT_BYTE: return dbv.bVal; - case DBVT_WORD: return dbv.wVal; - case DBVT_DWORD: return WORD(dbv.dVal); - } - currDb->FreeVariant(&dbv); - } - } - return errorValue; -} - -MIR_CORE_DLL(DWORD) db_get_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD errorValue) -{ - if (currDb != NULL) { - DBVARIANT dbv; - if (!currDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { - switch(dbv.type) { - case DBVT_BYTE: return dbv.bVal; - case DBVT_WORD: return dbv.wVal; - case DBVT_DWORD: return dbv.dVal; - default: currDb->FreeVariant(&dbv); - } - currDb->FreeVariant(&dbv); - } - } - - return errorValue; -} - -MIR_CORE_DLL(INT_PTR) db_get(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) -{ - if (currDb == NULL) - return 1; - - return currDb->GetContactSetting(hContact, szModule, szSetting, dbv); -} - -MIR_CORE_DLL(INT_PTR) db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType) -{ - if (currDb == NULL) - return 1; - - dbv->type = (BYTE)nType; - return currDb->GetContactSettingStr(hContact, szModule, szSetting, dbv); -} - -MIR_CORE_DLL(char*) db_get_sa(MCONTACT hContact, const char *szModule, const char *szSetting) -{ - if (currDb == NULL) - return NULL; - - DBVARIANT dbv = { DBVT_ASCIIZ }; - return currDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv) ? NULL : dbv.pszVal; -} - -MIR_CORE_DLL(wchar_t*) db_get_wsa(MCONTACT hContact, const char *szModule, const char *szSetting) -{ - if (currDb == NULL) - return NULL; - - DBVARIANT dbv = { DBVT_WCHAR }; - return currDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv) ? NULL : dbv.pwszVal; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// getting static data - -MIR_CORE_DLL(int) db_get_static(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) -{ - if (currDb == NULL) - return 1; - - DBVARIANT dbv; - dbv.type = DBVT_ASCIIZ; - dbv.pszVal = pDest; - dbv.cchVal = cbDest; - return currDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(int) db_get_static_utf(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) -{ - if (currDb == NULL) - return 1; - - DBVARIANT dbv; - dbv.type = DBVT_UTF8; - dbv.pszVal = pDest; - dbv.cchVal = cbDest; - return currDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(int) db_get_wstatic(MCONTACT hContact, const char *szModule, const char *szSetting, WCHAR *pDest, int cbDest) -{ - if (currDb == NULL) - return 1; - - DBVARIANT dbv; - dbv.type = DBVT_WCHAR; - dbv.pwszVal = pDest; - dbv.cchVal = cbDest; - return currDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// setting data - -MIR_CORE_DLL(INT_PTR) db_set(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) -{ - if (currDb == NULL) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value = *dbv; - return currDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_b(MCONTACT hContact, const char *szModule, const char *szSetting, BYTE val) -{ - if (currDb == NULL) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_BYTE; - cws.value.bVal = val; - return currDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_w(MCONTACT hContact, const char *szModule, const char *szSetting, WORD val) -{ - if (currDb == NULL) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_WORD; - cws.value.wVal = val; - return currDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD val) -{ - if (currDb == NULL) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_DWORD; - cws.value.dVal = val; - return currDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_s(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) -{ - if (currDb == NULL) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_ASCIIZ; - cws.value.pszVal = (char*)(val == NULL ? "" : val); - return currDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_ws(MCONTACT hContact, const char *szModule, const char *szSetting, const WCHAR *val) -{ - if (currDb == NULL) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_WCHAR; - cws.value.pwszVal = (WCHAR*)(val == NULL ? L"" : val); - return currDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_utf(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) -{ - if (currDb == NULL) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_UTF8; - cws.value.pszVal = (char*)(val == NULL ? "" : val); - return currDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_blob(MCONTACT hContact, const char *szModule, const char *szSetting, void *val, unsigned len) -{ - if (currDb == NULL) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_BLOB; - cws.value.cpbVal = (WORD)len; - cws.value.pbVal = (unsigned char*)val; - return currDb->WriteContactSetting(hContact, &cws); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// events - -MIR_CORE_DLL(HANDLE) db_event_add(MCONTACT hContact, DBEVENTINFO *dbei) -{ - return (currDb == NULL) ? 0 : currDb->AddEvent(hContact, dbei); -} - -MIR_CORE_DLL(int) db_event_count(MCONTACT hContact) -{ - return (currDb == NULL) ? 0 : currDb->GetEventCount(hContact); -} - -MIR_CORE_DLL(int) db_event_delete(MCONTACT hContact, HANDLE hDbEvent) -{ - return (currDb == NULL) ? 0 : currDb->DeleteEvent(hContact, hDbEvent); -} - -MIR_CORE_DLL(HANDLE) db_event_first(MCONTACT hContact) -{ - return (currDb == NULL) ? 0 : currDb->FindFirstEvent(hContact); -} - -MIR_CORE_DLL(HANDLE) db_event_firstUnread(MCONTACT hContact) -{ - return (currDb == NULL) ? 0 : currDb->FindFirstUnreadEvent(hContact); -} - -MIR_CORE_DLL(int) db_event_get(HANDLE hDbEvent, DBEVENTINFO *dbei) -{ - return (currDb == NULL) ? 1 : currDb->GetEvent(hDbEvent, dbei); -} - -MIR_CORE_DLL(int) db_event_getBlobSize(HANDLE hDbEvent) -{ - return (currDb == NULL) ? 0 : currDb->GetBlobSize(hDbEvent); -} - -MIR_CORE_DLL(MCONTACT) db_event_getContact(HANDLE hDbEvent) -{ - return (currDb == NULL) ? 0 : currDb->GetEventContact(hDbEvent); -} - -MIR_CORE_DLL(HANDLE) db_event_last(MCONTACT hContact) -{ - return (currDb == NULL) ? 0 : currDb->FindLastEvent(hContact); -} - -MIR_CORE_DLL(int) db_event_markRead(MCONTACT hContact, HANDLE hDbEvent) -{ - return (currDb == NULL) ? 0 : currDb->MarkEventRead(hContact, hDbEvent); -} - -MIR_CORE_DLL(HANDLE) db_event_next(MCONTACT hContact, HANDLE hDbEvent) -{ - return (currDb == NULL) ? 0 : currDb->FindNextEvent(hContact, hDbEvent); -} - -MIR_CORE_DLL(HANDLE) db_event_prev(MCONTACT hContact, HANDLE hDbEvent) -{ - return (currDb == NULL) ? 0 : currDb->FindPrevEvent(hContact, hDbEvent); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// misc functions - -MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv) -{ - return (currDb == NULL) ? 1 : currDb->FreeVariant(dbv); -} - -MIR_CORE_DLL(INT_PTR) db_unset(MCONTACT hContact, const char *szModule, const char *szSetting) -{ - if (currDb == NULL) - return 1; - - return currDb->DeleteContactSetting(hContact, szModule, szSetting); -} - -MIR_CORE_DLL(DBCachedContact*) db_get_contact(MCONTACT hContact) -{ - return (currDb == NULL) ? NULL : currDb->m_cache->GetCachedContact(hContact); -} - -MIR_CORE_DLL(MCONTACT) db_find_first(const char *szProto) -{ - return (currDb == NULL) ? NULL : currDb->FindFirstContact(szProto); -} - -MIR_CORE_DLL(MCONTACT) db_find_next(MCONTACT hContact, const char *szProto) -{ - return (currDb == NULL) ? NULL : currDb->FindNextContact(hContact, szProto); -} - -extern "C" MIR_CORE_DLL(void) db_setCurrent(MIDatabase *_db) -{ - currDb = _db; - - // try to get the langpack's name from a profile - ptrT langpack(db_get_tsa(NULL, "Langpack", "Current")); - if (langpack && langpack[0] != '\0') - LoadLangPack(langpack); - else - GetDefaultLang(); -} - -MIR_CORE_DLL(BOOL) db_set_resident(const char *szModule, const char *szService, BOOL bEnable) -{ - if (currDb == NULL || szModule == NULL || szService == NULL) - return FALSE; - - char str[MAXMODULELABELLENGTH * 2]; - mir_snprintf(str, SIZEOF(str), "%s/%s", szModule, szService); - return currDb->SetSettingResident(bEnable, str); -} diff --git a/src/mir_core/http.cpp b/src/mir_core/http.cpp deleted file mode 100644 index b47cdd4e9c..0000000000 --- a/src/mir_core/http.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* -Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "commonheaders.h" - -///////////////////////////////////////////////////////////////////////////////////////// - -static const char szHexDigits[] = "0123456789ABCDEF"; - -MIR_CORE_DLL(char*) mir_urlEncode(const char *szUrl) -{ - if (szUrl == NULL) - return NULL; - - const BYTE *s; - int outputLen; - for (outputLen = 0, s = (const BYTE*)szUrl; *s; s++) { - if (('0' <= *s && *s <= '9') || //0-9 - ('A' <= *s && *s <= 'Z') || //ABC...XYZ - ('a' <= *s && *s <= 'z') || //abc...xyz - *s == '-' || *s == '_' || *s == '.' || *s == ' ') outputLen++; - else outputLen += 3; - } - - char *szOutput = (char*)mir_alloc(outputLen+1); - if (szOutput == NULL) - return NULL; - - char *d = szOutput; - for (s = (const BYTE*)szUrl; *s; s++) { - if (('0' <= *s && *s <= '9') || //0-9 - ('A' <= *s && *s <= 'Z') || //ABC...XYZ - ('a' <= *s && *s <= 'z') || //abc...xyz - *s == '-' || *s == '_' || *s == '.') *d++ = *s; - else if (*s == ' ') *d++='+'; - else { - *d++ = '%'; - *d++ = szHexDigits[*s >> 4]; - *d++ = szHexDigits[*s & 0xF]; - } - } - *d = '\0'; - return szOutput; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -MIR_CORE_DLL(char*) mir_base64_encode(const BYTE *input, unsigned inputLen) -{ - if (input == NULL) - return NULL; - - unsigned outputLen = mir_base64_encode_bufsize(inputLen); - char *output = (char*)mir_alloc(outputLen); - if (output == NULL) - return NULL; - - return mir_base64_encodebuf(input, inputLen, output, outputLen); -} - -MIR_CORE_DLL(char*) mir_base64_encodebuf(const BYTE *input, unsigned inputLen, char *output, unsigned outputLen) -{ - if (input == NULL) - return NULL; - - if (outputLen < mir_base64_encode_bufsize(inputLen)) - return NULL; - - char *p = output; - for (unsigned i=0; i < inputLen; ) { - int rest = 0; - BYTE chr[3]; - chr[0] = input[i++]; - chr[1] = (i < inputLen) ? input[i++] : rest++, 0; - chr[2] = (i < inputLen) ? input[i++] : rest++, 0; - - *p++ = cb64[ chr[0] >> 2 ]; - *p++ = cb64[ ((chr[0] & 0x03) << 4) | (chr[1] >> 4) ]; - int b2 = ((chr[1] & 0x0F) << 2) | (chr[2] >> 6), - b3 = chr[2] & 0x3F; - - if (rest == 2) { *p++ = '='; *p++ = '='; } - else if (rest == 1) { *p++ = cb64[b2]; *p++ = '='; } - else { *p++ = cb64[b2]; *p++ = cb64[b3]; } - } - - *p = 0; - return output; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static BYTE Base64DecodeTable[] = -{ - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, - 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, - 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, - -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, - 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 -}; - -MIR_CORE_DLL(void*) mir_base64_decode(const char *input, unsigned *outputLen) -{ - if (input == NULL) - return NULL; - - size_t length = strlen(input); - size_t nLength = (length / 4) * 3; - const char *stop = input + length; - - char *output = (char *)mir_alloc(nLength+1); - char *p = output; - - while (input < stop) { - BYTE e[4]; - for (int i=0; i < 4; ) { - if (*input == '\n' || *input == '\r') // simply skip a char - input++; - else if (*input == 0) // do not advance input - e[i++] = (BYTE)-1; - else - e[i++] = Base64DecodeTable[*input++]; - } - - if (e[0] == (BYTE)-1 || e[1] == (BYTE)-1) - break; - - *p++ = (e[0] << 2) | (e[1] >> 4); - if (e[2] != (BYTE)-1) - *p++ = ((e[1] & 15) << 4) | (e[2] >> 2); - if (e[3] != (BYTE)-1) - *p++ = ((e[2] & 3) << 6) | e[3]; - } - - *p = 0; - - if (outputLen != NULL) - *outputLen = p - output; - - return output; -} diff --git a/src/mir_core/icons.cpp b/src/mir_core/icons.cpp deleted file mode 100644 index 77c924be25..0000000000 --- a/src/mir_core/icons.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-14 Miranda NG project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -#include -#include "..\src\core\stdplug.h" - -MIR_CORE_DLL(void) Icon_Register(HINSTANCE hInst, const char *szSection, IconItem *pIcons, size_t iCount, char *prefix, int hLangpack) -{ - TCHAR szFile[MAX_PATH]; - GetModuleFileName(hInst, szFile, MAX_PATH); - - SKINICONDESC sid = { sizeof(sid) }; - sid.ptszDefaultFile = szFile; - sid.pszSection = (char*)szSection; - sid.flags = SIDF_PATH_TCHAR; - - for (unsigned i = 0; i < iCount; i++) { - char szSetting[100]; - if (prefix) { - mir_snprintf(szSetting, SIZEOF(szSetting), "%s_%s", prefix, pIcons[i].szName); - sid.pszName = szSetting; - } - else sid.pszName = pIcons[i].szName; - - sid.cx = sid.cy = pIcons[i].size; - sid.pszDescription = pIcons[i].szDescr; - sid.iDefaultIndex = -pIcons[i].defIconID; - pIcons[i].hIcolib = (HANDLE)CallService("Skin2/Icons/AddIcon", hLangpack, (LPARAM)&sid); - } -} - -MIR_CORE_DLL(void) Icon_RegisterT(HINSTANCE hInst, const TCHAR *szSection, IconItemT *pIcons, size_t iCount, char *prefix, int hLangpack) -{ - TCHAR szFile[MAX_PATH]; - GetModuleFileName(hInst, szFile, MAX_PATH); - - SKINICONDESC sid = { sizeof(sid) }; - sid.ptszDefaultFile = szFile; - sid.ptszSection = (TCHAR*)szSection; - sid.flags = SIDF_ALL_TCHAR; - - for (unsigned i = 0; i < iCount; i++) { - char szSetting[100]; - if (prefix) { - mir_snprintf(szSetting, SIZEOF(szSetting), "%s_%s", prefix, pIcons[i].szName); - sid.pszName = szSetting; - } - else sid.pszName = pIcons[i].szName; - - sid.cx = sid.cy = pIcons[i].size; - sid.ptszDescription = pIcons[i].tszDescr; - sid.iDefaultIndex = -pIcons[i].defIconID; - pIcons[i].hIcolib = (HANDLE)CallService("Skin2/Icons/AddIcon", hLangpack, (LPARAM)&sid); - } -} diff --git a/src/mir_core/json/JSONChildren.cpp b/src/mir_core/json/JSONChildren.cpp deleted file mode 100644 index 1eb9e29d46..0000000000 --- a/src/mir_core/json/JSONChildren.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" - -#include "JSONChildren.h" -#include "JSONNode.h" - -void jsonChildren::inc(void){ - if (mysize == mycapacity){ //it's full - if (!mycapacity){ //the array hasn't been created yet - JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); - #ifdef JSON_LESS_MEMORY - array = json_malloc(1); - mycapacity = 1; - #else - array = json_malloc(8); //8 seems average for JSON, and it's only 64 bytes - mycapacity = 8; - #endif - } else { - #ifdef JSON_LESS_MEMORY - mycapacity += 1; //increment the size of the array - #else - mycapacity <<= 1; //double the size of the array - #endif - array = json_realloc(array, mycapacity); - } - } -} - -void jsonChildren::inc(json_index_t amount){ - if (!amount) return; - if (mysize + amount >= mycapacity){ //it's full - if (!mycapacity){ //the array hasn't been created yet - JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); - #ifdef JSON_LESS_MEMORY - array = json_malloc(amount); - mycapacity = amount; - #else - array = json_malloc(amount > 8 ? amount : 8); //8 seems average for JSON, and it's only 64 bytes - mycapacity = amount > 8 ? amount : 8; - #endif - } else { - #ifdef JSON_LESS_MEMORY - mycapacity = mysize + amount; //increment the size of the array - #else - while(mysize + amount > mycapacity){ - mycapacity <<= 1; //double the size of the array - } - #endif - array = json_realloc(array, mycapacity); - } - } -} - -//actually deletes everything within the vector, this is safe to do on an empty or even a null array -void jsonChildren::deleteAll(void){ - json_foreach((*this), runner){ - JSON_ASSERT(*runner, JSON_TEXT("a null pointer within the children")); - JSONNode::deleteJSONNode(*runner); //this is why I can't do forward declaration - } -} - -void jsonChildren::doerase(JSONNode ** position, json_index_t number){ - JSON_ASSERT(array, JSON_TEXT("erasing something from a null array 2")); - JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 2")); - JSON_ASSERT(position + number <= array + mysize, JSON_TEXT("erasing out of bounds 2")); - if (position + number >= array + mysize){ - mysize = (json_index_t)(position - array); - #ifndef JSON_ISO_STRICT - JSON_ASSERT((long long)position - (long long)array >= 0, JSON_TEXT("doing negative allocation")); - #endif - } else { - memmove(position, position + number, (mysize - (position - array) - number) * sizeof(JSONNode *)); - mysize -= number; - } -} diff --git a/src/mir_core/json/JSONChildren.h b/src/mir_core/json/JSONChildren.h deleted file mode 100644 index ce697ffd77..0000000000 --- a/src/mir_core/json/JSONChildren.h +++ /dev/null @@ -1,232 +0,0 @@ -#ifndef JSONCHILDREN_H -#define JSONCHILDREN_H - -#include "JSONMemory.h" -#include "JSONDebug.h" //for JSON_ASSERT macro - -#define json_foreach(children, iterator)\ - JSONNode ** iterator = children.begin();\ - for(JSONNode ** iterator##_end = children.end(); iterator != iterator##_end; ++iterator) - -/* - This class is essentially a vector that has been heavily optimized for the specific purpose - of holding JSONNode children. It acts the same way as a vector, it has a automatically - expanding array. On destruction, this container automatically destroys everything contained - in it as well, so that you libJSON doesn't have to do that. - - T is JSONNode*, I can't define it that way directly because JSONNode uses this container, and because - the container deletes the children automatically, forward declaration can't be used - */ - -class JSONNode; //forward declaration - -class jsonChildren { -public: - //starts completely empty and the array is not allocated - jsonChildren(void) : array(0), mysize(0), mycapacity(0) { } - - //deletes the array and everything that is contained within it (using delete) - ~jsonChildren(void){ - if (array){ //the following function calls are safe, but take more time than a check here - deleteAll(); - libjson_free(array); - } - } - - //increase the size of the array - void inc(json_index_t amount); - void inc(void); - - //Adds something to the vector, doubling the array if necessary - void push_back(JSONNode * item){ - inc(); - array[mysize++] = item; - } - - //Adds something to the front of the vector, doubling the array if necessary - void push_front(JSONNode * item){ - inc(); - memmove(array + 1, array, mysize++ * sizeof(JSONNode *)); - array[0] = item; - } - - //gets an item out of the vector by it's position - inline JSONNode * operator[] (json_index_t position) const { - JSON_ASSERT(position < mysize, JSON_TEXT("Using [] out of bounds")); - JSON_ASSERT(position < mycapacity, JSON_TEXT("Using [] out of bounds")); - JSON_ASSERT(array, JSON_TEXT("Array is null")); - return array[position]; - } - - //returns the allocated capacity, but keep in mind that some might not be valid - inline json_index_t capacity() const { - return mycapacity; - } - - //returns the number of valid objects within the vector - inline json_index_t size() const { - return mysize; - } - - //tests whether or not the vector is empty - inline bool empty() const { - return mysize == 0; - } - - //clears (and deletes) everything from the vector and sets it's size to 0 - inline void clear() { - if (array){ //don't bother clearing anything if there is nothing in it - JSON_ASSERT(mycapacity != 0, JSON_TEXT("mycapacity is not zero, but array is null")); - deleteAll(); - mysize = 0; - } - JSON_ASSERT(mysize == 0, JSON_TEXT("mysize is not zero after clear")); - } - - //returns the beginning of the array - inline JSONNode ** begin(void) const { - return array; - } - - //returns the end of the array - inline JSONNode ** end(void) const { - return array + mysize; - } - - //makes sure that even after shirnking and expanding, the iterator is in same relative position - struct iteratorKeeper { - public: - #ifdef JSON_LIBRARY - iteratorKeeper(jsonChildren * pthis, JSONNode ** & position) : - myRelativeOffset((json_index_t)(position - pthis -> array)), - #else - iteratorKeeper(jsonChildren * pthis, JSONNode ** & position, bool reverse = false) : - myRelativeOffset(reverse ? (json_index_t)(pthis -> array + (size_t)pthis -> mysize - position) : (json_index_t)(position - pthis -> array)), - myReverse(reverse), - #endif - myChildren(pthis), - myPos(position){} - - ~iteratorKeeper(void){ - #ifdef JSON_LIBRARY - myPos = myChildren -> array + myRelativeOffset; - #else - if (myReverse){ - myPos = myChildren -> array + myChildren -> mysize - myRelativeOffset; - } else { - myPos = myChildren -> array + myRelativeOffset; - } - #endif - } - private: - iteratorKeeper(const iteratorKeeper &); - iteratorKeeper & operator = (const iteratorKeeper &); - - jsonChildren * myChildren; - JSONNode ** & myPos; - json_index_t myRelativeOffset; - #ifndef JSON_LIBRARY - bool myReverse BITS(1); - #endif - }; - - //This function DOES NOT delete the item it points to - inline void erase(JSONNode ** & position){ - JSON_ASSERT(array, JSON_TEXT("erasing something from a null array 1")); - JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 1")); - JSON_ASSERT(position <= array + mysize, JSON_TEXT("erasing out of bounds 1")); - memmove(position, position + 1, (mysize-- - (position - array) - 1) * sizeof(JSONNode *)); - iteratorKeeper ik(this, position); - shrink(); - } - - //This function DOES NOT delete the item it points to - inline void erase(JSONNode ** & position, json_index_t number){ - doerase(position, number); - iteratorKeeper ik(this, position); - shrink(); - } - - //This function DOES NOT delete the item it points to - inline void erase(JSONNode ** position, json_index_t number, JSONNode ** & starter){ - doerase(position, number); - iteratorKeeper ik(this, starter); - shrink(); - } - - #ifdef JSON_LIBRARY - void insert(JSONNode ** & position, JSONNode * item){ - #else - void insert(JSONNode ** & position, JSONNode * item, bool reverse = false){ - #endif - //position isnt relative to array because of realloc - JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 1")); - JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 1")); - { - #ifdef JSON_LIBRARY - iteratorKeeper ik(this, position); - #else - iteratorKeeper ik(this, position, reverse); - #endif - inc(); - } - memmove(position + 1, position, (mysize++ - (position - array)) * sizeof(JSONNode *)); - *position = item; - } - - void insert(JSONNode ** & position, JSONNode ** items, json_index_t num){ - JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 2")); - JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 2")); - { - iteratorKeeper ik(this, position); - inc(num); - } - const size_t ptrs = ((JSONNode **)(array + mysize)) - position; - memmove(position + num, position, ptrs * sizeof(JSONNode *)); - memcpy(position, items, num * sizeof(JSONNode *)); - mysize += num; - } - - inline void reserve(json_index_t amount){ - JSON_ASSERT(!array, JSON_TEXT("reserve is not meant to expand a preexisting array")); - JSON_ASSERT(!mycapacity, JSON_TEXT("reservec is not meant to expand a preexisting array")); - JSON_ASSERT(!mysize, JSON_TEXT("reserves is not meant to expand a preexisting array")); - array = json_malloc(mycapacity = amount); - } - - inline void reserve2(json_index_t amount){ - if (array){ - if (mycapacity < amount) inc(amount - mycapacity); - } else { - reserve(amount); - } - } - - //shrinks the array to only as large as it needs to be to hold everything within it - inline void shrink() { - if (mysize == 0){ //size is zero, we should completely free the array - libjson_free(array); //free does checks for a null pointer, so don't bother checking - array = 0; - #ifdef JSON_LESS_MEMORY - } else { //need to shrink it, using realloc - JSON_ASSERT(array, JSON_TEXT("shrinking a null array that is not size 0")); - array = json_realloc(array, mysize); - #endif - } - mycapacity = mysize; - } -JSON_PRIVATE - //to make sure it's not copyable - jsonChildren(const jsonChildren &); - jsonChildren & operator = (const jsonChildren &); - - void deleteAll(void); //implemented in JSONNode.cpp - void doerase(JSONNode ** position, json_index_t number); - - JSONNode ** array; //the expandable array - - json_index_t mysize; //the number of valid items - json_index_t mycapacity; //the number of possible items -}; - -#endif diff --git a/src/mir_core/json/JSONDebug.cpp b/src/mir_core/json/JSONDebug.cpp deleted file mode 100644 index e5ba81a188..0000000000 --- a/src/mir_core/json/JSONDebug.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" - -#include - -#ifdef JSON_DEBUG - -#ifdef JSON_STDERROR - #include //need std::cerr -#else - //otherwise, use a callback to tell the end user what happened - json_error_callback_t ErrorCallback = 0; - void JSONDebug::register_callback(json_error_callback_t callback){ - ErrorCallback = callback; - } -#endif - -//Something went wrong or an assert failed -void JSONDebug::_JSON_FAIL(const json_string & msg){ - #ifdef JSON_STDERROR //no callback, just use stderror - #ifndef JSON_UNICODE - std::cerr << msg << std::endl; - #else - std::cerr << std::string(msg.begin(), msg.end()) << std::endl; - #endif - #else - if (ErrorCallback){ //only do anything if the callback is registered - #ifdef JSON_LIBRARY - ErrorCallback(msg.c_str()); - #else - ErrorCallback(msg); - #endif - } - #endif -} - -//asserts that condition is true, more useful than cassert because it lets you keep going -void JSONDebug::_JSON_ASSERT(bool condition, const json_string & msg){ - if (!condition){ - _JSON_FAIL(msg); - } -} -#endif diff --git a/src/mir_core/json/JSONDebug.h b/src/mir_core/json/JSONDebug.h deleted file mode 100644 index ff1cedf8fc..0000000000 --- a/src/mir_core/json/JSONDebug.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef JSON_DEBUG_H -#define JSON_DEBUG_H - -#include "JSONDefs.h" -#include "JSONOptions.h" - -#ifdef JSON_UNIT_TEST - #define JSON_PRIVATE -#else - #define JSON_PRIVATE private: -#endif - -#ifdef JSON_DEBUG - #ifdef JSON_SAFE - #define JSON_ASSERT_SAFE(condition, msg, code)\ - {\ - if (!(condition)) {\ - JSON_FAIL(msg);\ - code\ - }\ - } - #define JSON_FAIL_SAFE(msg, code)\ - {\ - JSON_FAIL(msg);\ - code\ - } - #else - #define JSON_ASSERT_SAFE(condition, msg, code) JSON_ASSERT(condition, msg) - #define JSON_FAIL_SAFE(msg, code) JSON_FAIL(msg) - #endif - - #define JSON_FAIL JSONDebug::_JSON_FAIL - #define JSON_ASSERT JSONDebug::_JSON_ASSERT - - class JSONDebug { - public: - #ifndef JSON_STDERROR - static void register_callback(json_error_callback_t callback); - #endif - static void _JSON_FAIL(const json_string & msg); - static void _JSON_ASSERT(bool condition, const json_string & msg); - }; -#else - #ifdef JSON_SAFE - #define JSON_ASSERT_SAFE(condition, msg, code)\ - {\ - if (!(condition)) {\ - code\ - }\ - } - #define JSON_FAIL_SAFE(msg, code)\ - {\ - code\ - } - #else - #define JSON_ASSERT_SAFE(condition, msg, code) - #define JSON_FAIL_SAFE(msg, code) - #endif - - #define JSON_ASSERT(condition, msg) - #define JSON_FAIL(msg) -#endif - -static const json_string EMPTY_STRING; -static const std::string EMPTY_STRING2; - -#endif - diff --git a/src/mir_core/json/JSONDefs.h b/src/mir_core/json/JSONDefs.h deleted file mode 100644 index 9bcaa55b64..0000000000 --- a/src/mir_core/json/JSONDefs.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef JSONDEFS_H -#define JSONDEFS_H - -/* - Defines all of the types of functions and various other definitions - that are used in C applications, this is very useful if dynamically loading - the library instead of linking. -*/ - -#include "JSONOptions.h" - -#define JSON_NULL '\0' -#define JSON_STRING '\1' -#define JSON_NUMBER '\2' -#define JSON_BOOL '\3' -#define JSON_ARRAY '\4' -#define JSON_NODE '\5' - -#ifdef __cplusplus - #include -#endif - -#ifdef JSON_UNICODE - #ifdef JSON_ISO_STRICT - #error, You can not use unicode under ISO Strict C++ - #endif - #define json_char wchar_t - #define json_uchar wchar_t - #ifdef __cplusplus - #include //need wide characters - typedef std::wstring json_string; - #else - #include //need wide characters - #endif - #define JSON_TEXT(s) L ## s - #define json_strlen wcslen - #define json_strcmp wcscmp -#else - #define json_char char - #define json_uchar BYTE - #ifdef __cplusplus - typedef std::string json_string; - #endif - #define JSON_TEXT(s) s - #define json_strlen strlen - #define json_strcmp strcmp -#endif - -#ifdef JSON_LESS_MEMORY - #define BITS(x) :x //tells the compiler how many bits to use for a field - typedef float json_number; -#else - #define BITS(x) - typedef double json_number; -#endif - -#if defined JSON_DEBUG || defined JSON_SAFE - #ifdef JSON_LIBRARY - typedef void (*json_error_callback_t)(const json_char *); - #else - typedef void (*json_error_callback_t)(const json_string &); - #endif -#endif - -#ifdef JSON_INDEX_TYPE - typedef JSON_INDEX_TYPE json_index_t; -#else - typedef size_t json_index_t; -#endif - -typedef void (*json_mutex_callback_t)(void *); -typedef void (*json_free_t)(void *); -#ifndef JSON_LIBRARY - typedef void * (*json_malloc_t)(size_t); - typedef void * (*json_realloc_t)(void *, size_t); -#else - #define JSONNODE void //so that JSONNODE* is void* - typedef JSONNODE** JSONNODE_ITERATOR; - typedef void * (*json_malloc_t)(size_t); - typedef void * (*json_realloc_t)(void *, size_t); -#endif - -#endif //JSONDEFS_H diff --git a/src/mir_core/json/JSONIterators.cpp b/src/mir_core/json/JSONIterators.cpp deleted file mode 100644 index 1ff164e1be..0000000000 --- a/src/mir_core/json/JSONIterators.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" - -#include "JSONNode.h" - -#ifdef JSON_ITERATORS - #ifdef JSON_REF_COUNT - #define JSON_ASSERT_UNIQUE(x) JSON_ASSERT(internal -> refcount == 1, json_string(JSON_TEXT(x)) + JSON_TEXT(" in non single reference")) - #else - #define JSON_ASSERT_UNIQUE(x) (void)0 - #endif - - #ifdef JSON_MUTEX_CALLBACKS - #define JSON_MUTEX_COPY2 ,internal -> mylock - #else - #define JSON_MUTEX_COPY2 - #endif - -JSONNode::json_iterator JSONNode::find(const json_string & name_t){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); - makeUniqueInternal(); - if (JSONNode ** res = internal -> at(name_t)) { - return ptr_to_json_iterator(res); - } - return end(); -} - -#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode::json_iterator JSONNode::find_nocase(const json_string & name_t){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); - makeUniqueInternal(); - if (JSONNode ** res = internal -> at_nocase(name_t)) { - return ptr_to_json_iterator(res); - } - return end(); - } -#endif - -JSONNode::json_iterator JSONNode::erase(json_iterator pos){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("erase 1"); - JSON_ASSERT_SAFE(pos < end(), JSON_TEXT("erase out of range"), return end();); - JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("erase out of range"), return begin();); - deleteJSONNode(*(json_iterator_ptr(pos))); - internal -> Children.erase(json_iterator_ptr(pos)); - return (empty()) ? end() : pos; -} - -JSONNode::json_iterator JSONNode::erase(json_iterator _start, const json_iterator & _end){ - if (_start == _end) return _start; - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("erase 3"); - JSON_ASSERT_SAFE(_start <= end(), JSON_TEXT("erase out of lo range"), return end();); - JSON_ASSERT_SAFE(_end <= end(), JSON_TEXT("erase out of hi range"), return end();); - JSON_ASSERT_SAFE(_start >= begin(), JSON_TEXT("erase out of lo range"), return begin();); - JSON_ASSERT_SAFE(_end >= begin(), JSON_TEXT("erase out of hi range"), return begin();); - for (JSONNode ** pos = json_iterator_ptr(_start); pos < json_iterator_ptr(_end); ++pos){ - deleteJSONNode(*pos); - } - - internal -> Children.erase(json_iterator_ptr(_start), json_iterator_ptr(_end) - json_iterator_ptr(_start)); - return (empty()) ? end() : _start; -} - -#ifdef JSON_LIBRARY -JSONNode::json_iterator JSONNode::insert(json_iterator pos, JSONNode * x){ -#else -JSONNode::json_iterator JSONNode::insert(json_iterator pos, const JSONNode & x){ -#endif - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("insert 1"); - if (json_iterator_ptr(pos) >= internal -> Children.end()) { - internal -> push_back(x); - return end() - 1; - } - JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of lo range"), return begin();); - #ifdef JSON_LIBRARY - internal -> Children.insert(json_iterator_ptr(pos), x); - #else - internal -> Children.insert(json_iterator_ptr(pos), newJSONNode(x)); - #endif - return pos; -} - -JSONNode::json_iterator JSONNode::insertFFF(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("insertFFF"); - JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of high range"), return end();); - JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of low range"), return begin();); - const size_t num = _end - _start; - json_auto mem(num); - JSONNode ** runner = mem.ptr; - for (JSONNode ** po = _start; po < _end; ++po){ - *runner++=newJSONNode(*(*po) JSON_MUTEX_COPY2); - } - internal -> Children.insert(json_iterator_ptr(pos), mem.ptr, num); - return pos; -} - -#ifndef JSON_LIBRARY - JSONNode::const_iterator JSONNode::find(const json_string & name_t) const { - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); - if (JSONNode ** res = internal -> at(name_t)) { - return JSONNode::const_iterator(res); - } - return JSONNode::const_iterator(internal -> end()); - } - - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode::const_iterator JSONNode::find_nocase(const json_string & name_t) const { - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); - if (JSONNode ** res = internal -> at_nocase(name_t)) { - return JSONNode::const_iterator(res); - } - return JSONNode::const_iterator(internal -> end()); - } - #endif - - JSONNode::reverse_iterator JSONNode::erase(reverse_iterator pos){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("erase 2"); - JSON_ASSERT_SAFE(pos < rend(), JSON_TEXT("erase out of range"), return rend();); - JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("erase out of range"), return rbegin();); - deleteJSONNode(*(pos.it)); - internal -> Children.erase(pos.it); - return (empty()) ? rend() : pos + 1; - } - - JSONNode::reverse_iterator JSONNode::erase(reverse_iterator _start, const reverse_iterator & _end){ - if (_start == _end) return _start; - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("erase 4"); - JSON_ASSERT_SAFE(_start <= rend(), JSON_TEXT("erase out of lo range"), return rend();); - JSON_ASSERT_SAFE(_end <= rend(), JSON_TEXT("erase out of hi range"), return rend();); - JSON_ASSERT_SAFE(_start >= rbegin(), JSON_TEXT("erase out of lo range"), return rbegin();); - JSON_ASSERT_SAFE(_end >= rbegin(), JSON_TEXT("erase out of hi range"), return rbegin();); - for (JSONNode ** pos = _start.it; pos > _end.it; --pos){ - deleteJSONNode(*pos); - } - const size_t num = _start.it - _end.it; - internal -> Children.erase(_end.it + 1, num, _start.it); - return (empty()) ? rend() : _start + num; - } - - JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const JSONNode & x){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("insert 1"); - if (pos.it < internal -> Children.begin()) { - internal -> push_front(x); - return rend() - 1; - } - JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); - internal -> Children.insert(++pos.it, newJSONNode(x), true); - return pos; - } - - JSONNode::reverse_iterator JSONNode::insertRFF(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("insert RFF"); - JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend();); - JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); - const size_t num = _end - _start; - json_auto mem(num); - JSONNode ** runner = mem.ptr + num; - for (JSONNode ** po = _start; po < _end; ++po){ //fill it backwards - *(--runner) = newJSONNode(*(*po) JSON_MUTEX_COPY2); - } - internal -> Children.insert(++pos.it, mem.ptr, num); - return pos - num + 1; - } - - JSONNode::iterator JSONNode::insertFRR(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("insert FRR"); - JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of range"), return end();); - JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of range"), return begin();); - const size_t num = _start - _end; - json_auto mem(num); - JSONNode ** runner = mem.ptr; - for (JSONNode ** po = _start; po > _end; --po){ - *runner++=newJSONNode(*(*po) JSON_MUTEX_COPY2); - } - internal -> Children.insert(pos.it, mem.ptr, num); - return pos; - } - - JSONNode::reverse_iterator JSONNode::insertRRR(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); - JSON_ASSERT_UNIQUE("insert RRR"); - JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend();); - JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); - const size_t num = _start - _end; - json_auto mem(num); - JSONNode ** runner = mem.ptr; - for (JSONNode ** po = _start; po > _end; --po){ - *runner++=newJSONNode(*(*po) JSON_MUTEX_COPY2); - } - internal -> Children.insert(++pos.it, mem.ptr, num); - return pos - num + 1; - } -#endif - -#endif diff --git a/src/mir_core/json/JSONMemory.cpp b/src/mir_core/json/JSONMemory.cpp deleted file mode 100644 index dfe757b5c1..0000000000 --- a/src/mir_core/json/JSONMemory.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" - -#include "JSONMemory.h" -#include "JSONNode.h" - -#ifdef JSON_MEMORY_MANAGE - void auto_expand::purge(void){ - for(std::map::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ - #if defined(JSON_DEBUG) || defined(JSON_SAFE) - void * temp = (void*)i -> first; //because its pass by reference - libjson_free(temp); - #else - libjson_free((void*)i -> first); - #endif - } - } - - void auto_expand_node::purge(void){ - for(std::map::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ - JSONNode::deleteJSONNode((JSONNode *)i -> second); - } - } -#endif - -#ifdef JSON_MEMORY_CALLBACKS - -json_malloc_t mymalloc = 0; -json_realloc_t myrealloc = 0; -json_free_t myfree = 0; - -void * JSONMemory::json_malloc(size_t siz){ - if (mymalloc){ - #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful - void * result = mymalloc(siz); - JSON_ASSERT(result, JSON_TEXT("out of memory")); - return result; - #else - return mymalloc((unsigned long)siz); - #endif - } - #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful - void * result = malloc(siz); - JSON_ASSERT(result, JSON_TEXT("out of memory")); - return result; - #else - return malloc(siz); - #endif -} - -void * JSONMemory::json_realloc(void * ptr, size_t siz){ - if (myrealloc){ - #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful - void * result = myrealloc(ptr, siz); - JSON_ASSERT(result, JSON_TEXT("out of memory")); - return result; - #else - return myrealloc(ptr, (unsigned long)siz); - #endif - } - #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful - void * result = realloc(ptr, siz); - JSON_ASSERT(result, JSON_TEXT("out of memory")); - return result; - #else - return realloc(ptr, siz); - #endif -} - -void JSONMemory::json_free(void * ptr){ - if (myfree){ - myfree(ptr); - } else { - free(ptr); - } -} - -void JSONMemory::registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre){ - mymalloc = mal; - myrealloc = real; - myfree = fre; -} - -#endif diff --git a/src/mir_core/json/JSONMemory.h b/src/mir_core/json/JSONMemory.h deleted file mode 100644 index 32e8c3f4ef..0000000000 --- a/src/mir_core/json/JSONMemory.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef JSON_MEMORY_H -#define JSON_MEMORY_H - -#include //for malloc, realloc, and free -#include //for memmove -#include "JSONOptions.h" -#include "JSONDebug.h" - -#if defined(JSON_DEBUG) || defined(JSON_SAFE) - #define JSON_FREE_PASSTYPE & -#else - #define JSON_FREE_PASSTYPE -#endif - -#ifdef JSON_MEMORY_CALLBACKS - class JSONMemory { - public: - static void * json_malloc(size_t siz); - static void * json_realloc(void * ptr, size_t siz); - static void json_free(void * ptr); - static void registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre); - }; - - template static inline T * json_malloc(size_t count){ - return (T *)JSONMemory::json_malloc(sizeof(T) * count); - } - - template static inline T * json_realloc(T * ptr, size_t count){ - return (T *)JSONMemory::json_realloc(ptr, sizeof(T) * count); - } - - template static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr){ - JSONMemory::json_free(ptr); - #if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again - ptr = 0; - #endif - } -#else - template - static inline T * json_malloc(size_t count){ - #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful - void * result = malloc(count * sizeof(T)); - JSON_ASSERT(result, JSON_TEXT("out of memory")); - #ifdef JSON_NULL_MEMORY - memset(result, '\0', count * sizeof(T)); - #endif - return (T *)result; - #else - return (T *)malloc(count * sizeof(T)); - #endif - } - - template - static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr){ - free(ptr); - #if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again - ptr = 0; - #endif - } - - template - static inline T * json_realloc(T * ptr, size_t count){ - #ifdef JSON_DEBUG //in debug mode, check the results of realloc to be sure it was successful - void * result = realloc(ptr, count * sizeof(T)); - JSON_ASSERT(result, JSON_TEXT("out of memory")); - #ifdef JSON_NULL_MEMORY - memset(result, '\0', count * sizeof(T)); - #endif - return (T *)result; - #else - return (T *)realloc(ptr, count * sizeof(T)); - #endif - } -#endif - -#ifdef JSON_MEMORY_MANAGE - #include - class JSONNode; - struct auto_expand { - auto_expand(void) : mymap() {} - ~auto_expand(void){ purge(); } - void purge(void); - inline void clear(void){ purge(); mymap.clear(); } - inline void * insert(void * ptr){ mymap[ptr] = ptr; return ptr; } - inline void remove(void * ptr){ - std::map::iterator i = mymap.find(ptr); - JSON_ASSERT(i != mymap.end(), JSON_TEXT("Removing a non-managed item")); - mymap.erase(i); - } - std::map mymap; - }; - - struct auto_expand_node { - auto_expand_node(void) : mymap() {} - ~auto_expand_node(void){ purge(); } - void purge(void); - inline void clear(void){ purge(); mymap.clear(); } - inline JSONNode * insert(JSONNode * ptr){ mymap[ptr] = ptr; return ptr; } - inline void remove(void * ptr){ - std::map::iterator i = mymap.find(ptr); - if(i != mymap.end()) mymap.erase(i); - } - std::map mymap; - }; -#endif - -//The C++ way, use an self-deleting pointer and let the optimizer decide when it gets destroyed -template -class json_auto { - public: - json_auto(void) : ptr(0){} - json_auto(size_t count) : ptr(json_malloc(count)) {} - ~json_auto(void){ - libjson_free(ptr); - } - void set(T * p){ - ptr = p; - } - T * ptr; - private: - json_auto(const json_auto &); - json_auto & operator = (const json_auto &); -}; - -//Clears a string, if required, frees the memory -static inline void clearString(json_string & str){ - #ifdef JSON_LESS_MEMORY - json_string().swap(str); - #else - str.clear(); - #endif -} - -#endif diff --git a/src/mir_core/json/JSONNode.cpp b/src/mir_core/json/JSONNode.cpp deleted file mode 100644 index b1a492b5a6..0000000000 --- a/src/mir_core/json/JSONNode.cpp +++ /dev/null @@ -1,312 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" - -#include "JSONNode.h" - -#ifdef JSON_UNIT_TEST - int allocCount = 0; - int deallocCount = 0; - int internalAllocCount = 0; - int internalDeallocCount = 0; - int JSONNode::getNodeAllocationCount(void){ return allocCount; } - int JSONNode::getNodeDeallocationCount(void){ return deallocCount; } - int JSONNode::getInternalAllocationCount(void){ return internalAllocCount; } - int JSONNode::getInternalDeallocationCount(void){ return internalDeallocCount; } - void JSONNode::incAllocCount(void){ ++allocCount; } - void JSONNode::decAllocCount(void){ ++deallocCount; } - void JSONNode::incinternalAllocCount(void){ ++internalAllocCount; } - void JSONNode::decinternalAllocCount(void){ ++internalDeallocCount; } -#endif - -#define IMPLEMENT_CTOR(type)\ - JSONNode::JSONNode(const json_string & name_t, type value_t) : internal(internalJSONNode::newInternal()) {\ - internal -> Set(value_t);\ - internal -> setname(name_t);\ - incAllocCount();\ - } -IMPLEMENT_FOR_ALL_TYPES(IMPLEMENT_CTOR) - -#ifndef JSON_LIBRARY - JSONNode::JSONNode(const json_string & name_t, const json_char * value_t) : internal(internalJSONNode::newInternal()) { - internal -> Set(json_string(value_t)); - internal -> setname(name_t); - incAllocCount(); - } -#endif - -JSONNode JSONNode::as_node(void) const { - JSON_CHECK_INTERNAL(); - if (type() == JSON_NODE){ - return *this; - } else if (type() == JSON_ARRAY){ - JSONNode res = duplicate(); - res.internal -> _type = JSON_NODE; - return res; - } - #ifdef JSON_MUTEX_CALLBACKS - if (internal -> mylock){ - JSONNode res = JSONNode(JSON_NODE); - res.set_mutex(internal -> mylock); - return res; - } - #endif - return JSONNode(JSON_NODE); -} - -JSONNode JSONNode::as_array(void) const { - JSON_CHECK_INTERNAL(); - if (type() == JSON_ARRAY){ - return *this; - } else if (type() == JSON_NODE){ - JSONNode res = duplicate(); - res.internal -> _type = JSON_ARRAY; - json_foreach(res.internal -> Children, runner){ - (*runner) -> set_name(JSON_TEXT("")); - } - return res; - } - #ifdef JSON_MUTEX_CALLBACKS - if (internal -> mylock){ - JSONNode res = JSONNode(JSON_ARRAY); - res.set_mutex(internal -> mylock); - return res; - } - #endif - return JSONNode(JSON_ARRAY); -} - -void JSONNode::cast(char newtype){ - JSON_CHECK_INTERNAL(); - if (newtype == type()) return; - - switch(newtype){ - case JSON_NULL: - nullify(); - return; - case JSON_STRING: - *this = as_string(); - return; - case JSON_NUMBER: - *this = as_float(); - return; - case JSON_BOOL: - *this = as_bool(); - return; - case JSON_ARRAY: - *this = as_array(); - return; - case JSON_NODE: - *this = as_node(); - return; - } - JSON_FAIL(JSON_TEXT("cast to unknown type")); -} - -//different just to supress the warning -#ifdef JSON_REF_COUNT -void JSONNode::merge(JSONNode & other){ -#else -void JSONNode::merge(JSONNode &) { -#endif - JSON_CHECK_INTERNAL(); - #ifdef JSON_REF_COUNT - if (internal == other.internal) return; - JSON_ASSERT(*this == other, JSON_TEXT("merging two nodes that aren't equal")); - if (internal -> refcount < other.internal -> refcount){ - *this = other; - } else { - other = *this; - } - #endif -} - -#ifdef JSON_REF_COUNT - void JSONNode::merge(JSONNode * other){ - JSON_CHECK_INTERNAL(); - if (internal == other -> internal) return; - *other = *this; - } - - //different just to supress the warning - void JSONNode::merge(unsigned int num, ...) { -#else - void JSONNode::merge(unsigned int, ...) { -#endif - JSON_CHECK_INTERNAL(); - #ifdef JSON_REF_COUNT - va_list args; - va_start(args, num); - for(unsigned int i=0; i < num; ++i){ - merge(va_arg(args, JSONNode*)); - } - va_end(args); - #endif -} - -JSONNode JSONNode::duplicate(void) const { - JSON_CHECK_INTERNAL(); - JSONNode mycopy(*this); - #ifdef JSON_REF_COUNT - JSON_ASSERT(internal == mycopy.internal, JSON_TEXT("copy ctor failed to ref count correctly")); - mycopy.makeUniqueInternal(); - #endif - JSON_ASSERT(internal != mycopy.internal, JSON_TEXT("makeUniqueInternal failed")); - return mycopy; -} - -JSONNode & JSONNode::at(json_index_t pos){ - JSON_CHECK_INTERNAL(); - if (pos >= internal -> size()) { - JSON_FAIL(JSON_TEXT("at() out of bounds")); - throw std::out_of_range(EMPTY_STRING2); - } - return (*this)[pos]; -} - -const JSONNode & JSONNode::at(json_index_t pos) const { - JSON_CHECK_INTERNAL(); - if (pos >= internal -> size()) { - JSON_FAIL(JSON_TEXT("at() const out of bounds")); - throw std::out_of_range(EMPTY_STRING2); - } - return (*this)[pos]; -} - -JSONNode & JSONNode::operator[](json_index_t pos){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] out of bounds")); - makeUniqueInternal(); - return *(internal -> at(pos)); -} - -const JSONNode & JSONNode::operator[](json_index_t pos) const { - JSON_CHECK_INTERNAL(); - JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] const out of bounds")); - return *(internal -> at(pos)); -} - -JSONNode & JSONNode::at(const json_string & name_t){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); - makeUniqueInternal(); - if (JSONNode ** res = internal -> at(name_t)) { - return *(*res); - } - JSON_FAIL(json_string(JSON_TEXT("at could not find child by name: ")) + name_t); - throw std::out_of_range(EMPTY_STRING2); -} - -const JSONNode & JSONNode::at(const json_string & name_t) const { - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); - if (JSONNode ** res = internal -> at(name_t)) { - return *(*res); - } - JSON_FAIL(json_string(JSON_TEXT("at const could not find child by name: ")) + name_t); - throw std::out_of_range(EMPTY_STRING2); -} - -#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode & JSONNode::at_nocase(const json_string & name_t){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); - makeUniqueInternal(); - if (JSONNode ** res = internal -> at_nocase(name_t)) { - return *(*res); - } - JSON_FAIL(json_string(JSON_TEXT("at_nocase could not find child by name: ")) + name_t); - throw std::out_of_range(EMPTY_STRING2); - } - - const JSONNode & JSONNode::at_nocase(const json_string & name_t) const { - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); - if (JSONNode ** res = internal -> at_nocase(name_t)) { - return *(*res); - } - JSON_FAIL(json_string(JSON_TEXT("at_nocase const could not find child by name: ")) + name_t); - throw std::out_of_range(EMPTY_STRING2); - } -#endif - -#ifndef JSON_LIBRARY - struct auto_delete { - public: - auto_delete(JSONNode *node) : mynode(node){}; - ~auto_delete(void){ JSONNode::deleteJSONNode(mynode); }; - JSONNode * mynode; - private: - auto_delete(const auto_delete &); - auto_delete & operator = (const auto_delete &); - }; -#endif - -JSONNode JSON_PTR_LIB JSONNode::pop_back(json_index_t pos){ - JSON_CHECK_INTERNAL(); - if (pos >= internal -> size()) { - JSON_FAIL(JSON_TEXT("pop_back out of bounds")); - throw std::out_of_range(EMPTY_STRING2); - } - makeUniqueInternal(); - #ifdef JSON_LIBRARY - return internal -> pop_back(pos); - #else - auto_delete temp(internal -> pop_back(pos)); - return *temp.mynode; - #endif -} - -JSONNode JSON_PTR_LIB JSONNode::pop_back(const json_string & name_t){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("popping a non-iteratable node")); - #ifdef JSON_LIBRARY - return internal -> pop_back(name_t); - #else - if (JSONNode * res = internal -> pop_back(name_t)) { - auto_delete temp(res); - return *(temp.mynode); - } - JSON_FAIL(json_string(JSON_TEXT("pop_back const could not find child by name: ")) + name_t); - throw std::out_of_range(EMPTY_STRING2); - #endif -} - -#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode JSON_PTR_LIB JSONNode::pop_back_nocase(const json_string & name_t){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("popping a non-iteratable node")); - #ifdef JSON_LIBRARY - return internal -> pop_back_nocase(name_t); - #else - if (JSONNode * res = internal -> pop_back_nocase(name_t)) { - auto_delete temp(res); - return *(temp.mynode); - } - JSON_FAIL(json_string(JSON_TEXT("pop_back_nocase could not find child by name: ")) + name_t); - throw std::out_of_range(EMPTY_STRING2); - #endif - } -#endif diff --git a/src/mir_core/json/JSONNode.h b/src/mir_core/json/JSONNode.h deleted file mode 100644 index dfb6ff01f3..0000000000 --- a/src/mir_core/json/JSONNode.h +++ /dev/null @@ -1,851 +0,0 @@ -#ifndef JSONNODE_H -#define JSONNODE_H - -#include "JSONDefs.h" //for string type -#include "internalJSONNode.h" //internal structure for json value - -#ifdef JSON_BINARY - #include "JSON_Base64.h" -#endif - -#ifndef JSON_REF_COUNT - #define makeUniqueInternal() (void)0 -#endif - -#define JSON_CHECK_INTERNAL() JSON_ASSERT(internal, JSON_TEXT("no internal")) - -#ifdef JSON_MUTEX_CALLBACKS - #define JSON_MUTEX_COPY_DECL ,void * parentMutex - #define JSON_MUTEX_COPY_DECL2 ,void * parentMutex = 0 -#else - #define JSON_MUTEX_COPY_DECL - #define JSON_MUTEX_COPY_DECL2 -#endif - -#ifdef JSON_LIBRARY - #define JSON_PTR_LIB * - #define JSON_NEW(x) JSONNode::newJSONNode_Shallow(x) - #define DECLARE_FOR_ALL_TYPES(foo)\ - foo(long);\ - foo(double);\ - foo(bool);\ - foo(const json_string &); - #define DECLARE_FOR_ALL_TYPES_CONST(foo)\ - foo(long) const;\ - foo(double) const;\ - foo(bool) const;\ - foo(const json_string &) const;\ - foo(const JSONNode &) const; - #define IMPLEMENT_FOR_ALL_NUMBERS(foo)\ - foo(long)\ - foo(double) - -#else - #define JSON_PTR_LIB - #define JSON_NEW(x) x - #define DECLARE_FOR_ALL_TYPES(foo)\ - foo(char); foo(unsigned char);\ - foo(short); foo(unsigned short);\ - foo(int); foo(unsigned int);\ - foo(long); foo(unsigned long);\ - foo(float); foo(double);\ - foo(bool);\ - foo(const json_string &);\ - foo(const json_char *); - #define DECLARE_FOR_ALL_TYPES_CONST(foo)\ - foo(char) const; foo(unsigned char) const;\ - foo(short) const; foo(unsigned short) const;\ - foo(int) const; foo(unsigned int) const;\ - foo(long) const; foo(unsigned long) const;\ - foo(float) const; foo(double) const;\ - foo(bool) const;\ - foo(const json_string &) const;\ - foo(const JSONNode &) const;\ - foo(const json_char *) const; - #define IMPLEMENT_FOR_ALL_NUMBERS(foo)\ - foo(char) foo(unsigned char)\ - foo(short) foo(unsigned short)\ - foo(int) foo(unsigned int)\ - foo(long) foo(unsigned long)\ - foo(float) foo(double) -#endif -#define IMPLEMENT_FOR_ALL_TYPES(foo)\ - IMPLEMENT_FOR_ALL_NUMBERS(foo)\ - foo(const json_string &)\ - foo(bool) -/* - This class is mostly just a wrapper class around internalJSONNode, this class keeps - the reference count and handles copy on write and such. This class is also responsible - for argument checking and throwing exceptions if needed. -*/ - -class JSONNode { -public: - explicit JSONNode(char mytype = JSON_NODE); - #define DECLARE_CTOR(type) JSONNode(const json_string & name_t, type value_t) - DECLARE_FOR_ALL_TYPES(DECLARE_CTOR) - - JSONNode(const JSONNode & orig); - ~JSONNode(void); - - json_index_t size(void) const; - bool empty(void) const; - void clear(void); - unsigned char type(void) const; - - const json_char* name(void) const; - void set_name(const json_string & newname); - #ifdef JSON_COMMENTS - void set_comment(const json_string & comment); - json_string get_comment(void) const; - #endif - #ifndef JSON_PREPARSE - void preparse(void); - #endif - #ifdef JSON_VALIDATE - #ifndef JSON_SAFE - #error JSON_VALIDATE also requires JSON_SAFE - #endif - bool validate(void); - #endif - - json_string as_string(void) const; - long as_int(void) const; - double as_float(void) const; - bool as_bool(void) const; - JSONNode as_node(void) const; - JSONNode as_array(void) const; - - #ifdef JSON_BINARY - std::string as_binary(void) const; - void set_binary(const unsigned char * bin, json_index_t bytes); - #endif - - JSONNode & at(json_index_t pos); - const JSONNode & at(json_index_t pos) const; - JSONNode & operator[](json_index_t pos); - const JSONNode & operator[](json_index_t pos) const; - - JSONNode & at(const json_string & name_t); - const JSONNode & at(const json_string & name_t) const; - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode & at_nocase(const json_string & name_t); - const JSONNode & at_nocase(const json_string & name_t) const; - #endif - JSONNode & operator[](const json_string & name_t); - const JSONNode & operator[](const json_string & name_t) const; - #ifdef JSON_LIBRARY - void push_back(JSONNode *node); - #else - void push_back(const JSONNode & node); - #endif - void reserve(json_index_t size); - JSONNode JSON_PTR_LIB pop_back(json_index_t pos); - JSONNode JSON_PTR_LIB pop_back(const json_string & name_t); - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode JSON_PTR_LIB pop_back_nocase(const json_string & name_t); - #endif - - DECLARE_FOR_ALL_TYPES(JSONNode & operator = ) - JSONNode & operator = (const JSONNode &); - DECLARE_FOR_ALL_TYPES_CONST(bool operator ==) - DECLARE_FOR_ALL_TYPES_CONST(bool operator !=) - - void nullify(void); - void swap(JSONNode & other); - void merge(JSONNode & other); - void merge(unsigned int num, ...); - JSONNode duplicate(void) const; - void cast(char newtype); - - //iterator - #ifdef JSON_ITERATORS - #ifndef JSON_LIBRARY - #define json_iterator_ptr(iter) iter.it - #define ptr_to_json_iterator(iter) json_iterator(iter) - struct iterator { - inline iterator& operator ++(void){ ++it; return *this; } - inline iterator& operator --(void){ --it; return *this; } - inline iterator& operator +=(long i){ it += i; return *this; } - inline iterator& operator -=(long i){ it -= i; return *this; } - inline iterator operator ++(int){ - iterator result(*this); - ++it; - return result; - } - inline iterator operator --(int){ - iterator result(*this); - --it; - return result; - } - inline iterator operator +(long i) const { - iterator result(*this); - result.it += i; - return result; - } - inline iterator operator -(long i) const { - iterator result(*this); - result.it -= i; - return result; - } - inline JSONNode& operator [](size_t pos) const { return *it[pos]; }; - inline JSONNode& operator *(void) const { return *(*it); } - inline bool operator == (const iterator & other) const { return it == other.it; } - inline bool operator != (const iterator & other) const { return it != other.it; } - inline bool operator > (const iterator & other) const { return it > other.it; } - inline bool operator >= (const iterator & other) const { return it >= other.it; } - inline bool operator < (const iterator & other) const { return it < other.it; } - inline bool operator <= (const iterator & other) const { return it <= other.it; } - inline iterator & operator = (const iterator & orig){ it = orig.it; return *this; } - iterator (const iterator & orig) : it(orig.it) {} - private: - JSONNode ** it; - iterator(JSONNode ** starter) : it(starter) {} - friend class JSONNode; - }; - typedef iterator json_iterator; - - struct const_iterator { - inline const_iterator& operator ++(void){ ++it; return *this; } - inline const_iterator& operator --(void){ --it; return *this; } - inline const_iterator& operator +=(long i){ it += i; return *this; } - inline const_iterator& operator -=(long i){ it -= i; return *this; } - inline const_iterator operator ++(int){ - const_iterator result(*this); - ++it; - return result; - } - inline const_iterator operator --(int){ - const_iterator result(*this); - --it; - return result; - } - inline const_iterator operator +(long i) const { - const_iterator result(*this); - result.it += i; - return result; - } - inline const_iterator operator -(long i) const { - const_iterator result(*this); - result.it -= i; - return result; - } - inline const JSONNode& operator [](size_t pos) const { return const_cast(*it[pos]); }; - inline const JSONNode& operator *(void) const { return const_cast(*(*it)); } - inline bool operator == (const const_iterator & other) const { return it == other.it; } - inline bool operator != (const const_iterator & other) const { return it != other.it; } - inline bool operator > (const const_iterator & other) const { return it > other.it; } - inline bool operator >= (const const_iterator & other) const { return it >= other.it; } - inline bool operator < (const const_iterator & other) const { return it < other.it; } - inline bool operator <= (const const_iterator & other) const { return it <= other.it; } - inline const_iterator & operator = (const const_iterator & orig){ it = orig.it; return *this; } - const_iterator (const const_iterator & orig) : it(orig.it) {} - private: - JSONNode ** it; - const_iterator(JSONNode ** starter) : it(starter) {} - friend class JSONNode; - }; - const_iterator begin(void) const; - const_iterator end(void) const; - - struct reverse_iterator { - inline reverse_iterator& operator ++(void){ --it; return *this; } - inline reverse_iterator& operator --(void){ ++it; return *this; } - inline reverse_iterator& operator +=(long i){ it -= i; return *this; } - inline reverse_iterator& operator -=(long i){ it += i; return *this; } - inline reverse_iterator operator ++(int){ - reverse_iterator result(*this); - --it; - return result; - } - inline reverse_iterator operator --(int){ - reverse_iterator result(*this); - ++it; - return result; - } - inline reverse_iterator operator +(long i) const { - reverse_iterator result(*this); - result.it -= i; - return result; - } - inline reverse_iterator operator -(long i) const { - reverse_iterator result(*this); - result.it += i; - return result; - } - inline JSONNode& operator [](size_t pos) const { return *it[pos]; }; - inline JSONNode& operator *(void) const { return *(*it); } - inline bool operator == (const reverse_iterator & other) const { return it == other.it; } - inline bool operator != (const reverse_iterator & other) const { return it != other.it; } - inline bool operator < (const reverse_iterator & other) const { return it > other.it; } - inline bool operator <= (const reverse_iterator & other) const { return it >= other.it; } - inline bool operator > (const reverse_iterator & other) const { return it < other.it; } - inline bool operator >= (const reverse_iterator & other) const { return it <= other.it; } - inline reverse_iterator & operator = (const reverse_iterator & orig){ it = orig.it; return *this; } - reverse_iterator (const reverse_iterator & orig) : it(orig.it) {} - private: - JSONNode ** it; - reverse_iterator(JSONNode ** starter) : it(starter) {} - friend class JSONNode; - }; - reverse_iterator rbegin(void); - reverse_iterator rend(void); - - struct reverse_const_iterator { - inline reverse_const_iterator& operator ++(void){ --it; return *this; } - inline reverse_const_iterator& operator --(void){ ++it; return *this; } - inline reverse_const_iterator& operator +=(long i){ it -= i; return *this; } - inline reverse_const_iterator& operator -=(long i){ it += i; return *this; } - inline reverse_const_iterator operator ++(int){ - reverse_const_iterator result(*this); - --it; - return result; - } - inline reverse_const_iterator operator --(int){ - reverse_const_iterator result(*this); - ++it; - return result; - } - inline reverse_const_iterator operator +(long i) const { - reverse_const_iterator result(*this); - result.it -= i; - return result; - } - inline reverse_const_iterator operator -(long i) const { - reverse_const_iterator result(*this); - result.it += i; - return result; - } - inline const JSONNode& operator [](size_t pos) const { return const_cast(*it[pos]); }; - inline const JSONNode& operator *(void) const { return const_cast(*(*it)); } - inline bool operator == (const reverse_const_iterator & other) const { return it == other.it; } - inline bool operator != (const reverse_const_iterator & other) const { return it != other.it; } - inline bool operator < (const reverse_const_iterator & other) const { return it > other.it; } - inline bool operator <= (const reverse_const_iterator & other) const { return it >= other.it; } - inline bool operator > (const reverse_const_iterator & other) const { return it < other.it; } - inline bool operator >= (const reverse_const_iterator & other) const { return it <= other.it; } - inline reverse_const_iterator & operator = (const reverse_const_iterator & orig){ it = orig.it; return *this; } - reverse_const_iterator (const reverse_const_iterator & orig) : it(orig.it) {} - private: - JSONNode ** it; - reverse_const_iterator(JSONNode ** starter) : it(starter) {} - friend class JSONNode; - }; - reverse_const_iterator rbegin(void) const; - reverse_const_iterator rend(void) const; - - const_iterator find(const json_string & name_t) const; - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - const_iterator find_nocase(const json_string & name_t) const; - #endif - - reverse_iterator erase(reverse_iterator pos); - reverse_iterator erase(reverse_iterator start, const reverse_iterator & end); - - iterator insert(iterator pos, const JSONNode & x); - reverse_iterator insert(reverse_iterator pos, const JSONNode & x); - iterator insert(iterator pos, const reverse_iterator & _start, const reverse_iterator & _end); - reverse_iterator insert(reverse_iterator pos, const iterator & _start, const iterator & _end); - reverse_iterator insert(reverse_iterator pos, const reverse_iterator & _start, const reverse_iterator & _end); - - json_iterator insert(json_iterator pos, const const_iterator & _start, const const_iterator & _end); - reverse_iterator insert(reverse_iterator pos, const const_iterator & _start, const const_iterator & _end); - json_iterator insert(json_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end); - reverse_iterator insert(reverse_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end); - #else - typedef JSONNode** json_iterator; - #define json_iterator_ptr(iter) iter - #define ptr_to_json_iterator(iter) iter - json_iterator insert(json_iterator pos, JSONNode * x); - #endif - - json_iterator begin(void); - json_iterator end(void); - - json_iterator find(const json_string & name_t); - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - json_iterator find_nocase(const json_string & name_t); - #endif - json_iterator erase(json_iterator pos); - json_iterator erase(json_iterator start, const json_iterator & end); - json_iterator insert(json_iterator pos, const json_iterator & _start, const json_iterator & _end); - #endif - - #ifdef JSON_MUTEX_CALLBACKS - static void register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock); - #ifdef JSON_MUTEX_MANAGE - static void register_mutex_destructor(json_mutex_callback_t destroy); - #endif - static void set_global_mutex(void * mutex); - void set_mutex(void * mutex); - void lock(int thread); - void unlock(int thread); - struct auto_lock { - public: - auto_lock(JSONNode & node, int thread) : mynode(&node), mythread(thread){ - mynode -> lock(mythread); - } - auto_lock(JSONNode *node, int thread) : mynode(node), mythread(thread){ - mynode -> lock(mythread); - } - ~auto_lock(void){ - mynode -> unlock(mythread); - } - private: - auto_lock & operator = (const auto_lock &); - auto_lock(const auto_lock &); - JSONNode * mynode; - int mythread; - }; - static void * getThisLock(JSONNode * pthis); - #endif - - #ifdef JSON_UNIT_TEST - static int getNodeAllocationCount(void); - static int getNodeDeallocationCount(void); - static int getInternalAllocationCount(void); - static int getInternalDeallocationCount(void); - static void incAllocCount(void); - static void decAllocCount(void); - static void incinternalAllocCount(void); - static void decinternalAllocCount(void); - #endif - - #ifdef JSON_WRITER - json_string write(void); - json_string write_formatted(void); - #endif - - #ifdef JSON_DEBUG - #ifndef JSON_LIBRARY - JSONNode dump(void) const; - #endif - #endif - static void deleteJSONNode(JSONNode * ptr); - static JSONNode * newJSONNode_Shallow(const JSONNode & orig); -JSON_PRIVATE - static JSONNode * newJSONNode(const JSONNode & orig JSON_MUTEX_COPY_DECL2); - static JSONNode * newJSONNode(internalJSONNode * internal_t); - //used by JSONWorker - JSONNode(const json_string & unparsed) : internal(internalJSONNode::newInternal(unparsed)) { //root, specialized because it can only be array or node - incAllocCount(); - } - JSONNode(internalJSONNode * internal_t) : internal(internal_t){ //do not increment anything, this is only used in one case and it's already taken care of - incAllocCount(); - } - JSONNode(bool, JSONNode & orig); - - void decRef(void); //decrements internal's counter, deletes it if needed - #ifdef JSON_REF_COUNT - void makeUniqueInternal(void); //makes internal it's own - void merge(JSONNode * other); - #endif - - #ifdef JSON_DEBUG - #ifndef JSON_LIBRARY - JSONNode dump(size_t & totalmemory); - #endif - #endif - - #ifdef JSON_ITERATORS - #ifndef JSON_LIBRARY - json_iterator insertFRR(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end); - reverse_iterator insertRRR(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end); - reverse_iterator insertRFF(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end); - #endif - json_iterator insertFFF(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end); - #endif - - mutable internalJSONNode * internal; - friend class JSONWorker; - friend class internalJSONNode; -}; - -/* - Implementations are here to keep the class declaration cleaner. They can't be placed in a different - file because they are inlined. -*/ -inline JSONNode::JSONNode(char mytype) : internal(internalJSONNode::newInternal(mytype)) { - JSON_ASSERT((mytype == JSON_NULL) || - (mytype == JSON_STRING) || - (mytype == JSON_NUMBER) || - (mytype == JSON_BOOL) || - (mytype == JSON_ARRAY) || - (mytype == JSON_NODE), JSON_TEXT("Not a proper JSON type")); - incAllocCount(); -} -inline JSONNode::JSONNode(const JSONNode & orig): internal(orig.internal -> incRef()) { - incAllocCount(); -} -//this allows a temp node to simply transfer its contents, even with ref counting off -inline JSONNode::JSONNode(bool, JSONNode & orig): internal(orig.internal){ - orig.internal = 0; - incAllocCount(); -} -inline JSONNode::~JSONNode(void){ - if (internal) decRef(); - decAllocCount(); -} -inline json_index_t JSONNode::size(void) const { - JSON_CHECK_INTERNAL(); - return internal -> size(); -} -inline bool JSONNode::empty(void) const { - JSON_CHECK_INTERNAL(); - return internal -> empty(); -} -inline void JSONNode::clear(void){ - JSON_CHECK_INTERNAL(); - if (!empty()) { - makeUniqueInternal(); - internal -> Children.clear(); - } -} -inline unsigned char JSONNode::type(void) const { - JSON_CHECK_INTERNAL(); - return internal -> type(); -} -inline const json_char* JSONNode::name(void) const { - JSON_CHECK_INTERNAL(); - return internal -> name(); -} -inline void JSONNode::set_name(const json_string & newname){ - JSON_CHECK_INTERNAL(); - makeUniqueInternal(); - internal -> setname(newname); -} -#ifdef JSON_COMMENTS - inline void JSONNode::set_comment(const json_string & newname){ - JSON_CHECK_INTERNAL(); - makeUniqueInternal(); - internal -> setcomment(newname); - } - inline json_string JSONNode::get_comment(void) const { - JSON_CHECK_INTERNAL(); - return internal -> getcomment(); - } -#endif -inline json_string JSONNode::as_string(void) const { - JSON_CHECK_INTERNAL(); - return internal -> as_string(); -} -inline long JSONNode::as_int(void) const { - JSON_CHECK_INTERNAL(); - return internal -> as_int(); -} -inline double JSONNode::as_float(void) const { - JSON_CHECK_INTERNAL(); - return internal -> as_float(); -} -inline bool JSONNode::as_bool(void) const { - JSON_CHECK_INTERNAL(); - return internal -> as_bool(); -} -#ifdef JSON_BINARY - inline void JSONNode::set_binary(const unsigned char * bin, json_index_t bytes){ - JSON_CHECK_INTERNAL(); - *this = JSONBase64::json_encode64(bin, bytes); - } - inline std::string JSONNode::as_binary(void) const { - JSON_ASSERT_SAFE(type() == JSON_STRING, JSON_TEXT("using as_binary for a non-string type"), return EMPTY_STRING2;); - JSON_CHECK_INTERNAL(); - return JSONBase64::json_decode64(as_string()); - } -#endif -inline JSONNode & JSONNode::operator[](const json_string & name_t){ - JSON_CHECK_INTERNAL(); - makeUniqueInternal(); - return *(*(internal -> at(name_t))); -} -inline const JSONNode & JSONNode::operator[](const json_string & name_t) const { - JSON_CHECK_INTERNAL(); - return *(*(internal -> at(name_t))); -} -#ifdef JSON_LIBRARY -inline void JSONNode::push_back(JSONNode * child){ -#else -inline void JSONNode::push_back(const JSONNode & child){ -#endif - JSON_CHECK_INTERNAL(); - makeUniqueInternal(); - internal -> push_back(child); -} - -inline void JSONNode::reserve(json_index_t size){ - makeUniqueInternal(); - internal -> reserve(size); -} -inline JSONNode & JSONNode::operator = (const JSONNode & orig){ - JSON_CHECK_INTERNAL(); - #ifdef JSON_REF_COUNT - if (internal == orig.internal) return *this; //don't want it accidentally deleting itself - #endif - decRef(); //dereference my current one - internal = orig.internal -> incRef(); //increase reference of original - return *this; -} -#ifndef JSON_LIBRARY - inline JSONNode & JSONNode::operator = (const json_char * val){ - JSON_CHECK_INTERNAL(); - *this = json_string(val); - return *this; - } -#endif - -#define NODE_SET_TYPED(type)\ - inline JSONNode & JSONNode::operator = (type val){\ - JSON_CHECK_INTERNAL();\ - makeUniqueInternal();\ - internal -> Set(val);\ - return *this;\ - } -IMPLEMENT_FOR_ALL_TYPES(NODE_SET_TYPED) - -/* - This section is the equality operators -*/ -#define NODE_CHECK_EQUALITY(type)\ - inline bool JSONNode::operator == (type val) const {\ - JSON_CHECK_INTERNAL();\ - return internal -> IsEqualToNum(val);\ - } -IMPLEMENT_FOR_ALL_NUMBERS(NODE_CHECK_EQUALITY) -inline bool JSONNode::operator == (const json_string & val) const { - JSON_CHECK_INTERNAL(); - return internal -> IsEqualTo(val); -} -#ifndef JSON_LIBRARY - inline bool JSONNode::operator == (const json_char * val) const { - JSON_CHECK_INTERNAL(); - return *this == json_string(val); - } -#endif -inline bool JSONNode::operator == (bool val) const { - JSON_CHECK_INTERNAL(); - return internal -> IsEqualTo(val); -} -inline bool JSONNode::operator == (const JSONNode & val) const { - JSON_CHECK_INTERNAL(); - return internal -> IsEqualTo(val.internal); -} - -/* - This section is the inequality operators -*/ - -#define NODE_CHECK_INEQUALITY(type)\ - inline bool JSONNode::operator != (type val) const {\ - JSON_CHECK_INTERNAL();\ - return !(*this == val);\ - } -IMPLEMENT_FOR_ALL_TYPES(NODE_CHECK_INEQUALITY) -NODE_CHECK_INEQUALITY(const JSONNode &) -#ifndef JSON_LIBRARY - NODE_CHECK_INEQUALITY(const json_char * ) -#endif - -inline void JSONNode::nullify(void){ - JSON_CHECK_INTERNAL(); - makeUniqueInternal(); - internal -> Nullify(); -} -inline void JSONNode::swap(JSONNode & other){ - JSON_CHECK_INTERNAL(); - internalJSONNode * temp = other.internal; - other.internal = internal; - internal = temp; - JSON_CHECK_INTERNAL(); -} -inline void JSONNode::decRef(void){ //decrements internal's counter, deletes it if needed - JSON_CHECK_INTERNAL(); - #ifdef JSON_REF_COUNT - internal -> decRef(); - if (internal -> hasNoReferences()) { - internalJSONNode::deleteInternal(internal); - } - #else - internalJSONNode::deleteInternal(internal); - #endif -} -#ifdef JSON_REF_COUNT - inline void JSONNode::makeUniqueInternal() { //makes internal it's own - JSON_CHECK_INTERNAL(); - internal = internal -> makeUnique(); //might return itself or a new one that's exactly the same - } -#endif -#ifdef JSON_ITERATORS - inline JSONNode::json_iterator JSONNode::begin(void){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); - makeUniqueInternal(); - return json_iterator(internal -> begin()); - } - inline JSONNode::json_iterator JSONNode::end(void){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); - makeUniqueInternal(); - return json_iterator(internal -> end()); - } - - #ifndef JSON_LIBRARY - inline JSONNode::const_iterator JSONNode::begin(void) const { - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); - return JSONNode::const_iterator(internal -> begin()); - } - inline JSONNode::const_iterator JSONNode::end(void) const { - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); - return JSONNode::const_iterator(internal -> end()); - } - inline JSONNode::reverse_iterator JSONNode::rbegin(void){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); - makeUniqueInternal(); - return JSONNode::reverse_iterator(internal -> end() - 1); - } - inline JSONNode::reverse_iterator JSONNode::rend(void){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); - makeUniqueInternal(); - return JSONNode::reverse_iterator(internal -> begin() - 1); - } - inline JSONNode::reverse_const_iterator JSONNode::rbegin(void) const { - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); - return JSONNode::reverse_const_iterator(internal -> end() - 1); - } - inline JSONNode::reverse_const_iterator JSONNode::rend(void) const { - JSON_CHECK_INTERNAL(); - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); - return JSONNode::reverse_const_iterator(internal -> begin() - 1); - } - - inline JSONNode::iterator JSONNode::insert(json_iterator pos, const const_iterator & _start, const const_iterator & _end){ - return insertFFF(pos, _start.it, _end.it); - } - - inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const const_iterator & _start, const const_iterator & _end){ - return insertRFF(pos, _start.it, _end.it); - } - - inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const iterator & _start, const iterator & _end){ - return insertRFF(pos, _start.it, _end.it); - } - - inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end){ - return insertRRR(pos, _start.it, _end.it); - } - - inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const reverse_iterator & _start, const reverse_iterator & _end){ - return insertRRR(pos, _start.it, _end.it); - } - - inline JSONNode::iterator JSONNode::insert(json_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end){ - return insertFRR(pos, _start.it, _end.it); - } - - inline JSONNode::iterator JSONNode::insert(iterator pos, const reverse_iterator & _start, const reverse_iterator & _end){ - return insertFRR(pos, _start.it, _end.it); - } - #endif - - inline JSONNode::json_iterator JSONNode::insert(json_iterator pos, const json_iterator & _start, const json_iterator & _end){ - return insertFFF(pos, json_iterator_ptr(_start), json_iterator_ptr(_end)); - } -#endif -#ifdef JSON_WRITER - inline json_string JSONNode::write(void){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Writing a non-writable node"), return JSON_TEXT("");); - return internal -> Write(0xFFFFFFFF, true); - } - inline json_string JSONNode::write_formatted(void){ - JSON_CHECK_INTERNAL(); - JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Writing a non-writable node"), return JSON_TEXT("");); - return internal -> Write(0, true); - } -#endif -#ifndef JSON_PREPARSE - inline void JSONNode::preparse(void){ - JSON_CHECK_INTERNAL(); - internal -> preparse(); - } -#endif -#ifdef JSON_VALIDATE - inline bool JSONNode::validate(void){ - JSON_CHECK_INTERNAL(); - if (type() == JSON_NULL) return false; - JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Validating non root node"), return false;); - #ifndef JSON_PREPARSE - internal -> Fetch(); //will nullify it if it's bad - #endif - if (type() == JSON_NULL) return false; - return internal -> validate(); - } -#endif -#ifdef JSON_DEBUG - #ifndef JSON_LIBRARY - inline JSONNode JSONNode::dump(void) const { - JSON_CHECK_INTERNAL(); - JSONNode dumpage(JSON_NODE); - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); - size_t total = 0; - JSONNode node = internal -> Dump(total); - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("total bytes used"), total))); - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), sizeof(JSONNode)))); - dumpage.push_back(JSON_NEW(node)); - return dumpage; - } - inline JSONNode JSONNode::dump(size_t & totalmemory){ - JSON_CHECK_INTERNAL(); - JSONNode dumpage(JSON_NODE); - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), sizeof(JSONNode)))); - dumpage.push_back(JSON_NEW(internal -> Dump(totalmemory))); - return dumpage; - } - #endif -#endif - -inline void JSONNode::deleteJSONNode(JSONNode * ptr){ - #ifdef JSON_MEMORY_CALLBACKS - ptr -> ~JSONNode(); - libjson_free(ptr); - #else - delete ptr; - #endif -} -inline JSONNode * _newJSONNode(const JSONNode & orig){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) JSONNode(orig); - #else - return new JSONNode(orig); - #endif -} -inline JSONNode * JSONNode::newJSONNode(const JSONNode & orig JSON_MUTEX_COPY_DECL){ - #ifdef JSON_MUTEX_CALLBACKS - if (parentMutex){ - JSONNode * temp = _newJSONNode(orig); - temp -> set_mutex(parentMutex); - return temp; - } - #endif - return _newJSONNode(orig); -} -inline JSONNode * JSONNode::newJSONNode(internalJSONNode * internal_t){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) JSONNode(internal_t); - #else - return new JSONNode(internal_t); - #endif -} - -inline JSONNode * JSONNode::newJSONNode_Shallow(const JSONNode & orig){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) JSONNode(true, const_cast(orig)); - #else - return new JSONNode(true, const_cast(orig)); - #endif -} -#endif diff --git a/src/mir_core/json/JSONNode_Mutex.cpp b/src/mir_core/json/JSONNode_Mutex.cpp deleted file mode 100644 index 497e867f62..0000000000 --- a/src/mir_core/json/JSONNode_Mutex.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" -#include - -#ifdef JSON_MUTEX_CALLBACKS - -json_mutex_callback_t json_lock_callback = 0; -json_mutex_callback_t json_unlock_callback = 0; -void * global_mutex = 0; -void * manager_mutex = 0; - -struct AutoLock { - AutoLock(void){ - json_lock_callback(manager_mutex); - } - ~AutoLock(void){ - json_unlock_callback(manager_mutex); - } -}; - -#include -#ifdef JSON_MUTEX_MANAGE - json_mutex_callback_t json_destroy = 0; - std::map mutex_manager; - - //make sure that the global mutex is taken care of too - struct auto_global { - auto_global(void){} - ~auto_global(void){ - if (global_mutex){ - JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("No json_destroy in mutex managed mode"), return;); - json_destroy(global_mutex); - } - } - }; - auto_global cleanupGlobal; -#endif - -void JSONNode::register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock){ - json_lock_callback = lock; - json_unlock_callback = unlock; - manager_mutex = manager_lock; -} - -void JSONNode::set_global_mutex(void * mutex){ - global_mutex = mutex; -} - -void JSONNode::set_mutex(void * mutex){ - makeUniqueInternal(); - internal -> _set_mutex(mutex); -} - -std::map > threadlocks; - -void * JSONNode::getThisLock(JSONNode * pthis){ - if (pthis -> internal -> mylock){ - return pthis -> internal -> mylock; - } - JSON_ASSERT_SAFE(global_mutex, JSON_TEXT("No global_mutex"), return 0;); - return global_mutex; -} - -void JSONNode::lock(int thread){ - JSON_ASSERT_SAFE(json_lock_callback, JSON_TEXT("No locking callback"), return;); - - AutoLock lockControl; - - //first, figure out what needs to be locked - void * thislock = getThisLock(this); - #ifdef JSON_SAFE - if (!thislock) return; - #endif - - //make sure that the same thread isn't locking it more than once (possible due to complex ref counting) - std::map >::iterator it = threadlocks.find(thread); - if (it == threadlocks.end()) { - std::map newthread; - newthread[thislock] = 1; - threadlocks.insert(std::pair >(thread, newthread)); - } else { //this thread already has some things locked, check if the current mutex is - std::map & newthread = it -> second; - std::map::iterator locker = newthread.find(thislock); - if (locker == newthread.end()) { //current mutex is not locked, set it to locked - newthread.insert(std::pair(thislock, 1)); - } else { //it's already locked, don't relock it - ++(locker -> second); - return; //don't try to relock, it will deadlock the program - } - } - - //if I need to, lock it - json_lock_callback(thislock); -} - -void JSONNode::unlock(int thread){ - JSON_ASSERT_SAFE(json_unlock_callback, JSON_TEXT("No unlocking callback"), return;); - - AutoLock lockControl; - - //first, figure out what needs to be locked - void * thislock = getThisLock(this); - #ifdef JSON_SAFE - if (!thislock) return; - #endif - - //get it out of the map - std::map >::iterator it = threadlocks.find(thread); - JSON_ASSERT_SAFE(it != threadlocks.end(), JSON_TEXT("thread unlocking something it didn't lock"), return;); - - //get the mutex out of the thread - std::map & newthread = it -> second; - std::map::iterator locker = newthread.find(thislock); - JSON_ASSERT_SAFE(locker != newthread.end(), JSON_TEXT("thread unlocking mutex it didn't lock"), return;); - - //unlock it - if (--(locker -> second)) return; //other nodes is this same thread still have a lock on it - - //if I need to, unlock it - newthread.erase(locker); - json_unlock_callback(thislock); -} - -#ifdef JSON_MUTEX_MANAGE - void JSONNode::register_mutex_destructor(json_mutex_callback_t destroy){ - json_destroy = destroy; - } -#endif - -void internalJSONNode::_set_mutex(void * mutex, bool unset){ - if (unset) _unset_mutex(); //for reference counting - mylock = mutex; - if (mutex){ - #ifdef JSON_MUTEX_MANAGE - std::map::iterator it = mutex_manager.find(mutex); - if (it == mutex_manager.end()) { - mutex_manager.insert(std::pair(mutex, 1)); - } else { - ++it -> second; - } - #endif - json_foreach(Children, myrunner){ - (*myrunner) -> set_mutex(mutex); - } - } -} - -void internalJSONNode::_unset_mutex(void){ - #ifdef JSON_MUTEX_MANAGE - if (mylock){ - std::map::iterator it = mutex_manager.find(mylock); - JSON_ASSERT_SAFE(it != mutex_manager.end(), JSON_TEXT("Mutex not managed"), return;); - --it -> second; - if (it -> second == 0){ - JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("You didn't register a destructor for mutexes"), return;); - mutex_manager.erase(it); - } - } - #endif -} - -#ifdef JSON_DEBUG - #ifndef JSON_LIBRARY - JSONNode internalJSONNode::DumpMutex(void) const { - JSONNode mut(JSON_NODE); - mut.set_name(JSON_TEXT("mylock")); - #ifdef JSON_MUTEX_MANAGE - if (mylock){ - mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)mylock))); - std::map::iterator it = mutex_manager.find(mylock); - if (it == mutex_manager.end()) { - mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), JSON_TEXT("error")))); - } else { - mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), it -> second))); - } - } else { - mut = (long)mylock; - } - #else - mut = (long)mylock; - #endif - return mut; - } - #endif -#endif - -#else - #ifdef JSON_MUTEX_MANAGE - #error You can not have JSON_MUTEX_MANAGE on without JSON_MUTEX_CALLBACKS - #endif -#endif diff --git a/src/mir_core/json/JSONOptions.h b/src/mir_core/json/JSONOptions.h deleted file mode 100644 index d4bd343677..0000000000 --- a/src/mir_core/json/JSONOptions.h +++ /dev/null @@ -1,188 +0,0 @@ -#ifndef JSON_OPTIONS_H -#define JSON_OPTIONS_H - -/** - * This file holds all of the compiling options for easy access and so - * that you don't have to remember them, or look them up all the time - */ - -/* - * JSON_LIBRARY must be declared if libjson is compiled as a static or dynamic - * library. This exposes a C-style interface, but none of the inner workings of libjson - */ -#define JSON_LIBRARY - -/* - * JSON_DEBUG is used to perform extra error checking. Because libjson usually - * does on the fly parsing, validation is impossible, so this option will allow - * you to register an error callback so that you can record what is going wrong - * before the library crashes. This option does not protect from these errors, - * it simply tells you about them, which is nice for debugging, but not preferable - * for release candidates - */ -//#define JSON_DEBUG - -/* - * JSON_SAFE performs similarly to JSON_DEBUG, except this option does protect - * from the errors that it encounters. This option is recommended for those who - * feel it's possible for their program to encounter invalid json. - */ -#define JSON_SAFE - -/* - * JSON_STDERROR routes error messages to cerr instead of a callback, this - * option hides the callback registering function. This will usually display - * messages in the console - */ -//#define JSON_STDERROR - -/* - * JSON_PREPARSE causes all parsing to be done immediately. By default, libjson - * parses nodes on the fly as they are needed, this makes parsing much faster if - * your program gets a lot of information that it doesn't need. An example of - * this would be a client application communicating with a server if the server - * returns things like last modified date and other things that you don't use. - */ -//#define JSON_PREPARSE - -/* - * JSON_LESS_MEMORY will force libjson to let go of memory as quickly as it can - * this is recommended for software that has to run on less than optimal machines. - * It will cut libjson's memory usage by about 20%, but also run slightly slower. - * It's recommended that you also compile using the -Os option, as this will also - * reduce the size of the library - */ -//#define JSON_LESS_MEMORY - -/* - * JSON_UNICODE tells libjson to use wstrings instead of regular strings, this - * means that libjson supports the full array of unicode characters, but also takes - * much more memory and processing power. - */ -//#define JSON_UNICODE - -/* - * JSON_REF_COUNT causes libjson to reference count JSONNodes, which makes copying - * and passing them around much faster. It is recommended that this stay on for - * most uses - */ -#define JSON_REF_COUNT - -/* - * JSON_BINARY is used to support binary, which is base64 encoded and decoded by libjson, - * if this option is not turned on, no base64 support is included - */ -//#define JSON_BINARY - -/* - * JSON_MEMORY_CALLBACKS exposes functions to register callbacks for allocating, resizing, - * and freeing memory. Because libjson is designed for costomizability, it is feasible - * that some users would like to further add speed by having the library utilize a memory - * pool. With this option turned on, the default behavior is still done internally unless - * a callback is registered. So you can have this option on and mot use it. - */ -#define JSON_MEMORY_CALLBACKS - -/* - * JSON_MEMORY_MANAGE is used to create functionality to automatically track and clean - * up memory that has been allocated by the user. This includes strings, binary data, and - * nodes. It also exposes bulk delete functions. - */ -//#define JSON_MEMORY_MANAGE - -/* - * JSON_MUTEX_CALLBACKS exposes functions to register callbacks to lock and unlock - * mutexs and functions to lock and unlock JSONNodes and all of it's children. This - * does not prevent other threads from accessing the node, but will prevent them from - * locking it. It is much easier for the end programmer to allow libjson to manage - * your mutexs because of reference counting and manipulating trees, libjson automatically - * tracks mutex controls for you, so you only ever lock what you need to - */ -//#define JSON_MUTEX_CALLBACKS - -/* - * JSON_MUTEX_MANAGE lets you set mutexes and forget them, libjson will not only keep - * track of the mutex, but also keep a count of how many nodes are using it, and delete - * it when there are no more references - */ -//#define JSON_MUTEX_MANAGE - -/* - * JSON_ISO_STRICT turns off all code that uses non-standard C++. This removes all - * references to long long and long double as well as a few others - */ -//#define JSON_ISO_STRICT - -/* - * JSON_ITERATORS turns on all of libjson's iterating functionality. This would usually - * only be turned off while compiling for use with C - */ -//#define JSON_ITERATORS - -/* - * JSON_WRITER turns on libjson's writing capabilties. Without this libjson can only - * read and parse json, this allows it to write back out - */ -#define JSON_WRITER - -/* - * JSON_NEWLINE affects how libjson writes. If this option is turned on, libjson - * will use whatever it's defined as for the newline signifier, otherwise, it will use - * standard unix \n. - */ -//#define JSON_NEWLINE "\r\n" //\r\n is standard for most windows and dos programs - -/* - * JSON_COMMENTS tells libjson to store and write comments. libjson always supports - * parsing json that has comments in it as it simply ignores them, but with this option - * it keeps the comments and allows you to insert further comments - */ -//#define JSON_COMMENTS - -/* - * JSON_INDENT affects how libjson writes. If this option is turned on, libjson - * will use \t to indent formatted json, otherwise it will use the number of characters - * that you specify. If this is not turned on, then it will use the tab (\t) character - */ -//#define JSON_INDENT " " - -/* - * JSON_WRITE_BASH_COMMENTS will cause libjson to write all comments in bash (#) style - * if this option is not turned on, then it will use C-style comments. Bash comments are - * all single line - */ -//#define JSON_WRITE_BASH_COMMENTS - -/* - * JSON_WRITE_SINGLE_LINE_COMMENTS will cause libjson to write all comments in using // - * notation, or (#) if that option is on. Some parsers do not support multiline C comments - * although, this option is not needed for bash comments, as they are all single line anyway - */ -//#define JSON_WRITE_SINGLE_LINE_COMMENTS - -/* - * JSON_VALIDATE turns on validation features of libjson. This option requires JSON_SAFE - */ -//#define JSON_VALIDATE - -/* - * JSON_CASE_INSENSITIVE_FUNCTIONS turns on funtions for finding child nodes in a case- - * insenititve way - */ -//#define JSON_CASE_INSENSITIVE_FUNCTIONS - -/* - * JSON_UNIT_TEST is used to maintain and debug the libjson. It makes all private - * members and functions public so that tests can do checks of the inner workings - * of libjson. This should not be turned on by end users. - */ -//#define JSON_UNIT_TEST - -/* - * JSON_INDEX_TYPE allows you th change the size type for the children functions. If this - * option is not used then unsigned int is used. This option is useful for cutting down - * on memory, or using huge numbers of child nodes (over 4 billion) - */ -//#define JSON_INDEX_TYPE unsigned int - -#endif diff --git a/src/mir_core/json/JSONWorker.cpp b/src/mir_core/json/JSONWorker.cpp deleted file mode 100644 index cf8254a357..0000000000 --- a/src/mir_core/json/JSONWorker.cpp +++ /dev/null @@ -1,698 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" - -#include "JSONWorker.h" - -#ifdef JSON_VALIDATE -JSONNode JSONWorker::validate(const json_string & json){ - JSONNode res = parse(json); - if (!res.validate()) { - throw std::invalid_argument(EMPTY_STRING2); - } - return JSONNode(true, res); //forces it to simply return the original interal, even with ref counting off -} -#endif - -JSONNode JSONWorker::parse(const json_string & json){ - json_auto s; - #if defined JSON_DEBUG || defined JSON_SAFE - json_char lastchar; - s.set(RemoveWhiteSpace(json, lastchar)); - #else - s.set(RemoveWhiteSpace(json)); - #endif - - #ifdef JSON_COMMENTS - json_char firstchar = s.ptr[0]; - json_string _comment; - json_char * runner = s.ptr; - if (firstchar == '\5') { //multiple comments will be consolidated into one - newcomment: - while(*(++runner) != '\5') { - JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed")); - _comment += *runner; - } - firstchar = *(++runner); //step past the trailing tag - if (firstchar == '\5') { - _comment += '\n'; - goto newcomment; - } - } - #else - const json_char firstchar = s.ptr[0]; - #endif - - switch (firstchar){ - case '{': - case '[': - #if defined JSON_DEBUG || defined JSON_SAFE - if (firstchar == '[') { - if (lastchar != ']') { - JSON_FAIL(JSON_TEXT("Missing final ]")); - break; - } - } else { - if (lastchar != '}') { - JSON_FAIL(JSON_TEXT("Missing final }")); - break; - } - } - #endif - #ifdef JSON_COMMENTS - JSONNode foo(runner); - foo.set_comment(_comment); - return JSONNode(true, foo); //forces it to simply return the original interal, even with ref counting off - #else - return JSONNode(s.ptr); - #endif - } - - JSON_FAIL(JSON_TEXT("Not JSON!")); - throw std::invalid_argument(EMPTY_STRING2); -} - -#define QUOTECASE()\ - case JSON_TEXT('\"'):\ - while (*(++p) != JSON_TEXT('\"')) {\ - JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), return json_string::npos;);\ - }\ - break; - -#ifdef JSON_DEBUG - #define NULLCASE(error)\ - case JSON_TEXT('\0'):\ - JSON_FAIL_SAFE(error, return json_string::npos;);\ - break; -#else - #define NULLCASE(error) -#endif - -#define BRACKET(left, right)\ - case left: {\ - size_t brac = 1;\ - while (brac){\ - switch (*(++p)) {\ - case right:\ - --brac;\ - break;\ - case left:\ - ++brac;\ - break;\ - QUOTECASE()\ - NULLCASE(JSON_TEXT("Null terminator inside of a bracket"))\ - }\ - }\ - break;}\ - case right:\ - return json_string::npos; - -size_t JSONWorker::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos){ - const json_char * start = value_t.c_str(); - const json_char * p = start + pos; //start at the correct offset - do { - if (*p == ch) return p - start; - switch (*p){ - BRACKET(JSON_TEXT('['), JSON_TEXT(']')) - BRACKET(JSON_TEXT('{'), JSON_TEXT('}')) - QUOTECASE() - } - } while(*(++p)); - return json_string::npos; -} - -#ifdef JSON_COMMENTS - #define COMMENT_DELIMITER() *runner++='\5' - #define AND_RUNNER ,runner - inline void SingleLineComment(const json_char * & p, json_char * & runner){ - COMMENT_DELIMITER(); - while((*(++p)) && (*p != JSON_TEXT('\n'))) { - *runner++=*p; - } - COMMENT_DELIMITER(); - } -#else - #define COMMENT_DELIMITER() (void)0 - #define AND_RUNNER -#endif - -inline void SingleLineComment(const json_char * & p){ - while((*(++p)) && (*p != JSON_TEXT('\n'))); -} - -#if defined JSON_DEBUG || defined JSON_SAFE - json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t, json_char & last){ -#else - json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t){ -#endif - json_char * result; - json_char * runner = result = json_malloc(value_t.length() + 1); //dealing with raw memory is faster than adding to a json_string - JSON_ASSERT(result, JSON_TEXT("Out of memory")); - const json_char * p = value_t.c_str(); - while(*p){ - switch(*p){ - case JSON_TEXT(' '): //defined as white space - case JSON_TEXT('\t'): //defined as white space - case JSON_TEXT('\n'): //defined as white space - case JSON_TEXT('\r'): //defined as white space - break; - case JSON_TEXT('/'): //a C comment - if (*(++p) == JSON_TEXT('*')) { //a multiline comment - COMMENT_DELIMITER(); - while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))) { - JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), COMMENT_DELIMITER(); goto endofloop;); - *runner++=*p; - } - ++p; - COMMENT_DELIMITER(); - break; - } - //Should be a single line C comment, so let it fall through to use the bash comment stripper - JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;); - case JSON_TEXT('#'): //a bash comment - SingleLineComment(p AND_RUNNER); - break; - case JSON_TEXT('\"'): //a quote - *runner++=JSON_TEXT('\"'); - while(*(++p) != JSON_TEXT('\"')) { //find the end of the quotation, as white space is preserved within it - JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), goto endofloop;); - switch(*p){ - case JSON_TEXT('\\'): - *runner++=JSON_TEXT('\\'); - *runner++=(*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p; //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on - break; - default: - *runner++=*p; - break; - } - } - //no break, let it fall through so that the trailing quote gets added - default: - JSON_ASSERT_SAFE((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); - JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;); - *runner++=*p; - break; - } - ++p; - } - #ifdef JSON_SAFE - endofloop: - #endif - #if defined JSON_DEBUG || defined JSON_SAFE - last = *(runner - 1); - #endif - *runner = JSON_TEXT('\0'); - return result; - } - -json_string JSONWorker::RemoveWhiteSpaceAndComments(const json_string & value_t){ - json_string result; - result.reserve(value_t.length()); - const json_char * p = value_t.c_str(); - while(*p){ - switch(*p){ - case JSON_TEXT(' '): //defined as white space - case JSON_TEXT('\t'): //defined as white space - case JSON_TEXT('\n'): //defined as white space - case JSON_TEXT('\r'): //defined as white space - break; - case JSON_TEXT('/'): //a C comment - if (*(++p) == JSON_TEXT('*')) { //a multiline comment - while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))) { - JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), goto endofloop;); - } - ++p; - break; - } - //Should be a single line C comment, so let it fall through to use the bash comment stripper - JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;); - case JSON_TEXT('#'): //a bash comment - SingleLineComment(p); - break; - case JSON_TEXT('\"'): //a quote - result += JSON_TEXT('\"'); - while(*(++p) != JSON_TEXT('\"')) { //find the end of the quotation, as white space is preserved within it - JSON_ASSERT(*p, JSON_TEXT("Null terminator inside of a quotation")); - switch(*p){ - case JSON_TEXT('\\'): - result += JSON_TEXT('\\'); - result += (*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p; //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on - break; - default: - result += *p; - break; - } - } - //no break, let it fall through so that the trailing quote gets added - default: - JSON_ASSERT_SAFE((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); - JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;); - result += *p; - break; - } - ++p; - } - #ifdef JSON_SAFE - endofloop: - #endif - return result; -} - -/* - These three functions analyze json_string literals and convert them into std::strings - This includes dealing with special characters and utf characters - */ -#ifdef JSON_UNICODE - inline json_uchar SurrogatePair(const json_uchar hi, const json_uchar lo){ - JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit")); - JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("size of json_char is not 32-bit")); - return (((hi << 10) & 0x1FFC00) + 0x10000) | lo & 0x3FF; - } - - json_string JSONWorker::UTF(const json_char * & pos){ - json_string result; - json_uchar first = UTF8(pos); - if ((*(pos + 1) == '\\') && (*(pos + 2) == 'u')) { - pos += 2; - json_uchar second = UTF8(pos); - //surrogate pair, not two characters - if ((first > 0xD800) && (first < 0xDBFF) && (second > 0xDC00) && (second < 0xDFFF)) { - result += SurrogatePair(first, second); - } else { - result += first; - result += second; - } - } else { - result += first; - } - JSON_ASSERT(!result.empty(), JSON_TEXT("missing case, somehow UTF returned empty")); - return result; - } -#endif - -json_uchar JSONWorker::UTF8(const json_char * & pos){ - #ifdef JSON_UNICODE - ++pos; - json_uchar temp = Hex(pos) << 8; - ++pos; - return temp | Hex(pos); - #else - JSON_ASSERT(*(pos + 1) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hihi)")); - JSON_ASSERT(*(pos + 2) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hilo)")); - pos += 3; - return Hex(pos); - #endif -} - -static json_char szU8Buffer[10]; - -json_char* JSONWorker::UTF8_2(const json_char * & pos){ - #ifdef JSON_UNICODE - ++pos; - json_uchar temp = Hex(pos) << 8; - ++pos; - *szU8Buffer = temp | Hex(pos); - szU8Buffer[1] = 0; - return szU8Buffer; - #else - union { - unsigned short uChar; - unsigned char uByte[2]; - }; - pos++; - strncpy(szU8Buffer+5,pos,4); - szU8Buffer[9] = 0; - uChar = strtoul(szU8Buffer+5,NULL,16); - if (uChar<0x80) { - szU8Buffer[0] = uChar; - szU8Buffer[1] = 0; - } else if (uChar<0x7ff) { - szU8Buffer[0] = 0xc0+(uByte[1]<<2)+(uByte[0]>>6); - szU8Buffer[1] = 0x80+(uByte[0]&0x3f); - szU8Buffer[2] = 0; - } else { - szU8Buffer[0] = 0xe0+(uByte[1]>>4); - szU8Buffer[1] = 0x80+((uByte[1]&0x0f)<<2)+(uByte[0]>>6); - szU8Buffer[2] = 0x80+(uByte[0]&0x3f); - szU8Buffer[3] = 0; - } - - pos += 3; - return szU8Buffer; - #endif -} - -json_char JSONWorker::Hex(const json_char * & pos){ - /* - takes the numeric value of the next two characters and convert them - \u0058 becomes 0x58 - - In case of \u, it's SpecialChar's responsibility to move past the first two chars - as this method is also used for \x - */ - //First character - json_uchar hi = *pos++ - 48; - if (hi > 48){ //A-F don't immediately follow 0-9, so have to pull them down a little - hi -= 39; - } else if (hi > 9){ //neither do a-f - hi -= 7; - } - //second character - json_uchar lo = *pos - 48; - if (lo > 48){ //A-F don't immediately follow 0-9, so have to pull them down a little - lo -= 39; - } else if (lo > 9){ //neither do a-f - lo -= 7; - } - //combine them - return (json_char)((hi << 4) | lo); -} - -inline json_char FromOctal(const json_char * & str){ - JSON_ASSERT(json_strlen(str) > 3, JSON_TEXT("Octal will go out of bounds")); - const json_uchar top = ((json_uchar)(*(str++) - 48)); - const json_uchar middle = (json_uchar)(*(str++) - 48); - const json_uchar bottom = (json_uchar)(*str - 48); - return (json_char)((top << 6) | (middle << 3) | bottom); -} - -void JSONWorker::SpecialChar(const json_char * & pos, json_string & res){ - /* - Since JSON uses forward slash escaping for special characters within strings, I have to - convert these escaped characters into C characters - */ - switch(*pos){ - case JSON_TEXT('\1'): //quote character (altered by RemoveWhiteSpace) - res += JSON_TEXT('\"'); - break; - case JSON_TEXT('t'): //tab character - res += JSON_TEXT('\t'); - break; - case JSON_TEXT('n'): //newline character - res += JSON_TEXT('\n'); - break; - case JSON_TEXT('r'): //return character - res += JSON_TEXT('\r'); - break; - case JSON_TEXT('\\'): //backslash - res += JSON_TEXT('\\'); - break; - case JSON_TEXT('/'): //forward slash - res += JSON_TEXT('/'); - break; - case JSON_TEXT('b'): //backspace - res += JSON_TEXT('\b'); - break; - case JSON_TEXT('f'): //formfeed - res += JSON_TEXT('\f'); - break; - case JSON_TEXT('v'): //vertical tab - res += JSON_TEXT('\v'); - break; - case JSON_TEXT('\''): //apostrophe - res += JSON_TEXT('\''); - break; - case JSON_TEXT('x'): //hexidecimal ascii code - res += Hex(++pos); - break; - case JSON_TEXT('u'): //utf character - #ifdef JSON_UNICODE - res += UTF(pos); - #else - //res += UTF8(pos); - res.append(UTF8_2(pos)); - #endif - break; - - //octal encoding - case JSON_TEXT('1'): - case JSON_TEXT('2'): - case JSON_TEXT('3'): - case JSON_TEXT('4'): - case JSON_TEXT('5'): - case JSON_TEXT('6'): - case JSON_TEXT('7'): - case JSON_TEXT('0'): - res += FromOctal(pos); - break; - - #ifdef JSON_DEBUG - default: - JSON_FAIL(JSON_TEXT("Unsupported escaped character")); - #endif - } -} - -#ifdef JSON_LESS_MEMORY - inline void doflag(const internalJSONNode * flag, bool which, bool x){ - if (which){ - flag -> _name_encoded = x; - } else { - flag -> _string_encoded = x; - } - } - - json_string JSONWorker::FixString(const json_string & value_t, const internalJSONNode * flag, bool which){ - #define setflag(x) doflag(flag, which, x) -#else - json_string JSONWorker::FixString(const json_string & value_t, bool & flag){ - #define setflag(x) flag = x -#endif - /* - Do things like unescaping - */ - setflag(false); - json_string res; - res.reserve(value_t.length()); //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating - const json_char * p = value_t.c_str(); - while(*p){ - switch (*p){ - case JSON_TEXT('\\'): - setflag(true); - SpecialChar(++p, res); - break; - default: - res += *p; - break; - } - ++p; - } - return res; -} - -#ifdef JSON_UNICODE - json_string JSONWorker::toSurrogatePair(json_uchar C){ - JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit")); - JSON_ASSERT(sizeof(unsigned short) == 2, JSON_TEXT("size of unsigned short is not 16-bit")); - JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("json_char is not 32-bit")); - //Compute the high surrogate - const unsigned int U = (C >> 16) & 31; - unsigned short HiSurrogate = 0xD800 | (((unsigned short)U - 1) << 6) | ((unsigned short)C) >> 10; - - //compute the low surrogate - unsigned short LoSurrogate = (unsigned short) (0xDC00 | ((unsigned short)C) & 1023); - - json_string res; - res += toUTF8(HiSurrogate); - res += toUTF8(LoSurrogate); - return res; - } -#endif - -json_string JSONWorker::toUTF8(json_uchar p){ - #ifdef JSON_UNICODE - if (p > 0xFFFF) return toSurrogatePair(p); - #endif - json_string res(JSON_TEXT("\\u")); - #ifdef JSON_UNICODE - json_uchar hihi = ((p & 0xF000) >> 12) + 48; - if (hihi > 57) hihi += 7; //A-F don't immediately follow 0-9, so have to further adjust those - json_uchar hilo = ((p & 0x0F00) >> 8) + 48; - if (hilo > 57) hilo += 7; //A-F don't immediately follow 0-9, so have to further adjust those - res += hihi; - res += hilo; - json_uchar hi = ((p & 0x00F0) >> 4) + 48; - #else - res += JSON_TEXT("00"); - json_uchar hi = (p >> 4) + 48; - #endif - //convert the character to be escaped into two digits between 0 and 15 - if (hi > 57) hi += 7; //A-F don't immediately follow 0-9, so have to further adjust those - json_uchar lo = (p & 0x000F) + 48; - if (lo > 57) lo += 7; //A-F don't immediately follow 0-9, so have to further adjust those - res += hi; - res += lo; - return res; -} - -json_string JSONWorker::UnfixString(const json_string & value_t, bool flag){ - if (!flag) return value_t; - /* - Re-escapes a json_string so that it can be written out into a JSON file - */ - json_string res; - res.reserve(value_t.length()); //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating - const json_char * p = value_t.c_str(); - while(*p){ - switch(*p){ - case JSON_TEXT('\"'): //quote character - res += JSON_TEXT("\\\""); - break; - case JSON_TEXT('\t'): //tab character - res += JSON_TEXT("\\t"); - break; - case JSON_TEXT('\n'): //newline character - res += JSON_TEXT("\\n"); - break; - case JSON_TEXT('\r'): //return character - res += JSON_TEXT("\\r"); - break; - case JSON_TEXT('\\'): //backslash - res += JSON_TEXT("\\\\"); - break; - case JSON_TEXT('/'): //forward slash - res += JSON_TEXT("\\/"); - break; - case JSON_TEXT('\b'): //backspace - res += JSON_TEXT("\\b"); - break; - case JSON_TEXT('\f'): //formfeed - res += JSON_TEXT("\\f"); - break; - case JSON_TEXT('\v'): //vertical tab - res += JSON_TEXT("\\v"); - break; - case JSON_TEXT('\''): //apostrophe - res += JSON_TEXT("\\\'"); - break; - default: - /*if (((json_uchar)(*p) < 32) || ((json_uchar)(*p) > 126)) { - //res += toUTF8((json_uchar)(*p)); - } else*/ { - res += *p; - } - break; - } - ++p; - } - return res; -} - -//Create a childnode -#ifdef JSON_COMMENTS - #define ARRAY_PARAM bool array //Just to supress warnings -#else - #define ARRAY_PARAM bool -#endif -inline void JSONWorker::NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, ARRAY_PARAM){ - #ifdef JSON_COMMENTS - const json_char * runner = (array) ? value.c_str() : name.c_str(); - json_string _comment; - if (*runner == '\5') { //multiple comments will be consolidated into one - newcomment: - while(*(++runner) != '\5') { - JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed")); - _comment += *runner; - } - if (*(++runner) == '\5') { //step past the trailing tag - _comment += '\n'; - goto newcomment; - } - } - internalJSONNode * myinternal; - if (array){ - myinternal = internalJSONNode::newInternal(name, runner); - } else { - myinternal = internalJSONNode::newInternal(++runner, value); - } - JSONNode * child = JSONNode::newJSONNode(myinternal); - child -> set_comment(_comment); - const_cast(parent) -> Children.push_back(child); //attach it to the parent node - #else - const_cast(parent) -> Children.push_back(JSONNode::newJSONNode(internalJSONNode::newInternal(name.c_str() + 1, value))); //attach it to the parent node - #endif -} - -//Create a subarray -void JSONWorker::DoArray(const internalJSONNode * parent, const json_string & value_t){ - /* - This takes an array and creates nodes out of them - */ - JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoArray is empty")); - JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('['), JSON_TEXT("DoArray is not an array"), parent -> Nullify(); return;); - const size_t len = value_t.length(); - if (len <= 2) return; // just a [] (blank array) - - //Not sure what's in the array, so we have to use commas - size_t starting = 1; //ignore the [ - size_t ending = FindNextRelevant(JSON_TEXT(','), value_t, 1); - while (ending != json_string::npos){ - #ifdef JSON_SAFE - json_string newValue = value_t.substr(starting, ending - starting); - JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;); - NewNode(parent, JSON_TEXT(""), newValue, true); - #else - NewNode(parent, JSON_TEXT(""), value_t.substr(starting, ending - starting), true); - #endif - starting = ending + 1; - ending = FindNextRelevant(JSON_TEXT(','), value_t, starting); - } - //since the last one will not find the comma, we have to add it here, but ignore the final ] - - #ifdef JSON_SAFE - json_string newValue = value_t.substr(starting, len - starting - 1); - JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;); - NewNode(parent, JSON_TEXT(""), newValue, true); - #else - NewNode(parent, JSON_TEXT(""), value_t.substr(starting, len - starting - 1), true); - #endif -} - -//Create all child nodes -void JSONWorker::DoNode(const internalJSONNode * parent, const json_string & value_t){ - /* - This take a node and creates its members and such - */ - JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoNode is empty")); - JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('{'), JSON_TEXT("DoNode is not an node"), parent -> Nullify(); return;); - const size_t len = value_t.length(); - if (len <= 2) return; // just a {} (blank node) - - size_t name_starting = 1; //ignore the { - size_t name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, 1); //find where the name ends - JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;); - json_string name = value_t.substr(name_starting, name_ending - 2); //pull the name out - size_t value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending); //find the end of the value - while (value_ending != json_string::npos){ - NewNode(parent, name, value_t.substr(name_ending + 1, value_ending - name_ending - 1), false); - name_starting = value_ending + 1; - name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, name_starting); - JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;); - name = value_t.substr(name_starting, name_ending - name_starting - 1); - value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending); - } - //since the last one will not find the comma, we have to add it here - NewNode(parent, name, value_t.substr(name_ending + 1, len - name_ending - 2), false); -} diff --git a/src/mir_core/json/JSONWorker.h b/src/mir_core/json/JSONWorker.h deleted file mode 100644 index f425e12e86..0000000000 --- a/src/mir_core/json/JSONWorker.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef JSON_WORKER_H -#define JSON_WORKER_H - -#include "JSONNode.h" - -class JSONWorker { -public: - static JSONNode parse(const json_string & json); - #ifdef JSON_VALIDATE - static JSONNode validate(const json_string & json); - #endif - #if defined JSON_DEBUG || defined JSON_SAFE - static json_char * RemoveWhiteSpace(const json_string & value_t, json_char & last); - #else - static json_char * RemoveWhiteSpace(const json_string & value_t); - #endif - static json_string RemoveWhiteSpaceAndComments(const json_string & value_t); - - static void DoArray(const internalJSONNode * parent, const json_string & value_t); - static void DoNode(const internalJSONNode * parent, const json_string & value_t); - - #ifdef JSON_LESS_MEMORY - #define NAME_ENCODED this, true - #define STRING_ENCODED this, false - static json_string FixString(const json_string & value_t, const internalJSONNode * flag, bool which); - #else - #define NAME_ENCODED _name_encoded - #define STRING_ENCODED _string_encoded - static json_string FixString(const json_string & value_t, bool & flag); - #endif - static json_string UnfixString(const json_string & value_t, bool flag); -JSON_PRIVATE - static json_char Hex(const json_char * & pos); - static json_uchar UTF8(const json_char * & pos); - static json_char* UTF8_2(const json_char * & pos); - static json_string toUTF8(json_uchar p); - #ifdef JSON_UNICODE - static json_string UTF(const json_char * & pos); - static json_string toSurrogatePair(json_uchar pos); - #endif - static void SpecialChar(const json_char * & pos, json_string & res); - static size_t FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos); - static void NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, bool array); -}; - -#endif diff --git a/src/mir_core/json/JSONWriter.cpp b/src/mir_core/json/JSONWriter.cpp deleted file mode 100644 index edf407d25d..0000000000 --- a/src/mir_core/json/JSONWriter.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" - -#include "JSONNode.h" -#ifdef JSON_WRITER -#include "JSONWorker.h" - -const static json_string WRITER_EMPTY; -#ifndef JSON_NEWLINE - const static json_string NEW_LINE(JSON_TEXT("\n")); -#else - const static json_string NEW_LINE(JSON_TEXT(JSON_NEWLINE)); -#endif - -#ifdef JSON_INDENT - const static json_string INDENT(JSON_TEXT(JSON_INDENT)); - - inline json_string makeIndent(unsigned int amount){ - if (amount == 0xFFFFFFFF) return WRITER_EMPTY; - json_string result; - result.reserve(amount); - for(unsigned int i=0; i < amount; ++i){ - result += INDENT; - } - return result; - } -#else - inline json_string makeIndent(unsigned int amount){ - if (amount == 0xFFFFFFFF) return WRITER_EMPTY; - return json_string(amount, JSON_TEXT('\t')); - } -#endif - -json_string internalJSONNode::WriteName(bool formatted, bool arrayChild) const { - if (arrayChild){ - return WRITER_EMPTY ; - } else { - return JSON_TEXT("\"") + JSONWorker::UnfixString(_name, _name_encoded) + ((formatted) ? JSON_TEXT("\" : ") : JSON_TEXT("\":")); - } -} - -json_string internalJSONNode::WriteChildren(unsigned int indent){ - //Iterate through the children and write them - if (Children.empty()) return WRITER_EMPTY; - - json_string indent_plus_one; - json_string indent_this; - json_string res; - //handle whether or not it's formatted JSON - if (indent != 0xFFFFFFFF){ //it's formatted, make the indentation strings - indent_this = NEW_LINE + makeIndent(indent); - indent_plus_one = NEW_LINE + makeIndent(++indent); - } - //else it's not formatted, leave the indentation strings empty - const size_t size_minus_one = Children.size() - 1; - size_t i=0; - json_foreach(Children, it){ - res += indent_plus_one + (*it) -> internal -> Write(indent, type() == JSON_ARRAY); - if (i < size_minus_one) res += JSON_TEXT(","); //the last one does not get a comma, but all of the others do - ++i; - } - return res + indent_this; -} - -#ifdef JSON_COMMENTS - #ifdef JSON_WRITE_BASH_COMMENTS - const static json_string SINGLELINE(JSON_TEXT("#")); - #else - const static json_string SINGLELINE(JSON_TEXT("//")); - #endif - - json_string internalJSONNode::WriteComment(unsigned int indent) const { - if (indent == 0xFFFFFFFF) return WRITER_EMPTY; - if (_comment.empty()) return WRITER_EMPTY; - size_t pos = _comment.find(JSON_TEXT('\n')); - if (pos == json_string::npos){ //Single line comment - return NEW_LINE + makeIndent(indent) + SINGLELINE + _comment + NEW_LINE + makeIndent(indent); - } - - /* - Multiline comments - */ - #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) - json_string result(NEW_LINE + makeIndent(indent)); - #else - json_string result(NEW_LINE + makeIndent(indent) + JSON_TEXT("/*") + NEW_LINE + makeIndent(indent + 1)); - #endif - size_t old = 0; - while(pos != json_string::npos){ - if (pos && _comment[pos - 1] == JSON_TEXT('\r')) --pos; - #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) - result += SINGLELINE; - #endif - result += _comment.substr(old, pos - old) + NEW_LINE; - #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) - result += makeIndent(indent); - #else - result += makeIndent(indent + 1); - #endif - old = (_comment[pos] == JSON_TEXT('\r')) ? pos + 2 : pos + 1; - pos = _comment.find(JSON_TEXT('\n'), old); - } - #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) - result += SINGLELINE; - #endif - result += _comment.substr(old, pos - old) + NEW_LINE + makeIndent(indent); - #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) - return result; - #else - return result + JSON_TEXT("*/") + NEW_LINE + makeIndent(indent); - #endif - } -#else - json_string internalJSONNode::WriteComment(unsigned int) const { - return WRITER_EMPTY; - } -#endif - -json_string internalJSONNode::Write(unsigned int indent, bool arrayChild){ - const bool formatted = indent != 0xFFFFFFFF; - - #ifndef JSON_PREPARSE - if (!(formatted || fetched)) { //It's not formatted or fetched, just do a raw dump - return WriteComment(indent) + WriteName(false, arrayChild) + _string; - } - #endif - - //It's either formatted or fetched - switch (type()) { - case JSON_NODE: //got members, write the members - Fetch(); - return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("{") + WriteChildren(indent) + JSON_TEXT("}"); - case JSON_ARRAY: //write out the child nodes int he array - Fetch(); - return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("[") + WriteChildren(indent) + JSON_TEXT("]"); - case JSON_NUMBER: //write out a literal, without quotes - case JSON_NULL: - case JSON_BOOL: - return WriteComment(indent) + WriteName(formatted, arrayChild) + _string; - } - - JSON_ASSERT_SAFE(type() == JSON_STRING, JSON_TEXT("Writing an unknown JSON node type"), return JSON_TEXT("");); - //If it go here, then it's a json_string - #ifndef JSON_PREPARSE - if (fetched) return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("\"") + JSONWorker::UnfixString(_string, _string_encoded) + JSON_TEXT("\""); //It's already been fetched, meaning that it's unescaped - return WriteComment(indent) + WriteName(formatted, arrayChild) + _string; //it hasn't yet been fetched, so it's already unescaped, just do a dump - #else - return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("\"") + JSONWorker::UnfixString(_string, _string_encoded) + JSON_TEXT("\""); - #endif -} -#endif diff --git a/src/mir_core/json/NumberToString.h b/src/mir_core/json/NumberToString.h deleted file mode 100644 index a706372f92..0000000000 --- a/src/mir_core/json/NumberToString.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef NUMBERTOSTRING_H -#define NUMBERTOSTRING_H - -#include "JSONDebug.h" -#include "JSONMemory.h" -#include - -static unsigned int getlen(unsigned int size){ - switch (size){ - case 1: - return 5; //3 digits for the number, plus null terminator and negation - case 2: - return 7; //5 digits for the number, plus null terminator and negation - case 4: - return 12; //10 digits for the number, plus null terminator and negation - case 8: - return 22; //20 digits for the number, plus null terminator and negation - } - JSON_ASSERT(size == 16, JSON_TEXT("template is not recognized 2^x in size")); - return 41; //39 digits for the number, plus null terminator and negation -} - -class NumberToString { -public: - template - static json_string _itoa(T val, unsigned int size){ - long value = (long)val; - const unsigned int digits = getlen(size); - json_auto result(digits); - result.ptr[digits - 1] = JSON_TEXT('\0'); //null terminator - json_char * runner = &result.ptr[digits - 2]; - bool negative; - - //first thing, check if it's negative, if so, make it positive - if (value < 0){ - value = -value; - negative = true; - } else { - negative = false; - } - - //create the string - do { - *runner--=(json_char)(value % 10) + JSON_TEXT('0'); - } while(value /= 10); - - //if it's negative, add the negation - json_string res; - if (negative){ - *runner = JSON_TEXT('-'); - res = runner; - } else { - res = runner + 1; - } - return res; - } - - #ifndef JSON_LIBRARY - template - static json_string _uitoa(T val, unsigned int size){ - unsigned long value = val; - const unsigned int digits = getlen(size) - 1; //minus one because no '-' char - json_auto result(digits); - result.ptr[digits - 1] = JSON_TEXT('\0'); //null terminator - json_char * runner = &result.ptr[digits - 2]; - - //create the string - do { - *runner--=(json_char)(value % 10) + JSON_TEXT('0'); - } while(value /= 10); - - json_string res = runner + 1; - return res; - } - #endif - - template - static json_string _ftoa(T value){ - json_char result[64]; - #ifdef JSON_UNICODE - mir_snwprintf(result, 63, L"%f", value); - #else - mir_snprintf(result, 63, "%f", value); - #endif - //strip the trailing zeros - for(json_char * pos = &result[0]; *pos; ++pos){ - if (*pos == '.') { //only care about after the decimal - for(json_char * runner = pos + 1; *runner; ++runner){ - if (*runner != JSON_TEXT('0')) pos = runner + 1; - } - *pos = JSON_TEXT('\0'); - break; - } - } - return result; - } - - static inline bool areEqual(const double & one, const double & two){ - const double temp = one - two; - return (temp > 0.0) ? temp < 0.00001 : temp > -0.00001; - } -}; - -#endif diff --git a/src/mir_core/json/internalJSONNode.cpp b/src/mir_core/json/internalJSONNode.cpp deleted file mode 100644 index 4b33ad9545..0000000000 --- a/src/mir_core/json/internalJSONNode.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" -#include - -#include "internalJSONNode.h" -#include "NumberToString.h" //So that I can convert numbers into strings -#include "JSONNode.h" //To fill in the foreward declaration -#include "JSONWorker.h" //For fetching and parsing and such - -/* - The point of these constants is for faster assigning, if I - were to constantly assign to a string literal, there would be - lots of copies, but since strings are copy on write, this assignment - is much faster -*/ -static const json_string CONST_TRUE(JSON_TEXT("true")); -static const json_string CONST_FALSE(JSON_TEXT("false")); -static const json_string CONST_NULL(JSON_TEXT("null")); - -#ifdef JSON_UNIT_TEST - void internalJSONNode::incinternalAllocCount(void){ JSONNode::incinternalAllocCount(); } - void internalJSONNode::decinternalAllocCount(void){ JSONNode::decinternalAllocCount(); } -#endif - -internalJSONNode::internalJSONNode(const internalJSONNode & orig) : - _type(orig._type), _name(orig._name), _name_encoded(orig._name_encoded), Children(), - _string(orig._string), _string_encoded(orig._string_encoded), _value(orig._value) - initializeRefCount(1) - initializeFetch(orig.fetched) - initializeMutex(0) - initializeComment(orig._comment) - initializeValid(orig.isValid){ - - incinternalAllocCount(); - #ifdef JSON_MUTEX_CALLBACKS - _set_mutex(orig.mylock, false); - #endif - if (!orig.Children.empty()) { - Children.reserve(orig.Children.size()); - json_foreach(orig.Children, myrunner){ - Children.push_back(JSONNode::newJSONNode((*myrunner) -> duplicate())); - } - } -} - -#ifdef JSON_PREPARSE - #define SetFetchedFalseOrDo(code) code -#else - #define SetFetchedFalseOrDo(code) SetFetched(false) -#endif - -#ifdef JSON_VALIDATE - #define NOTVALID false -#else - #define NOTVALID -#endif - -//this one is specialized because the root can only be array or node -internalJSONNode::internalJSONNode(const json_string & unparsed) : _type(), _name(),_name_encoded(false), _string(unparsed), _string_encoded(), _value(), Children() - initializeMutex(0) - initializeRefCount(1) - initializeFetch(false) - initializeComment(0) - initializeValid(0){ - - incinternalAllocCount(); - switch (unparsed[0]) { - case JSON_TEXT('{'): //node - _type = JSON_NODE; - #ifdef JSON_PREPARSE - FetchNode(); - #endif - break; - case JSON_TEXT('['): //array - _type = JSON_ARRAY; - #ifdef JSON_PREPARSE - FetchArray(); - #endif - break; - default: - JSON_FAIL_SAFE(JSON_TEXT("root not starting with either { or ["), Nullify(NOTVALID);); - break; - } -} - -internalJSONNode::internalJSONNode(const json_string & name_t, const json_string & value_t) : _type(), _name_encoded(), _name(JSONWorker::FixString(name_t, NAME_ENCODED)), _string(), _string_encoded(), _value(), Children() - initializeMutex(0) - initializeRefCount(1) - initializeFetch(0) - initializeComment(0) - initializeValid(0){ - - incinternalAllocCount(); - - if (value_t.empty()) { - _type = JSON_NULL; - #ifdef JSON_VALIDATE - isValid = true; - #endif - SetFetched(true); - return; - } - - _string = value_t; - const json_char firstchar = value_t[0]; - #if defined JSON_DEBUG || defined JSON_SAFE - const json_char lastchar = value_t[value_t.length() - 1]; - #endif - - switch (firstchar){ - case JSON_TEXT('\"'): //a json_string literal, still escaped and with leading and trailing quotes - JSON_ASSERT_SAFE(lastchar == JSON_TEXT('\"'), JSON_TEXT("Unterminated quote"), Nullify(NOTVALID); return;); - _type = JSON_STRING; - SetFetchedFalseOrDo(FetchString()); - break; - case JSON_TEXT('{'): //a child node, or set of children - JSON_ASSERT_SAFE(lastchar == JSON_TEXT('}'), JSON_TEXT("Missing }"), Nullify(NOTVALID); return;); - _type = JSON_NODE; - SetFetchedFalseOrDo(FetchNode()); - break; - case JSON_TEXT('['): //an array - JSON_ASSERT_SAFE(lastchar == JSON_TEXT(']'), JSON_TEXT("Missing ]"), Nullify(NOTVALID); return;); - _type = JSON_ARRAY; - SetFetchedFalseOrDo(FetchArray()); - break; - case JSON_TEXT('t'): - JSON_ASSERT_SAFE(value_t == JSON_TEXT("true"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); - _value._bool = true; - _type = JSON_BOOL; - SetFetched(true); - break; - case JSON_TEXT('f'): - JSON_ASSERT_SAFE(value_t == JSON_TEXT("false"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); - _value._bool = false; - _type = JSON_BOOL; - SetFetched(true); - break; - case JSON_TEXT('n'): - JSON_ASSERT_SAFE(value_t == JSON_TEXT("null"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); - _type = JSON_NULL; - SetFetched(true); - #ifdef JSON_VALIDATE - isValid = true; - #endif - break; - default: - JSON_ASSERT_SAFE(value_t.find_first_not_of(JSON_TEXT("0123456789.e+-")) == json_string::npos, json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); - _type = JSON_NUMBER; - SetFetchedFalseOrDo(FetchNumber()); - break; - } -} - -internalJSONNode::~internalJSONNode(void){ - decinternalAllocCount(); - #ifdef JSON_MUTEX_CALLBACKS - _unset_mutex(); - #endif - //DO NOT delete the children! It automatically gets removed -} - -void internalJSONNode::FetchString(void) const { - JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON json_string type is empty?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't start with a quotation?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't end with a quotation?"), Nullify(NOTVALID); return;); - _string = JSONWorker::FixString(_string.substr(1, _string.length() - 2), STRING_ENCODED); -} - -void internalJSONNode::FetchNode(void) const { - JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('{'), JSON_TEXT("JSON node type doesn't start with a bracket?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('}'), JSON_TEXT("JSON node type doesn't end with a bracket?"), Nullify(NOTVALID); return;); - JSONWorker::DoNode(this, _string); - clearString(_string); -} - -void internalJSONNode::FetchArray(void) const { - JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('['), JSON_TEXT("JSON node type doesn't start with a square bracket?"), Nullify(NOTVALID); return;); - JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT(']'), JSON_TEXT("JSON node type doesn't end with a square bracket?"), Nullify(NOTVALID); return;); - JSONWorker::DoArray(this, _string); - clearString(_string); -} - -void internalJSONNode::FetchNumber(void) const { - #ifdef JSON_UNICODE - { - const size_t len = _string.length(); - json_auto temp(len + 1); - wcstombs(temp.ptr, _string.c_str(), len); - temp.ptr[len] = '\0'; - _value._number = (json_number)atof(temp.ptr); - } - #else - _value._number = (json_number)atof(_string.c_str()); - #endif -} - -#ifndef JSON_PREPARSE - void internalJSONNode::Fetch(void) const { - if (fetched) return; - switch (type()) { - case JSON_STRING: - FetchString(); - break; - case JSON_NODE: - FetchNode(); - break; - case JSON_ARRAY: - FetchArray(); - break; - case JSON_NUMBER: - FetchNumber(); - break; - #if defined JSON_DEBUG || defined JSON_SAFE - default: - JSON_FAIL(JSON_TEXT("Fetching an unknown type")); - Nullify(NOTVALID); - #endif - } - fetched = true; - } -#endif - -void internalJSONNode::Set(const json_string & val){ - _type = JSON_STRING; - _string = val; - _string_encoded = true; - SetFetched(true); -} - -#ifdef JSON_LIBRARY - void internalJSONNode::Set(long val){ - _type = JSON_NUMBER; - _value._number = (json_number)val; - _string = NumberToString::_itoa(val, sizeof(long)); - SetFetched(true); - } - - void internalJSONNode::Set(json_number val){ - _type = JSON_NUMBER; - _value._number = val; - _string = NumberToString::_ftoa(val); - SetFetched(true); - } -#else - #define SET(converter, type)\ - void internalJSONNode::Set(type val){\ - _type = JSON_NUMBER;\ - _value._number = (json_number)val;\ - _string = NumberToString::converter(val, sizeof(type));\ - SetFetched(true);\ - } - #define SET_INTEGER(type) SET(_itoa, type) SET(_uitoa, unsigned type) - #define SET_FLOAT(type) \ - void internalJSONNode::Set(type val){\ - _type = JSON_NUMBER;\ - _value._number = (json_number)val;\ - _string = NumberToString::_ftoa(val);\ - SetFetched(true);\ - } - - SET_INTEGER(char) - SET_INTEGER(short) - SET_INTEGER(int) - SET_INTEGER(long) - #ifndef JSON_ISO_STRICT - SET_INTEGER(long long) - #endif - - SET_FLOAT(float) - SET_FLOAT(double) -#endif - -void internalJSONNode::Set(bool val){ - _type = JSON_BOOL; - _value._bool = val; - _string = val ? CONST_TRUE : CONST_FALSE; - SetFetched(true); -} - -bool internalJSONNode::IsEqualTo(const internalJSONNode * val) const { - #ifdef JSON_REF_COUNT - if (this == val) return true; //reference counting the same internal object, so they must be equal - #endif - if (type() != val -> type()) return false; //aren't even same type - if (_name != val -> _name) return false; //names aren't the same - if (type() == JSON_NULL) return true; //both null, can't be different - #ifndef JSON_PREPARSE - Fetch(); - val -> Fetch(); - #endif - switch (type()) { - case JSON_STRING: - return val -> _string == _string; - case JSON_NUMBER: - return NumberToString::areEqual(val -> _value._number, _value._number); - case JSON_BOOL: - return val -> _value._bool == _value._bool; - }; - - JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Checking for equality, not sure what type")); - if (Children.size() != val -> Children.size()) return false; //if they arne't he same size then they certainly aren't equal - - //make sure each children is the same - JSONNode ** valrunner = val -> Children.begin(); - json_foreach(Children, myrunner){ - JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); - JSON_ASSERT(*valrunner, JSON_TEXT("a null pointer within the children")); - JSON_ASSERT(valrunner != val -> Children.end(), JSON_TEXT("at the end of other one's children, but they're the same size?")); - if (**myrunner != **valrunner) return false; - ++valrunner; - } - return true; -} - -#ifdef JSON_VALIDATE -void internalJSONNode::Nullify(bool validation) const { - isValid = validation; -#else -void internalJSONNode::Nullify(void) const { -#endif - _type = JSON_NULL; - _string = CONST_NULL; - SetFetched(true); -} - -#ifdef JSON_MUTEX_CALLBACKS - #define JSON_MUTEX_COPY ,mylock -#else - #define JSON_MUTEX_COPY -#endif - -#ifdef JSON_LIBRARY -void internalJSONNode::push_back(JSONNode *node){ -#else -void internalJSONNode::push_back(const JSONNode & node){ -#endif - JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing back to something that is not an array or object")); - #ifdef JSON_LIBRARY - #ifdef JSON_MUTEX_CALLBACKS - if (mylock) node -> set_mutex(mylock); - #endif - Children.push_back(node); - #else - Children.push_back(JSONNode::newJSONNode(node JSON_MUTEX_COPY)); - #endif -} - -void internalJSONNode::push_front(const JSONNode & node){ - JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing front to something that is not an array or object")); - Children.push_front(JSONNode::newJSONNode(node JSON_MUTEX_COPY)); -} - -JSONNode * internalJSONNode::pop_back(json_index_t pos){ - JSONNode * result = Children[pos]; - JSONNode ** temp = Children.begin() + pos; - Children.erase(temp); - return result; -} - -JSONNode * internalJSONNode::pop_back(const json_string & name_t){ - if (JSONNode ** res = at(name_t)) { - JSONNode * result = *res; - Children.erase(res); - return result; - } - return 0; -} - -#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode * internalJSONNode::pop_back_nocase(const json_string & name_t){ - if (JSONNode ** res = at_nocase(name_t)) { - JSONNode * result = *res; - Children.erase(res); - return result; - } - return 0; - } -#endif - -JSONNode ** internalJSONNode::at(const json_string & name_t){ - Fetch(); - json_foreach(Children, myrunner){ - JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); - if ((*myrunner) -> name() == name_t) return myrunner; - } - return 0; -} - -#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - bool internalJSONNode::AreEqualNoCase(const json_char * ch_one, const json_char * ch_two){ - while (*ch_one){ //only need to check one, if the other one terminates early, the check will cause it to fail - const json_char c_one = *ch_one; - const json_char c_two = *ch_two; - if (c_one != c_two){ - if ((c_two > 64) && (c_two < 91)) { //A - Z - if (c_one != (json_char)(c_two + 32)) return false; - } else if ((c_two > 96) && (c_two < 123)) { //a - z - if (c_one != (json_char)(c_two - 32)) return false; - } else { //not a letter, so return false - return false; - } - } - ++ch_one; - ++ch_two; - - } - return *ch_two == '\0'; //this one has to be null terminated too, or else json_string two is longer, hence, not equal - } - - JSONNode ** internalJSONNode::at_nocase(const json_string & name_t){ - Fetch(); - json_foreach(Children, myrunner){ - JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); - if (AreEqualNoCase((*myrunner) -> name().c_str(), name_t.c_str())) return myrunner; - } - return 0; - } -#endif - -#ifndef JSON_PREPARSE - void internalJSONNode::preparse(void){ - Fetch(); - json_foreach(Children, myrunner){ - (*myrunner) -> preparse(); - } - } -#endif - -#ifdef JSON_VALIDATE - bool internalJSONNode::validate(void){ - json_foreach(Children, myrunner){ - if ((*myrunner) -> type() != JSON_NULL){ - #ifndef JSON_PREPARSE - (*myrunner) -> internal -> Fetch(); - #endif - if ((*myrunner) -> type() == JSON_NULL) return false; - } else if (!((*myrunner) -> internal -> isValid)) { - JSON_FAIL(_name + JSON_TEXT(" is null and not valid")); - return false; - } - } - json_foreach(Children, runner){ - if (!((*runner) -> internal -> validate())) return false; - } - return true; - } -#endif - -#ifdef JSON_DEBUG - #ifndef JSON_LIBRARY - JSONNode internalJSONNode::Dump(size_t & totalbytes) const { - JSONNode dumpage(JSON_NODE); - dumpage.set_name(JSON_TEXT("internalJSONNode")); - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); - - size_t memory = sizeof(internalJSONNode); - memory += _name.capacity() * sizeof(json_char); - memory += _string.capacity() * sizeof(json_char); - memory += Children.capacity() * sizeof(JSONNode*); - #ifdef JSON_COMMENTS - memory += _comment.capacity() * sizeof(json_char); - #endif - totalbytes += memory; - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), memory))); - - #ifdef JSON_REF_COUNT - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("refcount"), refcount))); - #endif - #ifdef JSON_MUTEX_CALLBACKS - dumpage.push_back(JSON_NEW(DumpMutex())); - #endif - - #define DUMPCASE(ty)\ - case ty:\ - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT(#ty))));\ - break; - - switch(type()) { - DUMPCASE(JSON_NULL) - DUMPCASE(JSON_STRING) - DUMPCASE(JSON_NUMBER) - DUMPCASE(JSON_BOOL) - DUMPCASE(JSON_ARRAY) - DUMPCASE(JSON_NODE) - default: - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT("Unknown")))); - } - - JSONNode str(JSON_NODE); - str.set_name(JSON_TEXT("_name")); - str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _name))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _name.length()))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _name.capacity()))); - - #ifdef JSON_LESS_MEMORY - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _type & 0x10))); - #else - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _name_encoded))); - #endif - dumpage.push_back(JSON_NEW(str)); - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_string_encoded"), _string_encoded))); - str.clear(); - str.set_name(JSON_TEXT("_string")); - str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _string))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _string.length()))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _string.capacity()))); - dumpage.push_back(JSON_NEW(str)); - - JSONNode unio(JSON_NODE); - unio.set_name(JSON_TEXT("_value")); - unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_bool"), _value._bool))); - unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_number"), _value._number))); - dumpage.push_back(JSON_NEW(unio)); - - #ifndef JSON_PREPARSE - dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("fetched"), fetched))); - #endif - - #ifdef JSON_COMMENTS - str.clear(); - str.set_name(JSON_TEXT("_comment")); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("value"), _comment))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _comment.length()))); - str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _comment.capacity()))); - dumpage.push_back(JSON_NEW(str)); - #endif - - JSONNode arra(JSON_NODE); - arra.set_name(JSON_TEXT("Children")); - arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("size"), Children.size()))); - arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("capacity"), Children.capacity()))); - JSONNode chil(JSON_ARRAY); - chil.set_name(JSON_TEXT("array")); - json_foreach(Children, it){ - chil.push_back(JSON_NEW((*it) -> dump(totalbytes))); - } - arra.push_back(JSON_NEW(chil)); - dumpage.push_back(JSON_NEW(arra)); - - return dumpage; - } - #endif -#endif diff --git a/src/mir_core/json/internalJSONNode.h b/src/mir_core/json/internalJSONNode.h deleted file mode 100644 index cf626ceae0..0000000000 --- a/src/mir_core/json/internalJSONNode.h +++ /dev/null @@ -1,452 +0,0 @@ -#ifndef INTERNAL_JSONNODE_H -#define INTERNAL_JSONNODE_H - -#include "JSONDebug.h" -#include "JSONChildren.h" -#include "JSONMemory.h" -#ifdef JSON_DEBUG - #include //to check int value -#endif - -/* - This class is the work horse of libJSON, it handles all of the - functinality of JSONNode. This object is reference counted for - speed and memory reasons. - - If JSON_REF_COUNT is not on, this internal structure still has an important - purpose, as it can be passed around by JSONNoders that are flagged as temporary -*/ - -class JSONNode; //forward declaration - -#ifndef JSON_LIBRARY - #define DECL_SET_INTEGER(type) void Set(type); void Set(unsigned type); -#endif - -#ifdef JSON_MUTEX_CALLBACKS - #define initializeMutex(x) ,mylock(x) -#else - #define initializeMutex(x) -#endif - -#ifdef JSON_PREPARSE - #define SetFetched(b) (void)0 - #define Fetch() (void)0 -#define initializeFetch(x) -#else - #define initializeFetch(x) ,fetched(x) -#endif - -#ifdef JSON_REF_COUNT - #define initializeRefCount(x) ,refcount(x) -#else - #define initializeRefCount(x) -#endif - -#ifdef JSON_COMMENTS - #define initializeComment(x) ,_comment(x) -#else - #define initializeComment(x) -#endif - -#ifndef JSON_UNIT_TEST - #define incAllocCount() (void)0 - #define decAllocCount() (void)0 - #define incinternalAllocCount() (void)0 - #define decinternalAllocCount() (void)0 -#endif - -#ifdef JSON_VALIDATE - #define initializeValid(x) ,isValid(x) -#else - #define initializeValid(x) -#endif - -class internalJSONNode { -public: - internalJSONNode(char mytype = JSON_NULL); - internalJSONNode(const json_string & unparsed); - internalJSONNode(const json_string & name_t, const json_string & value_t); - internalJSONNode(const internalJSONNode & orig); - internalJSONNode & operator = (const internalJSONNode &); - ~internalJSONNode(void); - - static internalJSONNode * newInternal(char mytype = JSON_NULL); - static internalJSONNode * newInternal(const json_string & unparsed); - static internalJSONNode * newInternal(const json_string & name_t, const json_string & value_t); - static internalJSONNode * newInternal(const internalJSONNode & orig); //not copyable, only by this class - static void deleteInternal(internalJSONNode * ptr); - - json_index_t size(void) const; - bool empty(void) const; - unsigned char type(void) const; - - const json_char* name(void) const; - void setname(const json_string & newname); - #ifdef JSON_COMMENTS - void setcomment(const json_string & comment); - json_string getcomment(void) const; - #endif - json_string as_string(void) const; - long as_int(void) const; - json_number as_float(void) const; - bool as_bool(void) const; - - #ifndef JSON_PREPARSE - void preparse(void); - #endif - - #ifdef JSON_LIBRARY - void push_back(JSONNode *node); - #else - void push_back(const JSONNode & node); - #endif - void reserve(json_index_t size); - void push_front(const JSONNode & node); - JSONNode * pop_back(json_index_t pos); - JSONNode * pop_back(const json_string & name_t); - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode * pop_back_nocase(const json_string & name_t); - #endif - - JSONNode * at(json_index_t pos); - //These return ** because pop_back needs them - JSONNode ** at(const json_string & name_t); - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - JSONNode ** at_nocase(const json_string & name_t); - #endif - - void Set(const json_string & val); - #ifdef JSON_LIBRARY - void Set(json_number val); - void Set(long val); - #else - DECL_SET_INTEGER(char) - DECL_SET_INTEGER(short) - DECL_SET_INTEGER(int) - DECL_SET_INTEGER(long) - #ifndef JSON_ISO_STRICT - DECL_SET_INTEGER(long long) - #endif - - void Set(float val); - void Set(double val); - #endif - void Set(bool val); - - bool IsEqualTo(const json_string & val)const ; - bool IsEqualTo(bool val) const; - bool IsEqualTo(const internalJSONNode * val) const; - - template - bool IsEqualToNum(T val) const; - - internalJSONNode * incRef(void); - #ifdef JSON_REF_COUNT - void decRef(void); - bool hasNoReferences(void); - #endif - internalJSONNode * makeUnique(void); - - JSONNode ** begin(void) const; - JSONNode ** end(void) const; - #ifdef JSON_REF_COUNT - size_t refcount BITS(20); - #endif - bool Fetched(void) const; - #ifdef JSON_MUTEX_CALLBACKS - void * mylock; - void _set_mutex(void * mutex, bool unset = true); - void _unset_mutex(void); - #endif - #ifdef JSON_UNIT_TEST - static void incinternalAllocCount(void); - static void decinternalAllocCount(void); - #endif - - #ifdef JSON_WRITER - json_string WriteName(bool formatted, bool arrayChild) const; - json_string WriteChildren(unsigned int indent); - json_string WriteComment(unsigned int indent) const; - json_string Write(unsigned int indent, bool arrayChild); - #endif - #ifdef JSON_DEBUG - #ifndef JSON_LIBRARY - JSONNode Dump(size_t & totalmemory) const; - JSONNode DumpMutex(void) const; - #endif - #endif - - //json parts - mutable unsigned char _type BITS(3); - mutable bool _name_encoded BITS(1); //must be above name due to initialization list order - json_string _name; - - mutable json_string _string; //these are both mutable because the string can change when it's fetched - mutable bool _string_encoded BITS(1); - - //the value of the json - union value_union_t { - bool _bool; - json_number _number; - }; - mutable value_union_t _value; //internal structure changes depending on type - - jsonChildren Children; //container that holds all of my children - - #ifdef JSON_VALIDATE - mutable bool isValid BITS(1); //this does not need to be initialized, it's only used if it's null - void Nullify(bool validation = true) const; - bool validate(void); - #else - void Nullify(void) const; - #endif - - //Fetching and such - #ifndef JSON_PREPARSE - mutable bool fetched BITS(1); - void SetFetched(bool val) const; - void Fetch(void) const; //it's const because it doesn't change the VALUE of the function - #endif - - #ifdef JSON_COMMENTS - json_string _comment; - #endif - - void FetchString(void) const; - void FetchNode(void) const; - void FetchArray(void) const; - void FetchNumber(void) const; - #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - static bool AreEqualNoCase(const json_char * ch_one, const json_char * ch_two); - #endif -}; - -inline internalJSONNode::internalJSONNode(char mytype) : _type(mytype), Children(), _name(), _name_encoded(), _string(), _string_encoded(), _value() - initializeMutex(0) - initializeRefCount(1) - initializeFetch(true) - initializeComment(0) - initializeValid(true){ - - incinternalAllocCount(); -} - -inline internalJSONNode * internalJSONNode::incRef(void){ - #ifdef JSON_REF_COUNT - ++refcount; - return this; - #else - return makeUnique(); - #endif -} - -inline json_index_t internalJSONNode::size(void) const { - Fetch(); - return Children.size(); -} - -inline bool internalJSONNode::empty(void) const { - if (type() != JSON_NODE && type() != JSON_ARRAY) return true; - Fetch(); - return Children.empty(); -} - -inline unsigned char internalJSONNode::type(void) const { - #ifdef JSON_LESS_MEMORY - return _type & 0xF; - #else - return _type; - #endif -} - -inline const json_char* internalJSONNode::name(void) const { - return _name.c_str(); -} - -inline void internalJSONNode::setname(const json_string & newname){ - _name = newname; - #ifdef JSON_LESS_MEMORY - _type |= 0x10; - #else - _name_encoded = true; - #endif -} - -#ifdef JSON_COMMENTS - inline void internalJSONNode::setcomment(const json_string & comment){ - _comment = comment; - } - - inline json_string internalJSONNode::getcomment(void) const { - return _comment; - } -#endif - -inline json_string internalJSONNode::as_string(void) const { - Fetch(); - return _string; -} - -inline long internalJSONNode::as_int(void) const { - Fetch(); - switch(type()) { - case JSON_NULL: - return 0; - case JSON_BOOL: - return _value._bool ? 1 : 0; - } - JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_int returning undefined results")); - JSON_ASSERT(_value._number > LONG_MIN, _string + JSON_TEXT(" is outside the lower range of long")); - JSON_ASSERT(_value._number < LONG_MAX, _string + JSON_TEXT(" is outside the upper range of long")); - JSON_ASSERT(_value._number == (json_number)((int)_value._number), json_string(JSON_TEXT("as_int will truncate ")) + _string); - return (int)_value._number; -} - -inline json_number internalJSONNode::as_float(void) const { - Fetch(); - switch(type()) { - case JSON_NULL: - return (json_number)0.0; - case JSON_BOOL: - return (json_number)(_value._bool ? 1.0 : 0.0); - } - JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_float returning undefined results")); - return _value._number; -} - -inline bool internalJSONNode::as_bool(void) const { - Fetch(); - switch(type()) { - case JSON_NUMBER: - return _value._number != 0.0f; - case JSON_NULL: - return false; - } - JSON_ASSERT(type() == JSON_BOOL, JSON_TEXT("as_bool returning undefined results")); - return _value._bool; -} - -inline bool internalJSONNode::IsEqualTo(const json_string & val) const { - if (type() != JSON_STRING) return false; - Fetch(); - return val == _string; -} - -inline bool internalJSONNode::IsEqualTo(bool val) const { - if (type() != JSON_BOOL) return false; - Fetch(); - return val == _value._bool; -} - -template -inline bool internalJSONNode::IsEqualToNum(T val) const { - if (type() != JSON_NUMBER) return false; - Fetch(); - return (json_number)val == _value._number; -} - -#ifdef JSON_REF_COUNT - inline void internalJSONNode::decRef(void){ - JSON_ASSERT(refcount != 0, JSON_TEXT("decRef on a 0 refcount internal")); - --refcount; - } - - inline bool internalJSONNode::hasNoReferences(void){ - return refcount == 0; - } -#endif - -inline internalJSONNode * internalJSONNode::makeUnique(void){ - #ifdef JSON_REF_COUNT - if (refcount > 1){ - decRef(); - return newInternal(*this); - } - JSON_ASSERT(refcount == 1, JSON_TEXT("makeUnique on a 0 refcount internal")); - return this; - #else - return newInternal(*this); - #endif -} - -#ifndef JSON_PREPARSE - inline void internalJSONNode::SetFetched(bool val) const { - fetched = val; - } -#endif - -inline bool internalJSONNode::Fetched(void) const { - #ifndef JSON_PREPARSE - return fetched; - #else - return true; - #endif -} - -inline JSONNode ** internalJSONNode::begin(void) const { - Fetch(); - return Children.begin(); -} - -inline JSONNode ** internalJSONNode::end(void) const { - Fetch(); - return Children.end(); -} - -inline JSONNode * internalJSONNode::at(json_index_t pos){ - Fetch(); - return Children[pos]; -} - -inline void internalJSONNode::reserve(json_index_t size){ - Fetch(); - Children.reserve2(size); -} - -/* - These functions are to allow allocation to be completely controlled by the callbacks -*/ - -inline void internalJSONNode::deleteInternal(internalJSONNode * ptr){ - #ifdef JSON_MEMORY_CALLBACKS - ptr -> ~internalJSONNode(); - libjson_free(ptr); - #else - delete ptr; - #endif -} - -inline internalJSONNode * internalJSONNode::newInternal(char mytype){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) internalJSONNode(mytype); - #else - return new internalJSONNode(mytype); - #endif -} - -inline internalJSONNode * internalJSONNode::newInternal(const json_string & unparsed){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) internalJSONNode(unparsed); - #else - return new internalJSONNode(unparsed); - #endif -} - -inline internalJSONNode * internalJSONNode::newInternal(const json_string & name_t, const json_string & value_t){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) internalJSONNode(name_t, value_t); - #else - return new internalJSONNode(name_t, value_t); - #endif -} - -inline internalJSONNode * internalJSONNode::newInternal(const internalJSONNode & orig){ - #ifdef JSON_MEMORY_CALLBACKS - return new(json_malloc(1)) internalJSONNode(orig); - #else - return new internalJSONNode(orig); - #endif -} - -#endif diff --git a/src/mir_core/json/libJSON.cpp b/src/mir_core/json/libJSON.cpp deleted file mode 100644 index d55505c4eb..0000000000 --- a/src/mir_core/json/libJSON.cpp +++ /dev/null @@ -1,457 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "..\commonheaders.h" - -#include - -/* - This is the implementation of the C interface to libJSON - This file may be included in any C++ application, but it will - be completely ignored if JSON_LIBRARY isn't defined. The - only reason JSON_LIBRARY should be defined is when compiling libJSON - as a library -*/ - -#include "JSONNode.h" -#include "JSONWorker.h" -#include //some methods throw exceptions -#ifdef JSON_MEMORY_MANAGE - auto_expand StringHandler; - auto_expand_node NodeHandler; - #define MANAGER_INSERT(x) NodeHandler.insert(x) -#else - #define MANAGER_INSERT(x) x -#endif - -#ifdef JSON_SAFE - static const json_char * EMPTY_CSTRING = JSON_TEXT(""); -#endif - -inline TCHAR* toCString(const json_string & str) -{ - return mir_utf8decodeT( str.c_str()); -} - -/* - stuff that's in namespace libJSON -*/ - -MIR_CORE_DLL(void) json_free(void *str){ - JSON_ASSERT_SAFE(str, JSON_TEXT("freeing null ptr"), return;); - #ifdef JSON_MEMORY_MANAGE - StringHandler.remove(str); - #endif - libjson_free(str); -} - -MIR_CORE_DLL(void) json_delete(JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("deleting null ptr"), return;); - #ifdef JSON_MEMORY_MANAGE - NodeHandler.remove(node); - #endif - JSONNode::deleteJSONNode((JSONNode *)node); -} - -#ifdef JSON_MEMORY_MANAGE - MIR_CORE_DLL(void) json_free_all(void){ - StringHandler.clear(); - } - - MIR_CORE_DLL(void) json_delete_all(void){ - NodeHandler.clear(); - } -#endif - -MIR_CORE_DLL(JSONNODE*) json_parse(const json_char *json){ - JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_parse"), return 0;); - try { - //use this constructor to simply copy reference instead of copying the temp - return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(JSONWorker::parse(json))); - } catch (std::invalid_argument){} - return 0; -} - -MIR_CORE_DLL(TCHAR*) json_strip_white_space(const json_char *json){ - JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_strip_white_space"), return 0;); - return toCString(JSONWorker::RemoveWhiteSpaceAndComments(json)); -} - -#ifdef JSON_VALIDATE - MIR_CORE_DLL(JSONNODE*) json_validate(const json_char *json){ - JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_validate"), return 0;); - try { - //use this constructor to simply copy reference instead of copying the temp - return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(JSONWorker::validate(json))); - } catch (std::invalid_argument){} - return 0; - } -#endif - -#if defined JSON_DEBUG && !defined JSON_STDERROR - //When libjson errors, a callback allows the user to know what went wrong - MIR_CORE_DLL(void) json_register_debug_callback(json_error_callback_t callback){ - JSONDebug::register_callback(callback); - } -#endif - -#ifdef JSON_MUTEX_CALLBACKS - #ifdef JSON_MUTEX_MANAGE - MIR_CORE_DLL(void) json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, json_mutex_callback_t destroy, void * manager_lock){ - JSONNode::register_mutex_callbacks(lock, unlock, manager_lock); - JSONNode::register_mutex_destructor(destroy); - } - - #else - MIR_CORE_DLL(void) json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock){ - JSONNode::register_mutex_callbacks(lock, unlock, manager_lock); - } - #endif - - MIR_CORE_DLL(void) json_set_global_mutex(void * mutex){ - JSONNode::set_global_mutex(mutex); - } - - MIR_CORE_DLL(void) json_set_mutex(JSONNODE *node, void * mutex){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_mutex"), return;); - ((JSONNode*)node) -> set_mutex(mutex); - } - - MIR_CORE_DLL(void) json_lock(JSONNODE *node, int threadid){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_lock"), return;); - ((JSONNode*)node) -> lock(threadid); - } - - MIR_CORE_DLL(void) json_unlock(JSONNODE *node, int threadid){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_unlock"), return;); - ((JSONNode*)node) -> unlock(threadid); - } -#endif - -/* -stuff that's in class JSONNode -*/ -//ctors -MIR_CORE_DLL(JSONNODE*) json_new_a(const json_char *name, const json_char *value){ - JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_a"), name = EMPTY_CSTRING;); - JSON_ASSERT_SAFE(value, JSON_TEXT("null value to json_new_a"), value = EMPTY_CSTRING;); - #ifdef JSON_MEMORY_CALLBACKS - return MANAGER_INSERT(new(json_malloc(1)) JSONNode(name, json_string(value))); - #else - return MANAGER_INSERT(new JSONNode(name, json_string(value))); - #endif -} - -MIR_CORE_DLL(JSONNODE*) json_new_i(const json_char *name, long value){ - JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_i"), name = EMPTY_CSTRING;); - #ifdef JSON_MEMORY_CALLBACKS - return MANAGER_INSERT(new(json_malloc(1)) JSONNode(name, value)); - #else - return MANAGER_INSERT(new JSONNode(name, value)); - #endif -} - -MIR_CORE_DLL(JSONNODE*) json_new_f(const json_char *name, double value){ - JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_f"), name = EMPTY_CSTRING;); - #ifdef JSON_MEMORY_CALLBACKS - return MANAGER_INSERT(new(json_malloc(1)) JSONNode(name, value)); - #else - return MANAGER_INSERT(new JSONNode(name, value)); - #endif -} - -MIR_CORE_DLL(JSONNODE*) json_new_b(const json_char *name, int value){ - JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_b"), name = EMPTY_CSTRING;); - #ifdef JSON_MEMORY_CALLBACKS - return MANAGER_INSERT(new(json_malloc(1)) JSONNode(name, value != 0 )); - #else - return MANAGER_INSERT(new JSONNode(name, value != 0)); - #endif -} - -MIR_CORE_DLL(JSONNODE*) json_new(char type){ - #ifdef JSON_MEMORY_CALLBACKS - return MANAGER_INSERT(new(json_malloc(1)) JSONNode(type)); - #else - return MANAGER_INSERT(new JSONNode(type)); - #endif -} - -MIR_CORE_DLL(JSONNODE*) json_copy(const JSONNODE *orig){ - JSON_ASSERT_SAFE(orig, JSON_TEXT("null orig to json_copy"), return 0;); - #ifdef JSON_MEMORY_CALLBACKS - return MANAGER_INSERT(new(json_malloc(1)) JSONNode(*((JSONNode*)orig))); - #else - return MANAGER_INSERT(new JSONNode(*((JSONNode*)orig))); - #endif -} - -MIR_CORE_DLL(JSONNODE*) json_duplicate(const JSONNODE *orig){ - JSON_ASSERT_SAFE(orig, JSON_TEXT("null orig to json_duplicate"), return 0;); - return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(((JSONNode*)orig) -> duplicate())); -} - -//assignment -MIR_CORE_DLL(void) json_set_a(JSONNODE *node, const json_char *value){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_a"), return;); - JSON_ASSERT_SAFE(value, JSON_TEXT("null value to json_set_a"), value = EMPTY_CSTRING;); - *((JSONNode*)node) = json_string(value); -} - -MIR_CORE_DLL(void) json_set_i(JSONNODE *node, long value){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_i"), return;); - *((JSONNode*)node) = value; -} - -MIR_CORE_DLL(void) json_set_f(JSONNODE *node, double value){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_f"), return;); - *((JSONNode*)node) = value; -} - -MIR_CORE_DLL(void) json_set_b(JSONNODE *node, int value){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_b"), return;); - *((JSONNode*)node) = value != 0; -} - -MIR_CORE_DLL(void) json_set_n(JSONNODE *node, const JSONNODE *orig){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_n"), return;); - JSON_ASSERT_SAFE(orig, JSON_TEXT("null node to json_set_n"), return;); - *((JSONNode*)node) = *((JSONNode*)orig); -} - -//inspectors -MIR_CORE_DLL(char) json_type(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_type"), return JSON_NULL;); - return ((JSONNode*)node) -> type(); -} - -MIR_CORE_DLL(json_index_t) json_size(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_size"), return 0;); - return ((JSONNode*)node) -> size(); -} - -MIR_CORE_DLL(int) json_empty(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_empty"), return true;); - return (int)(((JSONNode*)node) -> empty()); -} - -MIR_CORE_DLL(const json_char*) json_name(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_name"), return EMPTY_CSTRING;); - return ((JSONNode*)node) -> name(); -} - -#ifdef JSON_COMMENTS - MIR_CORE_DLL(json_char*) json_get_comment(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_get_comment"), return toCString(EMPTY_CSTRING);); - return toCString(((JSONNode*)node) -> get_comment()); - } -#endif - -MIR_CORE_DLL(TCHAR*) json_as_string(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_string"), return toCString(EMPTY_CSTRING);); - return toCString(((JSONNode*)node) -> as_string()); -} - -MIR_C_CORE_DLL(std::string) json_as_pstring(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_string"), return EMPTY_CSTRING;); - return ((JSONNode*)node) -> as_string(); -} - -MIR_CORE_DLL(long) json_as_int(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_int"), return 0;); - return ((JSONNode*)node) -> as_int(); -} - -MIR_CORE_DLL(double) json_as_float(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_float"), return 0.0;); - return ((JSONNode*)node) -> as_float(); -} - -MIR_CORE_DLL(int) json_as_bool(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_bool"), return false;); - return (int)(((JSONNode*)node) -> as_bool()); -} - -MIR_CORE_DLL(JSONNODE*) json_as_node(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_node"), return 0;); - return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(((JSONNode*)node) -> as_node())); -} - -MIR_CORE_DLL(JSONNODE*) json_as_array(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_array"), return 0;); - return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(((JSONNode*)node) -> as_array())); -} - -#ifdef JSON_BINARY - void * json_as_binary(const JSONNODE *node, unsigned long * size){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_binary"), if (size){*size = 0;} return 0;); - const std::string result = ((JSONNode*)node) -> as_binary(); - const size_t len = result.length(); - if (size) *size = len; - #ifdef JSON_SAFE - if (result.empty()) return 0; - #endif - #ifdef JSON_MEMORY_MANAGE - return StringHandler.insert(memcpy(json_malloc(len), result.data(), len)); - #else - return memcpy(json_malloc(len), result.data(), len); - #endif - } -#endif - -#ifdef JSON_WRITER - MIR_CORE_DLL(TCHAR*) json_write(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_write"), return toCString(EMPTY_CSTRING);); - return toCString(((JSONNode*)node) -> write()); - } - - MIR_CORE_DLL(TCHAR*) json_write_formatted(const JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_write_formatted"), return toCString(EMPTY_CSTRING);); - return toCString(((JSONNode*)node) -> write_formatted()); - } -#endif - -//modifiers -MIR_CORE_DLL(void) json_set_name(JSONNODE *node, const json_char *name){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_name"), return;); - JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_set_name"), name = EMPTY_CSTRING;); - ((JSONNode*)node) -> set_name(name); -} - -#ifdef JSON_COMMENTS - MIR_CORE_DLL(void) json_set_comment(JSONNODE *node, const json_char * comment){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_comment"), return;); - JSON_ASSERT_SAFE(comment, JSON_TEXT("null name to json_set_comment"), comment = EMPTY_CSTRING;); - ((JSONNode*)node) -> set_comment(comment); - } -#endif - -MIR_CORE_DLL(void) json_clear(JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_clear"), return;); - ((JSONNode*)node) -> clear(); -} - -MIR_CORE_DLL(void) json_nullify(JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_nullify"), return;); - ((JSONNode*)node) -> nullify(); -} - -MIR_CORE_DLL(void) json_swap(JSONNODE *node, JSONNODE *node2){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_swap"), return;); - JSON_ASSERT_SAFE(node2, JSON_TEXT("null node to json_swap"), return;); - ((JSONNode*)node) -> swap(*(JSONNode*)node2); -} - -MIR_CORE_DLL(void) json_merge(JSONNODE *node, JSONNODE *node2){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_merge"), return;); - JSON_ASSERT_SAFE(node2, JSON_TEXT("null node to json_merge"), return;); - ((JSONNode*)node) -> merge(*(JSONNode*)node2); -} - -#ifndef JSON_PREPARSE - MIR_CORE_DLL(void) json_preparse(JSONNODE *node){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_preparse"), return;); - ((JSONNode*)node) -> preparse(); - } -#endif - -#ifdef JSON_BINARY - MIR_CORE_DLL(void) json_set_binary(JSONNODE *node, const void * data, unsigned long length){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_swap"), return;); - JSON_ASSERT_SAFE(data, JSON_TEXT("null data to json_set_binary"), *((JSONNode*)node) = EMPTY_CSTRING; return;); - ((JSONNode*)node) -> set_binary((unsigned char *)data, length); - } -#endif - -MIR_CORE_DLL(void) json_cast(JSONNODE *node, char type){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_cast"), return;); - ((JSONNode*)node) -> cast(type); -} - -//children access -MIR_CORE_DLL(void) json_reserve(JSONNODE *node, json_index_t siz){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_reserve"), return;); - ((JSONNode*)node) -> reserve(siz); -} - -MIR_CORE_DLL(JSONNODE*) json_at(JSONNODE *node, json_index_t pos){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_at"), return 0;); - try { - return &((JSONNode*)node) -> at(pos); - } catch (std::out_of_range){} - return 0; -} - -MIR_CORE_DLL(JSONNODE*) json_get(JSONNODE *node, const json_char *name){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_get"), return 0;); - JSON_ASSERT_SAFE(name, JSON_TEXT("null node to json_get. Did you mean to use json_at?"), return 0;); - try { - return &((JSONNode*)node) -> at(name); - } catch (std::out_of_range){} - return 0; -} - -#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS - MIR_CORE_DLL(JSONNODE*) json_get_nocase(JSONNODE *node, const json_char *name){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_at_nocase"), return 0;); - JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_at_nocase"), return 0;); - try { - return &((JSONNode*)node) -> at_nocase(name); - } catch (std::out_of_range){} - return 0; - } - - MIR_CORE_DLL(JSONNODE*) json_pop_back_nocase(JSONNODE *node, const json_char *name){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_pop_back_nocase"), return 0;); - JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_pop_back_nocase"), return 0;); - return MANAGER_INSERT(((JSONNode*)node) -> pop_back_nocase(name)); - } -#endif - -MIR_CORE_DLL(void) json_push_back(JSONNODE *node, JSONNODE *node2){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_push_back"), return;); - JSON_ASSERT_SAFE(node2, JSON_TEXT("null node2 to json_push_back"), return;); - #ifdef JSON_MEMORY_MANAGE - NodeHandler.remove(node2); - #endif - ((JSONNode*)node) -> push_back((JSONNode*)node2); -} - -MIR_CORE_DLL(JSONNODE*) json_pop_back_at(JSONNODE *node, json_index_t pos){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_pop_back_i"), return 0;); - return MANAGER_INSERT(((JSONNode*)node) -> pop_back(pos)); -} - -MIR_CORE_DLL(JSONNODE*) json_pop_back(JSONNODE *node, const json_char *name){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_pop_back"), return 0;); - JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_pop_back. Did you mean to use json_pop_back_at?"), return 0;); - return MANAGER_INSERT(((JSONNode*)node) -> pop_back(name)); -} - -//comparison -MIR_CORE_DLL(int) json_equal(JSONNODE *node, JSONNODE *node2){ - JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_equal"), return false;); - JSON_ASSERT_SAFE(node2, JSON_TEXT("null node2 to json_equal"), return false;); - return (int)(*((JSONNode*)node) == *((JSONNode*)node2)); -} diff --git a/src/mir_core/langpack.cpp b/src/mir_core/langpack.cpp deleted file mode 100644 index 29f633bc45..0000000000 --- a/src/mir_core/langpack.cpp +++ /dev/null @@ -1,734 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" -#include "../modules/langpack/langpack.h" - -#define LANGPACK_BUF_SIZE 4000 - -static int CompareMuuids(const MUUID *p1, const MUUID *p2) -{ - return memcmp(p1, p2, sizeof(MUUID)); -} - -static LIST lMuuids(10, CompareMuuids); -static MUUID *pCurrentMuuid = NULL; -static HANDLE hevChanged = 0; - -static BOOL bModuleInitialized = FALSE; - -struct LangPackEntry -{ - DWORD englishHash; - char *szLocal; - wchar_t *wszLocal; - MUUID *pMuuid; - LangPackEntry* pNext; // for langpack items with the same hash value -}; - -static LANGPACK_INFO langPack; -static TCHAR g_tszRoot[MAX_PATH]; - -static LangPackEntry *g_pEntries; -static int g_entryCount, g_entriesAlloced; - -static int IsEmpty(const char *str) -{ - for (int i = 0; str[i]; i++) - if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') - return 0; - - return 1; -} - -static int ConvertBackslashes(char *str, UINT fileCp) -{ - int shift = 0; - char *pstr; - for (pstr = str; *pstr; pstr = CharNextExA(fileCp, pstr, 0)) { - if (*pstr == '\\') { - shift++; - switch (pstr[1]) { - case 'n': *pstr = '\n'; break; - case 't': *pstr = '\t'; break; - case 'r': *pstr = '\r'; break; - case 's': *pstr = ' '; break; - default: *pstr = pstr[1]; break; - } - memmove(pstr + 1, pstr + 2, strlen(pstr + 2) + 1); - } - } - return shift; -} - -#ifdef _DEBUG -//#pragma optimize("gt", on) -#endif - -// MurmurHash2 -MIR_CORE_DLL(unsigned int) mir_hash(const void * key, unsigned int len) -{ - // 'm' and 'r' are mixing constants generated offline. - // They're not really 'magic', they just happen to work well. - const unsigned int m = 0x5bd1e995; - const int r = 24; - - // Initialize the hash to a 'random' value - unsigned int h = len; - - // Mix 4 bytes at a time into the hash - const unsigned char *data = (const unsigned char*)key; - - while (len >= 4) { - unsigned int k = *(unsigned int*)data; - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - data += 4; - len -= 4; - } - - // Handle the last few bytes of the input array - switch (len) { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; - h *= m; - } - - // Do a few final mixes of the hash to ensure the last few - // bytes are well-incorporated. - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} - -static unsigned int __fastcall hashstrW(const char *key) -{ - if (key == NULL) return 0; - const unsigned int len = (unsigned int)wcslen((const wchar_t*)key); - char *buf = (char*)alloca(len + 1); - for (unsigned i = 0; i <= len; ++i) - buf[i] = key[i << 1]; - return mir_hash(buf, len); -} - -static int SortLangPackHashesProc(LangPackEntry *arg1, LangPackEntry *arg2) -{ - if (arg1->englishHash < arg2->englishHash) return -1; - if (arg1->englishHash > arg2->englishHash) return 1; - - return (arg1->pMuuid < arg2->pMuuid) ? -1 : 1; -} - -static void swapBytes(void *p, size_t iSize) -{ - char *head = (char*)p; // here - char *tail = head + iSize - 1; - - for (; tail > head; --tail, ++head) { - char temp = *head; - *head = *tail; - *tail = temp; - } -} - -static bool EnterMuuid(const char *p, MUUID &result) -{ - if (*p++ != '{') - return false; - - BYTE *d = (BYTE*)&result; - - for (int nBytes = 0; *p && nBytes < 24; p++) { - if (*p == '-') - continue; - - if (*p == '}') - break; - - if (!isxdigit(*p)) - return false; - - if (!isxdigit(p[1])) - return false; - - int c = 0; - if (sscanf(p, "%2x", &c) != 1) - return false; - - *d++ = (BYTE)c; - nBytes++; - p++; - } - - if (*p != '}') - return false; - - swapBytes(&result.a, sizeof(result.a)); - swapBytes(&result.b, sizeof(result.b)); - swapBytes(&result.c, sizeof(result.c)); - return true; -} - -static void LoadLangPackFile(FILE *fp, char *line) -{ - while (!feof(fp)) { - if (fgets(line, LANGPACK_BUF_SIZE, fp) == NULL) - break; - - if (IsEmpty(line) || line[0] == ';' || line[0] == 0) - continue; - - rtrim(line); - - if (line[0] == '#') { - strlwr(line); - - if (!memcmp(line + 1, "include", 7)) { - TCHAR tszFileName[MAX_PATH]; - TCHAR *p = _tcsrchr(langPack.tszFullPath, '\\'); - if (p) - *p = 0; - mir_sntprintf(tszFileName, SIZEOF(tszFileName), _T("%s\\%S"), langPack.tszFullPath, ltrim(line + 9)); - if (p) - *p = '\\'; - - FILE *fp = _tfopen(tszFileName, _T("r")); - if (fp) { - line[0] = 0; - fgets(line, LANGPACK_BUF_SIZE, fp); - - if (strlen(line) >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf') - fseek(fp, 3, SEEK_SET); - else - fseek(fp, 0, SEEK_SET); - - LoadLangPackFile(fp, line); - fclose(fp); - } - } - else if (!memcmp(line + 1, "muuid", 5)) { - MUUID t; - if (!EnterMuuid(line + 7, t)) - continue; - - MUUID *pNew = (MUUID*)mir_alloc(sizeof(MUUID)); - memcpy(pNew, &t, sizeof(t)); - lMuuids.insert(pNew); - pCurrentMuuid = pNew; - } - - continue; - } - - char cFirst = line[0]; - - ConvertBackslashes(line, CP_UTF8); - - size_t cbLen = strlen(line) - 1; - if (cFirst == '[' && line[cbLen] == ']') { - if (g_entryCount && g_pEntries[g_entryCount-1].wszLocal == NULL) - g_entryCount--; - - char *pszLine = line + 1; - line[cbLen] = '\0'; - if (++g_entryCount > g_entriesAlloced) { - g_entriesAlloced += 128; - g_pEntries = (LangPackEntry*)mir_realloc(g_pEntries, sizeof(LangPackEntry)*g_entriesAlloced); - } - - LangPackEntry *E = &g_pEntries[g_entryCount - 1]; - E->englishHash = mir_hashstr(pszLine); - E->szLocal = NULL; - E->wszLocal = NULL; - E->pMuuid = pCurrentMuuid; - E->pNext = NULL; - continue; - } - - if (!g_entryCount) - continue; - - LangPackEntry *E = &g_pEntries[g_entryCount - 1]; - int iNeeded = MultiByteToWideChar(CP_UTF8, 0, line, -1, 0, 0), iOldLen; - if (E->wszLocal == NULL) { - iOldLen = 0; - E->wszLocal = (wchar_t *)mir_alloc((iNeeded + 1) * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, line, -1, E->wszLocal, iNeeded); - } - else { - iOldLen = (int)wcslen(E->wszLocal); - E->wszLocal = (wchar_t*)mir_realloc(E->wszLocal, (sizeof(wchar_t)* (iOldLen + iNeeded + 2))); - E->wszLocal[iOldLen++] = '\n'; - } - MultiByteToWideChar(CP_UTF8, 0, line, -1, E->wszLocal + iOldLen, iNeeded); - } -} - -static int LoadLangDescr(LANGPACK_INFO &lpinfo, FILE *fp, char *line, int &startOfLine) -{ - char szLanguage[64]; szLanguage[0] = 0; - CMStringA szAuthors; - - lpinfo.codepage = CP_ACP; - lpinfo.flags = 0; - - fgets(line, LANGPACK_BUF_SIZE, fp); - size_t lineLen = strlen(line); - if (lineLen >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf') - memmove(line, line + 3, lineLen - 2); - - lrtrim(line); - if (mir_strcmp(line, "Miranda Language Pack Version 1")) - return 2; - - // headers - while (!feof(fp)) { - startOfLine = ftell(fp); - if (fgets(line, LANGPACK_BUF_SIZE, fp) == NULL) - break; - - lrtrim(line); - if (IsEmpty(line) || line[0] == ';' || line[0] == 0) - continue; - - if (line[0] == '[' || line[0] == '#') - break; - - char *pszColon = strchr(line, ':'); - if (pszColon == NULL) - return 3; - - *pszColon++ = 0; - if (!mir_strcmp(line, "Language")) { - strncpy_s(szLanguage, pszColon, _TRUNCATE); - lrtrim(szLanguage); - } - else if (!mir_strcmp(line, "Last-Modified-Using")) { - lpinfo.szLastModifiedUsing = pszColon; - lpinfo.szLastModifiedUsing.Trim(); - } - else if (!mir_strcmp(line, "Authors")) { - if (!szAuthors.IsEmpty()) - szAuthors.AppendChar(' '); - szAuthors.Append(lrtrim(pszColon)); - } - else if (!mir_strcmp(line, "Author-email")) { - lpinfo.szAuthorEmail = pszColon; - lpinfo.szAuthorEmail.Trim(); - } - else if (!mir_strcmp(line, "Locale")) { - char szBuf[20], *stopped; - - lrtrim(pszColon + 1); - USHORT langID = (USHORT)strtol(pszColon, &stopped, 16); - lpinfo.Locale = MAKELCID(langID, 0); - GetLocaleInfoA(lpinfo.Locale, LOCALE_IDEFAULTANSICODEPAGE, szBuf, 10); - szBuf[5] = 0; // codepages have max. 5 digits - lpinfo.codepage = atoi(szBuf); - } - } - - lpinfo.szAuthors = szAuthors; - - MultiByteToWideChar(lpinfo.codepage, 0, szLanguage, -1, lpinfo.tszLanguage, SIZEOF(lpinfo.tszLanguage)); - - if (!lpinfo.tszLanguage[0] && (lpinfo.Locale == 0) || !GetLocaleInfo(lpinfo.Locale, LOCALE_SENGLANGUAGE, lpinfo.tszLanguage, sizeof(lpinfo.tszLanguage))) { - TCHAR *p = _tcschr(lpinfo.tszFileName, '_'); - _tcsncpy_s(lpinfo.tszLanguage, ((p != NULL) ? (p + 1) : lpinfo.tszFileName), _TRUNCATE); - p = _tcsrchr(lpinfo.tszLanguage, _T('.')); - if (p != NULL) *p = '\0'; - } - return 0; -} - -MIR_CORE_DLL(int) LoadLangPack(const TCHAR *ptszLangPack) -{ - if (ptszLangPack == NULL || !mir_tstrcmpi(ptszLangPack, _T(""))) - return 1; - - // ensure that a lang's name is a full file name - TCHAR tszFullPath[MAX_PATH]; - if (!PathIsAbsoluteT(ptszLangPack)) - mir_sntprintf(tszFullPath, SIZEOF(tszFullPath), _T("%s\\%s"), g_tszRoot, ptszLangPack); - else - _tcsncpy_s(tszFullPath, ptszLangPack, _TRUNCATE); - - // this lang is already loaded? nothing to do then - if (!mir_tstrcmp(tszFullPath, langPack.tszFullPath)) - return 0; - - // ok... loading a new langpack. remove the old one if needed - if (g_entryCount) - UnloadLangPackModule(); - - // exists & not a directory? - DWORD dwAttrib = GetFileAttributes(tszFullPath); - if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) - return 3; - - // copy the full file name and extract a file name from it - _tcsncpy_s(langPack.tszFullPath, tszFullPath, _TRUNCATE); - TCHAR *p = _tcsrchr(langPack.tszFullPath, '\\'); - _tcsncpy_s(langPack.tszFileName, (p == NULL) ? tszFullPath : p + 1, _TRUNCATE); - CharLower(langPack.tszFileName); - - FILE *fp = _tfopen(tszFullPath, _T("rt")); - if (fp == NULL) - return 1; - - char line[LANGPACK_BUF_SIZE] = ""; - int startOfLine = 0; - if (LoadLangDescr(langPack, fp, line, startOfLine)) { - fclose(fp); - return 1; - } - - // body - fseek(fp, startOfLine, SEEK_SET); - - LoadLangPackFile(fp, line); - fclose(fp); - pCurrentMuuid = NULL; - - qsort(g_pEntries, g_entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc); - return 0; -} - -MIR_CORE_DLL(int) LoadLangPackDescr(const TCHAR *ptszLangPack, LANGPACK_INFO *lpInfo) -{ - if (lpInfo == NULL) - return 1; - - _tcsncpy_s(lpInfo->tszFullPath, ptszLangPack, _TRUNCATE); - TCHAR *p = _tcsrchr(lpInfo->tszFullPath, '\\'); - _tcsncpy_s(lpInfo->tszFileName, (p == NULL) ? ptszLangPack : p+1, _TRUNCATE); - CharLower(lpInfo->tszFileName); - - FILE *fp = _tfopen(ptszLangPack, _T("rt")); - if (fp == NULL) - return 1; - - char line[LANGPACK_BUF_SIZE] = ""; - int startOfLine = 0; - int res = LoadLangDescr(*lpInfo, fp, line, startOfLine); - fclose(fp); - return res; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static int SortLangPackHashesProc2(LangPackEntry *arg1, LangPackEntry *arg2) -{ - if (arg1->englishHash < arg2->englishHash) return -1; - if (arg1->englishHash > arg2->englishHash) return 1; - return 0; -} - -static char *LangPackTranslateString(MUUID *pUuid, const char *szEnglish, const int W) -{ - if (g_entryCount == 0 || szEnglish == NULL) - return (char*)szEnglish; - - LangPackEntry key, *entry; - key.englishHash = W ? hashstrW(szEnglish) : mir_hashstr(szEnglish); - entry = (LangPackEntry*)bsearch(&key, g_pEntries, g_entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc2); - if (entry == NULL) - return (char*)szEnglish; - - // try to find the exact match, otherwise the first entry will be returned - if (pUuid) { - for (LangPackEntry *p = entry->pNext; p != NULL; p = p->pNext) { - if (p->pMuuid == pUuid) { - entry = p; - break; - } - } - } - - if (W) - return (char*)entry->wszLocal; - - if (entry->szLocal == NULL && entry->wszLocal != NULL) - entry->szLocal = mir_u2a_cp(entry->wszLocal, langPack.codepage); - return entry->szLocal; -} - -MIR_CORE_DLL(int) Langpack_GetDefaultCodePage() -{ - return langPack.codepage; -} - -MIR_CORE_DLL(int) Langpack_GetDefaultLocale() -{ - return (langPack.Locale == 0) ? LOCALE_USER_DEFAULT : langPack.Locale; -} - -MIR_CORE_DLL(TCHAR*) Langpack_PcharToTchar(const char *pszStr) -{ - if (pszStr == NULL) - return NULL; - - int len = (int)strlen(pszStr); - TCHAR *result = (TCHAR*)alloca((len + 1)*sizeof(TCHAR)); - MultiByteToWideChar(Langpack_GetDefaultCodePage(), 0, pszStr, -1, result, len); - result[len] = 0; - return mir_wstrdup(TranslateW(result)); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(char*) TranslateA_LP(const char *str, int hLangpack) -{ - return (char*)LangPackTranslateString(Langpack_LookupUuid(hLangpack), str, FALSE); -} - -MIR_CORE_DLL(WCHAR*) TranslateW_LP(const WCHAR *str, int hLangpack) -{ - return (WCHAR*)LangPackTranslateString(Langpack_LookupUuid(hLangpack), (LPCSTR)str, TRUE); -} - -MIR_CORE_DLL(void) TranslateMenu_LP(HMENU hMenu, int hLangpack) -{ - MUUID *uuid = Langpack_LookupUuid(hLangpack); - - MENUITEMINFO mii = { sizeof(mii) }; - for (int i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) { - TCHAR str[256]; - mii.fMask = MIIM_TYPE | MIIM_SUBMENU; - mii.dwTypeData = (TCHAR*)str; - mii.cch = SIZEOF(str); - GetMenuItemInfo(hMenu, i, TRUE, &mii); - - if (mii.cch && mii.dwTypeData) { - TCHAR *result = (TCHAR*)LangPackTranslateString(uuid, (const char*)mii.dwTypeData, TRUE); - if (result != mii.dwTypeData) { - mii.dwTypeData = result; - mii.fMask = MIIM_TYPE; - SetMenuItemInfo(hMenu, i, TRUE, &mii); - } - } - - if (mii.hSubMenu != NULL) - TranslateMenu_LP(mii.hSubMenu, hLangpack); - } -} - -static void TranslateWindow(MUUID *pUuid, HWND hwnd) -{ - TCHAR title[2048]; - GetWindowText(hwnd, title, SIZEOF(title)); - - TCHAR *result = (TCHAR*)LangPackTranslateString(pUuid, (const char*)title, TRUE); - if (result != title) - SetWindowText(hwnd, result); -} - -struct LANGPACKTRANSLATEDIALOG -{ - HWND hwndDlg; - int hLangpack; -}; - -static BOOL CALLBACK TranslateDialogEnumProc(HWND hwnd, LPARAM lParam) -{ - int hLangpack = (int)lParam; - TCHAR szClass[32]; - int id = GetDlgCtrlID(hwnd); - - MUUID *uuid = Langpack_LookupUuid(hLangpack); - - GetClassName(hwnd, szClass, SIZEOF(szClass)); - if (!mir_tstrcmpi(szClass, _T("static")) || !mir_tstrcmpi(szClass, _T("hyperlink")) || !mir_tstrcmpi(szClass, _T("button")) || !mir_tstrcmpi(szClass, _T("MButtonClass")) || !mir_tstrcmpi(szClass, _T("MHeaderbarCtrl"))) - TranslateWindow(uuid, hwnd); - else if (!mir_tstrcmpi(szClass, _T("edit"))) { - if (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY) - TranslateWindow(uuid, hwnd); - } - return TRUE; -} - -MIR_CORE_DLL(void) TranslateDialog_LP(HWND hDlg, int hLangpack) -{ - TranslateWindow(Langpack_LookupUuid(hLangpack), hDlg); - EnumChildWindows(hDlg, TranslateDialogEnumProc, hLangpack); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(MUUID*) Langpack_LookupUuid(WPARAM wParam) -{ - int idx = (wParam >> 16) & 0xFFFF; - return (idx > 0 && idx <= lMuuids.getCount()) ? lMuuids[idx - 1] : NULL; -} - -MIR_CORE_DLL(int) Langpack_MarkPluginLoaded(PLUGININFOEX *pInfo) -{ - int idx = lMuuids.getIndex(&pInfo->uuid); - if (idx == -1) - return 0; - - return (idx + 1) << 16; -} - -MIR_CORE_DLL(void) Langpack_SortDuplicates(void) -{ - if (g_entryCount == 0) - return; - - LangPackEntry *s = g_pEntries + 1, *d = s, *pLast = g_pEntries; - DWORD dwSavedHash = g_pEntries->englishHash; - bool bSortNeeded = false; - - for (int i = 1; i < g_entryCount; i++, s++) { - if (s->englishHash != dwSavedHash) { - pLast = d; - if (s != d) - *d++ = *s; - else - d++; - dwSavedHash = s->englishHash; - } - else { - bSortNeeded = true; - LangPackEntry *p = (LangPackEntry*)mir_alloc(sizeof(LangPackEntry)); - *p = *s; - pLast->pNext = p; pLast = p; - } - } - - if (bSortNeeded) { - g_entryCount = (int)(d - g_pEntries); - qsort(g_pEntries, g_entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -TCHAR tszDefaultLang[100]; - -void GetDefaultLang() -{ - // calculate the langpacks' root - PathToAbsoluteT(_T("\\Languages"), g_tszRoot); - if (_taccess(g_tszRoot, 0) != 0) // directory Languages exists - PathToAbsoluteT(_T("."), g_tszRoot); - - // look into mirandaboot.ini - TCHAR tszPath[MAX_PATH]; - PathToAbsoluteT(_T("\\mirandaboot.ini"), tszPath); - GetPrivateProfileString(_T("Language"), _T("DefaultLanguage"), _T(""), tszDefaultLang, SIZEOF(tszDefaultLang), tszPath); - - if (!mir_tstrcmpi(tszDefaultLang, _T("default"))) { - db_set_ts(NULL, "Langpack", "Current", _T("default")); - return; - } - else if (!LoadLangPack(tszDefaultLang)) { - db_set_ts(NULL, "Langpack", "Current", tszDefaultLang); - return; - } - - // finally try to load first file - mir_sntprintf(tszPath, SIZEOF(tszPath), _T("%s\\langpack_*.txt"), g_tszRoot); - - WIN32_FIND_DATA fd; - HANDLE hFind = FindFirstFile(tszPath, &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - /* search first langpack that could be loaded */ - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - continue; - - if (!LoadLangPack(fd.cFileName)) { - db_set_ts(NULL, "Langpack", "Current", fd.cFileName); - break; - } - } while (FindNextFile(hFind, &fd)); - FindClose(hFind); - } else - db_set_ts(NULL, "Langpack", "Current", _T("default")); -} - -MIR_CORE_DLL(int) LoadLangPackModule(void) -{ - bModuleInitialized = TRUE; - hevChanged = CreateHookableEvent(ME_LANGPACK_CHANGED); - GetDefaultLang(); - return 0; -} - -void UnloadLangPackModule() -{ - if (!bModuleInitialized) return; - - int i; - for (i = 0; i < lMuuids.getCount(); i++) - mir_free(lMuuids[i]); - lMuuids.destroy(); - - LangPackEntry *p = g_pEntries; - for (i = 0; i < g_entryCount; i++, p++) { - if (p->pNext != NULL) { - for (LangPackEntry *p1 = p->pNext; p1 != NULL;) { - LangPackEntry *p2 = p1; p1 = p1->pNext; - mir_free(p2->szLocal); - mir_free(p2->wszLocal); - mir_free(p2); - } - } - - mir_free(p->szLocal); - mir_free(p->wszLocal); - } - - if (g_entryCount) { - mir_free(g_pEntries); - g_pEntries = 0; - g_entryCount = g_entriesAlloced = 0; - } - - langPack.tszFileName[0] = langPack.tszFullPath[0] = 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(void) ReloadLangpack(TCHAR *pszStr) -{ - if (pszStr == NULL) - pszStr = NEWTSTR_ALLOCA(langPack.tszFileName); - - UnloadLangPackModule(); - LoadLangPack(pszStr); - Langpack_SortDuplicates(); - - NotifyEventHooks(hevChanged, 0, 0); -} diff --git a/src/mir_core/lists.cpp b/src/mir_core/lists.cpp deleted file mode 100644 index f981927cd8..0000000000 --- a/src/mir_core/lists.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -/* a simple sorted list implementation */ - -MIR_CORE_DLL(SortedList*) List_Create(int p_limit, int p_increment) -{ - SortedList* result = (SortedList*)mir_calloc(sizeof(SortedList)); - if (result == NULL) - return(NULL); - - result->increment = p_increment; - result->limit = p_limit; - return result; -} - -MIR_CORE_DLL(void) List_Destroy(SortedList* p_list) -{ - if (p_list == NULL) - return; - - if (p_list->items != NULL) { - mir_free(p_list->items); - p_list->items = NULL; - } - - p_list->realCount = p_list->limit = 0; -} - -MIR_CORE_DLL(void*) List_Find(SortedList* p_list, void* p_value) -{ - int idx; - if (!List_GetIndex(p_list, p_value, &idx)) - return NULL; - - return p_list->items[idx]; -} - -#ifdef _DEBUG -#pragma optimize("gt", on) -#endif - -MIR_CORE_DLL(int) List_GetIndex(SortedList* p_list, void* p_value, int* p_index) -{ - if (p_value == NULL || p_list->sortFunc == NULL) { - *p_index = -1; - return 0; - } - - int low = 0; - int high = p_list->realCount - 1; - - switch ((INT_PTR)p_list->sortFunc) { - case HandleKeySort: - #ifdef _WIN64 - { - const unsigned __int64 val = *(unsigned __int64 *)p_value; - - while (low <= high) { - int i = (low + high) / 2; - unsigned __int64 vali = *(unsigned __int64 *)p_list->items[i]; - if (vali == val) { - *p_index = i; - return 1; - } - - if (vali < val) - low = i + 1; - else - high = i - 1; - } - } - break; - #endif - - case NumericKeySort: - { - const unsigned val = *(unsigned *)p_value; - - while (low <= high) { - int i = (low + high) / 2; - unsigned vali = *(unsigned *)p_list->items[i]; - if (vali == val) { - *p_index = i; - return 1; - } - - if (vali < val) - low = i + 1; - else - high = i - 1; - } - } - break; - - case PtrKeySort: - while (low <= high) { - int i = (low + high) / 2; - const void* vali = p_list->items[i]; - if (vali == p_value) { - *p_index = i; - return 1; - } - - if (vali < p_value) - low = i + 1; - else - high = i - 1; - } - break; - - default: - while (low <= high) { - int i = (low + high) / 2; - int result = p_list->sortFunc(p_list->items[i], p_value); - if (result == 0) { - *p_index = i; - return 1; - } - - if (result < 0) - low = i + 1; - else - high = i - 1; - } - break; - } - - *p_index = low; - return 0; -} - -MIR_CORE_DLL(int) List_IndexOf(SortedList* p_list, void* p_value) -{ - if (p_value == NULL) - return -1; - - for (int i = 0; i < p_list->realCount; i++) - if (p_list->items[i] == p_value) - return i; - - return -1; -} - -#ifdef _DEBUG -#pragma optimize("", on) -#endif - -MIR_CORE_DLL(int) List_Insert(SortedList* p_list, void* p_value, int p_index) -{ - if (p_value == NULL || p_index > p_list->realCount) - return 0; - - if (p_list->realCount == p_list->limit) { - p_list->items = (void**)mir_realloc(p_list->items, sizeof(void*)*(p_list->realCount + p_list->increment)); - p_list->limit += p_list->increment; - } - - if (p_index < p_list->realCount) - memmove(p_list->items + p_index + 1, p_list->items + p_index, sizeof(void*)*(p_list->realCount - p_index)); - - p_list->realCount++; - - p_list->items[p_index] = p_value; - return 1; -} - -MIR_CORE_DLL(int) List_InsertPtr(SortedList* list, void* p) -{ - if (p == NULL) - return -1; - - int idx; - if (list->sortFunc == 0) - idx = list->realCount; - else - List_GetIndex(list, p, &idx); - return List_Insert(list, p, idx); -} - -MIR_CORE_DLL(int) List_Remove(SortedList* p_list, int index) -{ - if (index < 0 || index > p_list->realCount) - return 0; - - p_list->realCount--; - if (p_list->realCount > index) { - memmove(p_list->items + index, p_list->items + index + 1, sizeof(void*)*(p_list->realCount - index)); - p_list->items[p_list->realCount] = NULL; - } - - return 1; -} - -MIR_CORE_DLL(int) List_RemovePtr(SortedList* list, void* p) -{ - int idx; - if (!List_GetIndex(list, p, &idx)) - return -1; - - List_Remove(list, idx); - return idx; -} - -MIR_CORE_DLL(void) List_Copy(SortedList* s, SortedList* d, size_t itemSize) -{ - d->increment = s->increment; - d->limit = s->limit; - d->realCount = s->realCount; - d->items = (void**)mir_alloc(sizeof(void*) * d->realCount); - memcpy(d->items, s->items, sizeof(void*) * d->realCount); -} - -MIR_CORE_DLL(void) List_ObjCopy(SortedList* s, SortedList* d, size_t itemSize) -{ - d->increment = s->increment; - d->sortFunc = s->sortFunc; - - for (int i = 0; i < s->realCount; i++) { - void* item = new char[itemSize]; - memcpy(item, s->items[i], itemSize); - List_Insert(d, item, i); - } -} diff --git a/src/mir_core/logger.cpp b/src/mir_core/logger.cpp deleted file mode 100644 index e129f48765..0000000000 --- a/src/mir_core/logger.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -#define SECRET_SIGNATURE 0x87654321 - -struct Logger -{ - Logger(const char* pszName, const TCHAR *ptszDescr, const TCHAR *ptszFilename, unsigned options) : - m_name(mir_strdup(pszName)), - m_descr(mir_tstrdup(ptszDescr)), - m_fileName(mir_tstrdup(ptszFilename)), - m_options(options), - m_signature(SECRET_SIGNATURE), - m_out(NULL), - m_lastwrite(0) - { - InitializeCriticalSection(&m_cs); - } - - ~Logger() - { - if (m_out) - fclose(m_out); - - DeleteCriticalSection(&m_cs); - } - - int m_signature; - ptrA m_name; - ptrT m_fileName, m_descr; - FILE *m_out; - __int64 m_lastwrite; - unsigned m_options; - - CRITICAL_SECTION m_cs; -}; - -static int CompareLoggers(const Logger *p1, const Logger *p2) -{ return strcmp(p1->m_name, p2->m_name); -} - -static OBJLIST arLoggers(1, CompareLoggers); - -static __int64 llIdlePeriod; - -void InitLogs() -{ - LARGE_INTEGER li; - QueryPerformanceFrequency(&li); - llIdlePeriod = li.QuadPart; -} - -void UninitLogs() -{ - arLoggers.destroy(); -} - -void CheckLogs() -{ - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - - for (int i=0; i < arLoggers.getCount(); i++) { - Logger &p = arLoggers[i]; - - mir_cslock lck(p.m_cs); - if (p.m_out && li.QuadPart - p.m_lastwrite > llIdlePeriod) { - fclose(p.m_out); - p.m_out = NULL; - } - else fflush(p.m_out); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(HANDLE) mir_createLog(const char* pszName, const TCHAR *ptszDescr, const TCHAR *ptszFile, unsigned options) -{ - if (ptszFile == NULL) - return NULL; - - Logger *result = new Logger(pszName, ptszDescr, ptszFile, options); - if (result == NULL) - return NULL; - - int idx = arLoggers.getIndex(result); - if (idx != -1) { - delete result; - return &arLoggers[idx]; - } - - FILE *fp = _tfopen(ptszFile, _T("ab")); - if (fp == NULL) { - TCHAR tszPath[MAX_PATH]; - _tcsncpy_s(tszPath, ptszFile, _TRUNCATE); - CreatePathToFileT(tszPath); - } - else fclose(fp); - - DeleteFile(ptszFile); - arLoggers.insert(result); - return result; -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -static Logger* prepareLogger(HANDLE hLogger) -{ - if (hLogger == NULL) - return NULL; - - Logger *p = (Logger*)hLogger; - return (p->m_signature == SECRET_SIGNATURE) ? p : NULL; -} - -MIR_CORE_DLL(void) mir_closeLog(HANDLE hLogger) -{ - Logger *p = prepareLogger(hLogger); - if (p != NULL) - arLoggers.remove(p); -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -MIR_C_CORE_DLL(int) mir_writeLogA(HANDLE hLogger, const char *format, ...) -{ - Logger *p = prepareLogger(hLogger); - if (p == NULL) - return 1; - - mir_cslock lck(p->m_cs); - if (p->m_out == NULL) - if ((p->m_out = _tfopen(p->m_fileName, _T("ab"))) == NULL) - return 2; - - va_list args; - va_start(args, format); - vfprintf(p->m_out, format, args); - - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - p->m_lastwrite = li.QuadPart; - return 0; -} - -MIR_C_CORE_DLL(int) mir_writeLogW(HANDLE hLogger, const WCHAR *format, ...) -{ - Logger *p = prepareLogger(hLogger); - if (p == NULL) - return 1; - - mir_cslock lck(p->m_cs); - if (p->m_out == NULL) - if ((p->m_out = _tfopen(p->m_fileName, _T("ab"))) == NULL) - return 2; - - va_list args; - va_start(args, format); - vfwprintf(p->m_out, format, args); - - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - p->m_lastwrite = li.QuadPart; - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(int) mir_writeLogVA(HANDLE hLogger, const char *format, va_list args) -{ - Logger *p = prepareLogger(hLogger); - if (p == NULL) - return 1; - - mir_cslock lck(p->m_cs); - if (p->m_out == NULL) - if ((p->m_out = _tfopen(p->m_fileName, _T("ab"))) == NULL) - return 2; - - vfprintf(p->m_out, format, args); - - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - p->m_lastwrite = li.QuadPart; - return 0; -} - -MIR_CORE_DLL(int) mir_writeLogVW(HANDLE hLogger, const WCHAR *format, va_list args) -{ - Logger *p = prepareLogger(hLogger); - if (p == NULL) - return 1; - - mir_cslock lck(p->m_cs); - if (p->m_out == NULL) - if ((p->m_out = _tfopen(p->m_fileName, _T("ab"))) == NULL) - return 2; - - vfwprintf(p->m_out, format, args); - - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - p->m_lastwrite = li.QuadPart; - return 0; -} diff --git a/src/mir_core/mc.cpp b/src/mir_core/mc.cpp deleted file mode 100644 index 189e4a3ed0..0000000000 --- a/src/mir_core/mc.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -static HANDLE hEventDefaultChanged, hEventEnabled; -static bool g_bEnabled; - -void InitMetaContacts() -{ - hEventDefaultChanged = CreateHookableEvent(ME_MC_DEFAULTTCHANGED); - hEventEnabled = CreateHookableEvent(ME_MC_ENABLED); -} - -DBCachedContact* CheckMeta(MCONTACT hMeta) -{ - if (!g_bEnabled) - return NULL; - - DBCachedContact *cc = currDb->m_cache->GetCachedContact(hMeta); - return (cc == NULL || cc->nSubs == -1) ? NULL : cc; -} - -int Meta_GetContactNumber(DBCachedContact *cc, MCONTACT hContact) -{ - if (g_bEnabled) - for (int i = 0; i < cc->nSubs; i++) - if (cc->pSubs[i] == hContact) - return i; - - return -1; -} - -MCONTACT Meta_GetContactHandle(DBCachedContact *cc, int contact_number) -{ - if (contact_number >= cc->nSubs || contact_number < 0 || !g_bEnabled) - return 0; - - return cc->pSubs[contact_number]; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// metacontacts - -MIR_CORE_DLL(BOOL) db_mc_isEnabled(void) -{ - return g_bEnabled; -} - -MIR_CORE_DLL(void) db_mc_enable(BOOL bEnabled) -{ - g_bEnabled = bEnabled != 0; - - NotifyEventHooks(hEventEnabled, g_bEnabled, 0); -} - -MIR_CORE_DLL(BOOL) db_mc_isMeta(MCONTACT hContact) -{ - if (currDb == NULL || !g_bEnabled) return FALSE; - - DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); - return (cc == NULL) ? FALSE : cc->nSubs != -1; -} - -MIR_CORE_DLL(BOOL) db_mc_isSub(MCONTACT hContact) -{ - if (currDb == NULL || !g_bEnabled) return FALSE; - - DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); - return (cc == NULL) ? FALSE : cc->parentID != 0; -} - -//returns a handle to the default contact, or null on failure -MIR_CORE_DLL(MCONTACT) db_mc_getDefault(MCONTACT hMetaContact) -{ - DBCachedContact *cc = CheckMeta(hMetaContact); - if (cc == NULL) - return 0; - - return (cc->nDefault != -1) ? Meta_GetContactHandle(cc, cc->nDefault) : 0; -} - -//returns the default contact number, or -1 on failure -MIR_CORE_DLL(int) db_mc_getDefaultNum(MCONTACT hMetaContact) -{ - DBCachedContact *cc = CheckMeta(hMetaContact); - return (cc == NULL) ? -1 : cc->nDefault; -} - -//returns the number of subcontacts, or -1 on failure -MIR_CORE_DLL(int) db_mc_getSubCount(MCONTACT hMetaContact) -{ - DBCachedContact *cc = CheckMeta(hMetaContact); - return (cc == NULL) ? -1 : cc->nSubs; -} - -// returns parent hContact for a subcontact or NULL if it's not a sub -MIR_CORE_DLL(MCONTACT) db_mc_getMeta(MCONTACT hSubContact) -{ - if (currDb == NULL) return NULL; - - DBCachedContact *cc = currDb->m_cache->GetCachedContact(hSubContact); - return (cc == NULL) ? NULL : cc->parentID; -} - -// returns parent hContact for a subcontact or hContact itself if it's not a sub -MIR_CORE_DLL(MCONTACT) db_mc_tryMeta(MCONTACT hContact) -{ - if (currDb == NULL) return hContact; - - DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); - if (cc == NULL) return hContact; - - return (cc->IsSub()) ? cc->parentID : hContact; -} - -// returns a subcontact with the given index -MIR_CORE_DLL(MCONTACT) db_mc_getSub(MCONTACT hMetaContact, int iNum) -{ - DBCachedContact *cc = CheckMeta(hMetaContact); - return (cc == NULL) ? 0 : Meta_GetContactHandle(cc, iNum); -} - -//sets the default contact, using the subcontact's handle -MIR_CORE_DLL(int) db_mc_setDefault(MCONTACT hMetaContact, MCONTACT hSub, BOOL bWriteDb) -{ - DBCachedContact *cc = CheckMeta(hMetaContact); - if (cc == NULL) - return 1; - - int contact_number = Meta_GetContactNumber(cc, hSub); - if (contact_number == -1) - return 1; - - if (cc->nDefault != contact_number) { - cc->nDefault = contact_number; - if (bWriteDb) - currDb->MetaSetDefault(cc); - - NotifyEventHooks(hEventDefaultChanged, hMetaContact, hSub); - } - return 0; -} - -//sets the default contact, using the subcontact's number -MIR_CORE_DLL(int) db_mc_setDefaultNum(MCONTACT hMetaContact, int iNum, BOOL bWriteDb) -{ - DBCachedContact *cc = CheckMeta(hMetaContact); - if (cc == NULL) - return 1; - if (iNum >= cc->nSubs || iNum < 0) - return 1; - - if (cc->nDefault != iNum) { - cc->nDefault = iNum; - if (bWriteDb) - currDb->MetaSetDefault(cc); - - NotifyEventHooks(hEventDefaultChanged, hMetaContact, Meta_GetContactHandle(cc, iNum)); - } - return 0; -} - -extern "C" MIR_CORE_DLL(void) db_mc_notifyDefChange(WPARAM wParam, LPARAM lParam) -{ - NotifyEventHooks(hEventDefaultChanged, wParam, lParam); -} diff --git a/src/mir_core/md5.cpp b/src/mir_core/md5.cpp deleted file mode 100644 index 216abfedba..0000000000 --- a/src/mir_core/md5.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c 2874 2006-05-16 21:38:00Z ghazan $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -// (C) 2005 Joe @ Whale - changed to compile with Miranda - -#include "commonheaders.h" - -#define T_MASK ((UINT32)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - -//gfd* -static void md5_process(mir_md5_state_t *pms, const BYTE *data /*[64]*/) -{ - UINT32 - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - UINT32 t; - /* Define storage for little-endian or both types of CPUs. */ - UINT32 xbuf[16]; - const UINT32 *X; - - { - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const BYTE *)&w)) /* dynamic little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if ( !((data - (const BYTE *)0) & 3)) { - /* data are properly aligned */ - X = (const UINT32 *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } - else /* dynamic big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const BYTE *xp = data; - int i; - - X = xbuf; /* (dynamic only) */ - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b, c, d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET1(a, b, c, d, k, s, Ti)\ - t = a + F(b, c, d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET1(a, b, c, d, 0, 7, T1); - SET1(d, a, b, c, 1, 12, T2); - SET1(c, d, a, b, 2, 17, T3); - SET1(b, c, d, a, 3, 22, T4); - SET1(a, b, c, d, 4, 7, T5); - SET1(d, a, b, c, 5, 12, T6); - SET1(c, d, a, b, 6, 17, T7); - SET1(b, c, d, a, 7, 22, T8); - SET1(a, b, c, d, 8, 7, T9); - SET1(d, a, b, c, 9, 12, T10); - SET1(c, d, a, b, 10, 17, T11); - SET1(b, c, d, a, 11, 22, T12); - SET1(a, b, c, d, 12, 7, T13); - SET1(d, a, b, c, 13, 12, T14); - SET1(c, d, a, b, 14, 17, T15); - SET1(b, c, d, a, 15, 22, T16); - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b, c, d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET2(a, b, c, d, k, s, Ti)\ - t = a + G(b, c, d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET2(a, b, c, d, 1, 5, T17); - SET2(d, a, b, c, 6, 9, T18); - SET2(c, d, a, b, 11, 14, T19); - SET2(b, c, d, a, 0, 20, T20); - SET2(a, b, c, d, 5, 5, T21); - SET2(d, a, b, c, 10, 9, T22); - SET2(c, d, a, b, 15, 14, T23); - SET2(b, c, d, a, 4, 20, T24); - SET2(a, b, c, d, 9, 5, T25); - SET2(d, a, b, c, 14, 9, T26); - SET2(c, d, a, b, 3, 14, T27); - SET2(b, c, d, a, 8, 20, T28); - SET2(a, b, c, d, 13, 5, T29); - SET2(d, a, b, c, 2, 9, T30); - SET2(c, d, a, b, 7, 14, T31); - SET2(b, c, d, a, 12, 20, T32); - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b, c, d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET3(a, b, c, d, k, s, Ti)\ - t = a + H(b, c, d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET3(a, b, c, d, 5, 4, T33); - SET3(d, a, b, c, 8, 11, T34); - SET3(c, d, a, b, 11, 16, T35); - SET3(b, c, d, a, 14, 23, T36); - SET3(a, b, c, d, 1, 4, T37); - SET3(d, a, b, c, 4, 11, T38); - SET3(c, d, a, b, 7, 16, T39); - SET3(b, c, d, a, 10, 23, T40); - SET3(a, b, c, d, 13, 4, T41); - SET3(d, a, b, c, 0, 11, T42); - SET3(c, d, a, b, 3, 16, T43); - SET3(b, c, d, a, 6, 23, T44); - SET3(a, b, c, d, 9, 4, T45); - SET3(d, a, b, c, 12, 11, T46); - SET3(c, d, a, b, 15, 16, T47); - SET3(b, c, d, a, 2, 23, T48); - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b, c, d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET4(a, b, c, d, k, s, Ti)\ - t = a + I(b, c, d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET4(a, b, c, d, 0, 6, T49); - SET4(d, a, b, c, 7, 10, T50); - SET4(c, d, a, b, 14, 15, T51); - SET4(b, c, d, a, 5, 21, T52); - SET4(a, b, c, d, 12, 6, T53); - SET4(d, a, b, c, 3, 10, T54); - SET4(c, d, a, b, 10, 15, T55); - SET4(b, c, d, a, 1, 21, T56); - SET4(a, b, c, d, 8, 6, T57); - SET4(d, a, b, c, 15, 10, T58); - SET4(c, d, a, b, 6, 15, T59); - SET4(b, c, d, a, 13, 21, T60); - SET4(a, b, c, d, 4, 6, T61); - SET4(d, a, b, c, 11, 10, T62); - SET4(c, d, a, b, 2, 15, T63); - SET4(b, c, d, a, 9, 21, T64); - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -MIR_CORE_DLL(void) mir_md5_init(mir_md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -MIR_CORE_DLL(void) mir_md5_append(mir_md5_state_t *pms, const BYTE *data, int nbytes) -{ - const BYTE *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - UINT32 nbits = (UINT32)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -MIR_CORE_DLL(void) mir_md5_finish(mir_md5_state_t *pms, BYTE digest[16]) -{ - static const BYTE pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - BYTE data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (BYTE)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - mir_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - mir_md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (BYTE)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} - -MIR_CORE_DLL(void) mir_md5_hash(const BYTE *data, int len, BYTE digest[16]) -{ - mir_md5_state_t state; - mir_md5_init(&state); - mir_md5_append(&state, data, len); - mir_md5_finish(&state, digest); -} diff --git a/src/mir_core/memory.cpp b/src/mir_core/memory.cpp deleted file mode 100644 index 9c1c2afbf6..0000000000 --- a/src/mir_core/memory.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -#define BLOCK_ALLOCED 0xABBABABA -#define BLOCK_FREED 0xDEADBEEF - -static int CheckBlock(void* blk) -{ - int result = FALSE; - char* p = (char*)blk - sizeof(DWORD)*2; - DWORD size, *b, *e; - - __try - { - size = *(DWORD*)p; - b = (DWORD*)&p[ sizeof(DWORD) ]; - e = (DWORD*)&p[ sizeof(DWORD)*2 + size ]; - - if (*b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED) - { - if (*b == BLOCK_FREED && *e == BLOCK_FREED) - OutputDebugStringA("memory block is already deleted\n"); - else - OutputDebugStringA("memory block is corrupted\n"); - #if defined(_DEBUG) - DebugBreak(); - #endif - } - else result = TRUE; - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - OutputDebugStringA("access violation during checking memory block\n"); - #if defined(_DEBUG) - DebugBreak(); - #endif - } - - return result; -} - -/******************************************************************************/ - -MIR_C_CORE_DLL(void*) mir_alloc(size_t size) -{ - if (size == 0) - return NULL; - - char *p = (char*)malloc(size + sizeof(DWORD)* 3); - if (p == NULL) { - OutputDebugStringA("memory overflow\n"); - #if defined(_DEBUG) - DebugBreak(); - #endif - return NULL; - } - - *(DWORD*)p = (DWORD)size; - *(DWORD*)&p[sizeof(DWORD)] = BLOCK_ALLOCED; - *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_ALLOCED; - return p + sizeof(DWORD)* 2; -} - -/******************************************************************************/ - -MIR_C_CORE_DLL(void*) mir_calloc(size_t size) -{ - void* p = mir_alloc(size); - if (p != NULL) - memset(p, 0, size); - return p; -} - -/******************************************************************************/ - -MIR_C_CORE_DLL(void*) mir_realloc(void* ptr, size_t size) -{ - char *p; - - if (ptr != NULL) { - if (!CheckBlock(ptr)) - return NULL; - p = (char*)ptr - sizeof(DWORD)*2; - } - else p = NULL; - - p = (char*)realloc(p, size + sizeof(DWORD)*3); - if (p == NULL) { - OutputDebugStringA("memory overflow\n"); - #if defined(_DEBUG) - DebugBreak(); - #endif - return NULL; - } - - *(DWORD*)p = (DWORD)size; - *(DWORD*)&p[sizeof(DWORD)] = BLOCK_ALLOCED; - *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_ALLOCED; - return p + sizeof(DWORD)*2; -} - -/******************************************************************************/ - -MIR_C_CORE_DLL(void) mir_free(void* ptr) -{ - char* p; - DWORD size; - - if (ptr == NULL) - return; - if (!CheckBlock(ptr)) - return; - - p = (char*)ptr - sizeof(DWORD)*2; - size = *(DWORD*)p; - - *(DWORD*)&p[sizeof(DWORD)] = BLOCK_FREED; - *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_FREED; - free(p); -} - -/******************************************************************************/ - -MIR_CORE_DLL(char*) mir_strdup(const char *str) -{ - if (str == NULL) - return NULL; - - char *p = (char*)mir_alloc(strlen(str)+1); - if (p) - strcpy(p, str); - return p; -} - -MIR_CORE_DLL(WCHAR*) mir_wstrdup(const WCHAR *str) -{ - if (str == NULL) - return NULL; - - WCHAR *p = (WCHAR*)mir_alloc(sizeof(WCHAR)*(wcslen(str)+1)); - if (p) - wcscpy(p, str); - return p; -} - -/******************************************************************************/ - -MIR_CORE_DLL(char*) mir_strndup(const char *str, size_t len) -{ - if (str == NULL || len == 0) - return NULL; - - char *p = (char*)mir_alloc(len+1); - if (p) { - memcpy(p, str, len); - p[len] = 0; - } - return p; -} - -MIR_CORE_DLL(WCHAR*) mir_wstrndup(const WCHAR *str, size_t len) -{ - if (str == NULL || len == 0) - return NULL; - - WCHAR *p = (WCHAR*)mir_alloc(sizeof(WCHAR)*(len+1)); - if (p) { - memcpy(p, str, sizeof(WCHAR)*len); - p[len] = 0; - } - return p; -} - -/******************************************************************************/ - -MIR_CORE_DLL(int) mir_snprintf(char *buffer, size_t count, const char* fmt, ...) -{ - va_list va; - va_start(va, fmt); - int len = _vsnprintf(buffer, count-1, fmt, va); - va_end(va); - buffer[count-1] = 0; - return len; -} - -/******************************************************************************/ - -MIR_CORE_DLL(int) mir_snwprintf(WCHAR *buffer, size_t count, const WCHAR* fmt, ...) -{ - va_list va; - va_start(va, fmt); - int len = _vsntprintf(buffer, count-1, fmt, va); - va_end(va); - buffer[count-1] = 0; - return len; -} - -/******************************************************************************/ - -MIR_CORE_DLL(int) mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va) -{ - int len = _vsnprintf(buffer, count-1, fmt, va); - buffer[count-1] = 0; - return len; -} - -/******************************************************************************/ - -MIR_CORE_DLL(int) mir_vsnwprintf(WCHAR *buffer, size_t count, const WCHAR* fmt, va_list va) -{ - int len = _vsntprintf(buffer, count-1, fmt, va); - buffer[count-1] = 0; - return len; -} - -/******************************************************************************/ - -MIR_CORE_DLL(wchar_t*) mir_a2u_cp(const char* src, int codepage) -{ - if (src == NULL) - return NULL; - - int cbLen = MultiByteToWideChar(codepage, 0, src, -1, NULL, 0); - wchar_t* result = (wchar_t*)mir_alloc(sizeof(wchar_t)*(cbLen+1)); - if (result == NULL) - return NULL; - - MultiByteToWideChar(codepage, 0, src, -1, result, cbLen); - result[cbLen] = 0; - return result; -} - -/******************************************************************************/ - -MIR_CORE_DLL(wchar_t*) mir_a2u(const char* src) -{ - return mir_a2u_cp(src, Langpack_GetDefaultCodePage()); -} - -/******************************************************************************/ - -MIR_CORE_DLL(char*) mir_u2a_cp(const wchar_t* src, int codepage) -{ - if (src == NULL) - return NULL; - - int cbLen = WideCharToMultiByte(codepage, 0, src, -1, NULL, 0, NULL, NULL); - char* result = (char*)mir_alloc(cbLen+1); - if (result == NULL) - return NULL; - - WideCharToMultiByte(codepage, 0, src, -1, result, cbLen, NULL, NULL); - result[cbLen] = 0; - return result; -} - -/******************************************************************************/ - -MIR_CORE_DLL(char*) mir_u2a(const wchar_t* src) -{ - return mir_u2a_cp(src, Langpack_GetDefaultCodePage()); -} diff --git a/src/mir_core/mir_core.def b/src/mir_core/mir_core.def deleted file mode 100644 index 312540f081..0000000000 --- a/src/mir_core/mir_core.def +++ /dev/null @@ -1,282 +0,0 @@ -LIBRARY mir_core - -EXPORTS -CallContactService @1 -CallProtoService @2 -Langpack_LookupUuid @3 -Langpack_MarkPluginLoaded @4 -CallFunctionAsync @5 -CallPluginEventHook @7 -CallService @8 -CallServiceSync @9 -CreateDirectoryTree @10 -CreateDirectoryTreeW @11 -CreateHookableEvent @12 -CreatePathToFile @13 -CreatePathToFileW @14 -CreateServiceFunction @15 -CreateServiceFunctionObj @16 -CreateServiceFunctionObjParam @17 -CreateServiceFunctionParam @18 -DestroyHookableEvent @19 -DestroyServiceFunction @20 -GetExceptionFilter @21 -GetInstByAddress @22 -HookEvent @23 -HookEventMessage @24 -HookEventObj @25 -HookEventObjParam @26 -HookEventParam @27 -KillModuleEventHooks @28 -KillModuleServices @29 -KillObjectEventHooks @30 -KillObjectServices @31 -KillObjectThreads @32 -Langpack_SortDuplicates @33 -Langpack_GetDefaultCodePage @34 -Langpack_GetDefaultLocale @35 -Langpack_PcharToTchar @36 -List_Copy @37 -List_Create @38 -List_Destroy @39 -List_Find @40 -List_GetIndex @41 -List_IndexOf @42 -List_Insert @43 -List_InsertPtr @44 -List_ObjCopy @45 -List_Remove @46 -List_RemovePtr @47 -LoadLangPack @48 -LoadLangPackModule @49 -NotifyEventHooks @50 -PathToAbsolute @51 -PathToAbsoluteW @52 -PathToRelative @53 -PathToRelativeW @54 -RegisterModule @55 -ReloadLangpack @56 -ServiceExists @57 -SetExceptionFilter @58 -SetHookDefaultForHookableEvent @59 -Thread_Pop @60 -Thread_Push @61 -Thread_Wait @62 -TranslateA_LP @63 -TranslateDialog_LP @64 -TranslateMenu_LP @65 -TranslateW_LP @66 -Ucs2toUtf8Len @67 -UnhookEvent @68 -UnregisterModule @69 -Utf8Decode @70 -Utf8DecodeCP @71 -Utf8DecodeW @72 -Utf8Encode @73 -Utf8EncodeCP @74 -Utf8EncodeW @75 -forkthread @76 -forkthreadex @77 -ltrim @78 -ltrimp @79 -mir_a2u @80 -mir_a2u_cp @81 -mir_alloc @82 -mir_calloc @83 -mir_free @84 -mir_hash @85 -mir_md5_append @86 -mir_md5_finish @87 -mir_md5_hash @88 -mir_md5_init @89 -mir_realloc @90 -mir_sha1_append @91 -mir_sha1_finish @92 -mir_sha1_hash @93 -mir_sha1_init @94 -mir_strdup @95 -mir_strndup @96 -mir_u2a @97 -mir_u2a_cp @98 -mir_vsnprintf @99 -mir_vsnwprintf @100 -mir_wstrdup @101 -rtrim @102 -wildcmp @103 -rtrimw @104 -mir_snprintf @105 -mir_snwprintf @106 -db_unset @107 -db_free @108 -db_get @109 -db_get_b @110 -db_get_dw @111 -db_get_s @112 -db_get_sa @113 -db_get_w @114 -db_get_wsa @115 -db_set_b @116 -db_set_blob @117 -db_set_dw @118 -db_set_s @119 -db_set_utf @120 -db_set_w @121 -db_set_ws @122 -UnloadCoreModule @123 -Thread_SetName @124 -replaceStr @125 -replaceStrW @126 -db_setCurrent @127 -CmdLine_GetOption @128 -CmdLine_Parse @129 -Utf8CheckString @130 -GetSubscribersCount @131 -NotifyFastHook @132 -db_find_first @133 -db_find_next @134 -Icon_Register @135 -Icon_RegisterT @136 -mir_subclassWindow @137 -mir_callNextSubclass @138 -KillModuleSubclassing @139 -mir_wstrndup @140 -mir_unsubclassWindow @141 -mir_urlEncode @142 -db_event_add @143 -db_event_count @144 -db_event_delete @145 -db_event_first @146 -db_event_firstUnread @147 -db_event_get @148 -db_event_getBlobSize @149 -db_event_getContact @150 -db_event_last @151 -db_event_markRead @152 -db_event_next @153 -db_event_prev @154 -ltrimw @155 -ltrimpw @156 -wildcmpw @157 -wildcmpi @158 -wildcmpiw @159 -mir_base64_encode @160 -mir_base64_decode @161 -ProtoServiceExists @162 -ProtoBroadcastAck @163 -ProtoCallService @164 -db_set_resident @165 -db_set @166 -ProtoConstructor @167 -ProtoDestructor @168 -ProtoCreateService @169 -ProtoCreateServiceParam @170 -ProtoHookEvent @171 -ProtoCreateHookableEvent @172 -ProtoForkThread @173 -ProtoForkThreadEx @174 -json_as_array @175 -json_as_bool @176 -json_as_float @177 -json_as_int @178 -json_as_node @179 -json_as_string @180 -json_as_pstring @181 -json_at @182 -json_cast @183 -json_clear @184 -json_copy @185 -json_delete @186 -json_duplicate @187 -json_empty @188 -json_equal @189 -json_free @190 -json_get @191 -json_merge @192 -json_name @193 -json_new @194 -json_new_a @195 -json_new_b @196 -json_new_f @197 -json_new_i @198 -json_nullify @199 -json_parse @200 -json_pop_back @201 -json_pop_back_at @202 -json_preparse @203 -json_push_back @204 -json_reserve @205 -json_set_a @206 -json_set_b @207 -json_set_f @208 -json_set_i @209 -json_set_n @210 -json_set_name @211 -json_size @212 -json_strip_white_space @213 -json_swap @214 -json_type @215 -json_write @216 -json_write_formatted @217 -mir_subclassWindowFull @218 -ProtoGetAvatarFormat @219 -ProtoGetAvatarExtension @220 -ProtoGetBufferFormat @221 -ProtoGetAvatarFileFormat @222 -mir_createLog @223 -mir_writeLogA @224 -mir_writeLogW @225 -mir_writeLogVA @226 -mir_writeLogVW @227 -bin2hex @228 -bin2hexW @229 -mir_hmac_sha1 @230 -mir_base64_encodebuf @231 -mirstr_allocate @232 -mirstr_free @233 -mirstr_realloc @234 -mirstr_getNil @235 -mirstr_lock @236 -mirstr_release @237 -mirstr_unlock @238 -IsWinVerVistaPlus @239 -IsWinVer7Plus @240 -IsFullScreen @241 -IsWorkstationLocked @242 -IsScreenSaverRunning @243 -ProtoLogA @244 -ProtoLogW @245 -db_get_static @246 -db_get_wstatic @247 -db_get_static_utf @248 -db_mc_isMeta @249 -db_mc_isSub @250 -db_mc_getMeta @251 -db_get_contact @252 -db_mc_getDefault @253 -db_mc_getDefaultNum @254 -db_mc_getSubCount @255 -db_mc_getSub @256 -db_mc_setDefault @257 -db_mc_setDefaultNum @258 -mir_closeLog @259 -db_mc_enable @260 -db_mc_isEnabled @261 -LoadLangPackDescr @262 -PathIsAbsolute @263 -PathIsAbsoluteW @264 -db_mc_notifyDefChange @265 -db_mc_tryMeta @266 -mir_strlen @267 -mir_wstrlen @268 -mir_strcpy @269 -mir_wstrcpy @270 -mir_strncpy @271 -mir_wstrncpy @272 -mir_strcat @273 -mir_wstrcat @274 -mir_strncat @275 -mir_wstrncat @276 -mir_strcmp @277 -mir_strcmpi @278 -mir_wstrcmp @279 -mir_wstrcmpi @280 diff --git a/src/mir_core/mir_core_10.vcxproj b/src/mir_core/mir_core_10.vcxproj index d1f2fbed58..2039a518f2 100644 --- a/src/mir_core/mir_core_10.vcxproj +++ b/src/mir_core/mir_core_10.vcxproj @@ -23,103 +23,73 @@ - - - - - - - - - - - + + + + + + + + + + + - - - - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + + + + ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + ..\commonheaders.h - - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h - ..\commonheaders.h + + ..\commonheaders.h - - - - - + + + + + Create - - - - - - - - - - - - - - + + + + + + + + + + + + + + mir_core @@ -190,7 +160,7 @@ ..\..\include\msapi - mir_core.def + src\mir_core.def true false Windows @@ -229,7 +199,7 @@ ..\..\include\msapi - mir_core.def + src\mir_core.def true false $(IntDir)$(TargetName)64.lib @@ -262,7 +232,7 @@ ..\..\include\msapi - mir_core.def + src\mir_core.def true true true @@ -305,7 +275,7 @@ ..\..\include\msapi - mir_core.def + src\mir_core.def true true true diff --git a/src/mir_core/mir_core_10.vcxproj.filters b/src/mir_core/mir_core_10.vcxproj.filters index 1de8cfd829..1aa55b2dfd 100644 --- a/src/mir_core/mir_core_10.vcxproj.filters +++ b/src/mir_core/mir_core_10.vcxproj.filters @@ -13,111 +13,111 @@ - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files - + Source Files - + Source Files - + Source Files - + Header Files Header Files - + Header Files @@ -126,31 +126,31 @@ Header Files - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json diff --git a/src/mir_core/mir_core_12.vcxproj b/src/mir_core/mir_core_12.vcxproj index 6e2a4f4ee2..c74c8ae5bf 100644 --- a/src/mir_core/mir_core_12.vcxproj +++ b/src/mir_core/mir_core_12.vcxproj @@ -25,97 +25,70 @@ - - - - - - - - - + + + + + + + + + - + - - - - - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h + + + + + ../commonheaders.h - - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h + + ../commonheaders.h - - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h + + ../commonheaders.h - - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h + + ../commonheaders.h - - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h + + ../commonheaders.h - - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h + + ../commonheaders.h - - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h + + ../commonheaders.h - - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h + + ../commonheaders.h - - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h - ../commonheaders.h + + ../commonheaders.h - - - - - + + + + + Create - - - - - - - - - - - - - - + + + + + + + + + + + + + + mir_core @@ -190,7 +163,7 @@ ..\..\include\msapi - mir_core.def + src\mir_core.def true false Windows @@ -230,7 +203,7 @@ ..\..\include\msapi - mir_core.def + src\mir_core.def true false $(IntDir)$(TargetName)64.lib @@ -263,7 +236,7 @@ ..\..\include\msapi - mir_core.def + src\mir_core.def true true true @@ -305,7 +278,7 @@ ..\..\include\msapi - mir_core.def + src\mir_core.def true true true diff --git a/src/mir_core/mir_core_12.vcxproj.filters b/src/mir_core/mir_core_12.vcxproj.filters index cf84f183a5..4f6c514596 100644 --- a/src/mir_core/mir_core_12.vcxproj.filters +++ b/src/mir_core/mir_core_12.vcxproj.filters @@ -13,108 +13,108 @@ - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files - + Source Files - + Source Files - + Source Files - + Header Files Header Files - + Header Files @@ -123,31 +123,31 @@ Header Files - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json - + Source Files\json diff --git a/src/mir_core/miranda.cpp b/src/mir_core/miranda.cpp deleted file mode 100644 index ebf4b59956..0000000000 --- a/src/mir_core/miranda.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "commonheaders.h" - -HWND hAPCWindow = NULL; - -int InitPathUtils(void); -void (*RecalculateTime)(void); - -void CheckLogs(); -void InitLogs(); -void UninitLogs(); - -void InitWinver(); -void InitMetaContacts(); - -int hLangpack = 0; -HINSTANCE hInst = 0; - -HANDLE hStackMutex, hThreadQueueEmpty; -DWORD mir_tls = 0; - -///////////////////////////////////////////////////////////////////////////////////////// -// module init - -static LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_USER+1) { - PAPCFUNC pFunc = (PAPCFUNC)wParam; - pFunc((ULONG_PTR)lParam); - return 0; - } - - if (msg == WM_TIMER) - CheckLogs(); - - if (msg == WM_TIMECHANGE && RecalculateTime) - RecalculateTime(); - - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -static void LoadCoreModule(void) -{ - INITCOMMONCONTROLSEX icce = {0}; - icce.dwSize = sizeof(icce); - icce.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES; - InitCommonControlsEx(&icce); - - hAPCWindow = CreateWindowEx(0, _T("ComboLBox"), NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); - SetClassLongPtr(hAPCWindow, GCL_STYLE, GetClassLongPtr(hAPCWindow, GCL_STYLE) | CS_DROPSHADOW); - DestroyWindow(hAPCWindow); - hAPCWindow = NULL; - - hAPCWindow = CreateWindowEx(0, _T("STATIC"), NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); - SetWindowLongPtr(hAPCWindow, GWLP_WNDPROC, (LONG_PTR)APCWndProc); - SetTimer(hAPCWindow, 1, 1000, NULL); - hStackMutex = CreateMutex(NULL, FALSE, NULL); - hThreadQueueEmpty = CreateEvent(NULL, TRUE, TRUE, NULL); - - #ifdef _WIN64 - HMODULE mirInst = GetModuleHandleA("miranda64.exe"); - #else - HMODULE mirInst = GetModuleHandleA("miranda32.exe"); - #endif - RecalculateTime = (void (*)()) GetProcAddress(mirInst, "RecalculateTime"); - - InitWinver(); - InitPathUtils(); - InitLogs(); - InitialiseModularEngine(); - InitProtocols(); - InitMetaContacts(); -} - -MIR_CORE_DLL(void) UnloadCoreModule(void) -{ - DestroyWindow(hAPCWindow); - CloseHandle(hStackMutex); - CloseHandle(hThreadQueueEmpty); - TlsFree(mir_tls); - - UninitProtocols(); - DestroyModularEngine(); - UninitLogs(); - UnloadLangPackModule(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// entry point - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) { - hInst = hinstDLL; - mir_tls = TlsAlloc(); - LoadCoreModule(); - } - else if (fdwReason == DLL_THREAD_DETACH) { - HANDLE hEvent = TlsGetValue(mir_tls); - if (hEvent) - CloseHandle(hEvent); - } - return TRUE; -} diff --git a/src/mir_core/miranda.h b/src/mir_core/miranda.h deleted file mode 100644 index 6b85fc2b67..0000000000 --- a/src/mir_core/miranda.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -extern "C" -{ - MIR_CORE_DLL(int) Langpack_MarkPluginLoaded(PLUGININFOEX* pInfo); - MIR_CORE_DLL(MUUID*) Langpack_LookupUuid(WPARAM wParam); -}; - -void UnloadLangPackModule(void); - -int InitialiseModularEngine(void); -void DestroyModularEngine(void); - -int InitPathUtils(void); - -void InitProtocols(); -void UninitProtocols(); - -extern HINSTANCE hInst; -extern HWND hAPCWindow; -extern HANDLE hStackMutex, hThreadQueueEmpty; -extern MIDatabase *currDb; - -/**** modules.cpp **********************************************************************/ - -struct THookSubscriber -{ - HINSTANCE hOwner; - int type; - union { - struct { - union { - MIRANDAHOOK pfnHook; - MIRANDAHOOKPARAM pfnHookParam; - MIRANDAHOOKOBJ pfnHookObj; - MIRANDAHOOKOBJPARAM pfnHookObjParam; - }; - void* object; - LPARAM lParam; - }; - struct { - HWND hwnd; - UINT message; - }; - }; -}; - -#define HOOK_SECRET_SIGNATURE 0xDEADBABA - -struct THook -{ - char name[ MAXMODULELABELLENGTH ]; - int id; - int subscriberCount; - THookSubscriber* subscriber; - MIRANDAHOOK pfnHook; - DWORD secretSignature; - CRITICAL_SECTION csHook; -}; - -extern LIST pluginListAddr; - -/**** langpack.cpp *********************************************************************/ - -char* LangPackTranslateString(MUUID* pUuid, const char *szEnglish, const int W); -TCHAR* LangPackTranslateStringT(int hLangpack, const TCHAR* tszEnglish); - -/**** options.cpp **********************************************************************/ - -HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR *name); - -/**** subclass.cpp *********************************************************************/ - -/**** threads.cpp **********************************************************************/ - -extern DWORD mir_tls; - -/**** utils.cpp ************************************************************************/ - -void HotkeyToName(TCHAR *buf, int size, BYTE shift, BYTE key); -WORD GetHotkeyValue(INT_PTR idHotkey); - -HBITMAP ConvertIconToBitmap(HICON hIcon, HIMAGELIST hIml, int iconId); - -class StrConvUT -{ -private: - wchar_t* m_body; - -public: - StrConvUT(const char* pSrc) : - m_body(mir_a2u(pSrc)) {} - - ~StrConvUT() { mir_free(m_body); } - operator const wchar_t* () const { return m_body; } -}; - -class StrConvAT -{ -private: - char* m_body; - -public: - StrConvAT(const wchar_t* pSrc) : - m_body(mir_u2a(pSrc)) {} - - ~StrConvAT() { mir_free(m_body); } - operator const char* () const { return m_body; } - operator const wchar_t* () const { return (wchar_t*)m_body; } // type cast to fake the interface definition - operator const LPARAM () const { return (LPARAM)m_body; } -}; - -#define StrConvT(x) StrConvUT(x) -#define StrConvTu(x) x -#define StrConvA(x) StrConvAT(x) -#define StrConvU(x) x diff --git a/src/mir_core/modules.cpp b/src/mir_core/modules.cpp deleted file mode 100644 index 8b819b17a4..0000000000 --- a/src/mir_core/modules.cpp +++ /dev/null @@ -1,662 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -// list of hooks - -static int compareHooks(const THook* p1, const THook* p2) -{ - return strcmp(p1->name, p2->name); -} - -static LIST hooks(50, compareHooks); - -struct THookToMainThreadItem -{ - THook* hook; - HANDLE hDoneEvent; - WPARAM wParam; - LPARAM lParam; - int result; -}; - -// list of services - -struct TService -{ - DWORD nameHash; - HINSTANCE hOwner; - union { - MIRANDASERVICE pfnService; - MIRANDASERVICEPARAM pfnServiceParam; - MIRANDASERVICEOBJ pfnServiceObj; - MIRANDASERVICEOBJPARAM pfnServiceObjParam; - }; - int flags; - LPARAM lParam; - void* object; - char name[1]; -}; - -LIST services(100, NumericKeySortT); - -typedef struct -{ - HANDLE hDoneEvent; - WPARAM wParam; - LPARAM lParam; - int result; - const char *name; -} - TServiceToMainThreadItem; - -// other static variables -static BOOL bServiceMode = FALSE; -static CRITICAL_SECTION csHooks, csServices; -static DWORD mainThreadId; -static int hookId = 1; - -///////////////////////////////////////////////////////////////////////////////////////// - -__forceinline HANDLE getThreadEvent() -{ - HANDLE pData = (HANDLE)TlsGetValue(mir_tls); - if (pData == NULL) { - pData = CreateEvent(NULL, FALSE, FALSE, NULL); - TlsSetValue(mir_tls, pData); - } - return pData; -} - -static int QueueMainThread(PAPCFUNC pFunc, void* pParam, HANDLE hDoneEvent) -{ - int result = PostMessage(hAPCWindow, WM_USER+1, (WPARAM)pFunc, (LPARAM)pParam); // let this get processed in its own time - if (hDoneEvent) - WaitForSingleObject(hDoneEvent, INFINITE); - - return result; -} - -/////////////////////////////////////////////////////////////////////////////// -// HOOKS - -MIR_CORE_DLL(HANDLE) CreateHookableEvent(const char *name) -{ - if (name == NULL) - return NULL; - - mir_cslock lck(csHooks); - - int idx; - if ((idx = hooks.getIndex((THook*)name)) != -1) - return hooks[idx]; - - THook* newItem = (THook*)mir_alloc(sizeof(THook)); - strncpy(newItem->name, name, sizeof(newItem->name)); newItem->name[ MAXMODULELABELLENGTH-1 ] = 0; - newItem->id = hookId++; - newItem->subscriberCount = 0; - newItem->subscriber = NULL; - newItem->pfnHook = NULL; - newItem->secretSignature = HOOK_SECRET_SIGNATURE; - InitializeCriticalSection(&newItem->csHook); - hooks.insert(newItem); - return (HANDLE)newItem; -} - -MIR_CORE_DLL(int) DestroyHookableEvent(HANDLE hEvent) -{ - if (hEvent == NULL) - return 1; - - mir_cslock lck(csHooks); - - int idx; - if ((idx = hooks.getIndex((THook*)hEvent)) == -1) - return 1; - - THook* p = hooks[idx]; - p->secretSignature = 0; - if (p->subscriberCount) { - mir_free(p->subscriber); - p->subscriber = NULL; - p->subscriberCount = 0; - } - hooks.remove(idx); - DeleteCriticalSection(&p->csHook); - mir_free(p); - return 0; -} - -MIR_CORE_DLL(int) SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook) -{ - THook* p = (THook*)hEvent; - - mir_cslock lck(csHooks); - if (hooks.getIndex(p) != -1) - p->pfnHook = pfnHook; - return 0; -} - -MIR_CORE_DLL(int) CallPluginEventHook(HINSTANCE hInst, HANDLE hEvent, WPARAM wParam, LPARAM lParam) -{ - THook* p = (THook*)hEvent; - if (p == NULL || hInst == NULL) - return -1; - - mir_cslock lck(p->csHook); - for (int i = 0; i < p->subscriberCount; i++) { - THookSubscriber* s = &p->subscriber[i]; - if (s->hOwner != hInst) - continue; - - int returnVal; - switch (s->type) { - case 1: returnVal = s->pfnHook(wParam, lParam); break; - case 2: returnVal = s->pfnHookParam(wParam, lParam, s->lParam); break; - case 3: returnVal = s->pfnHookObj(s->object, wParam, lParam); break; - case 4: returnVal = s->pfnHookObjParam(s->object, wParam, lParam, s->lParam); break; - case 5: returnVal = SendMessage(s->hwnd, s->message, wParam, lParam); break; - default: continue; - } - if (returnVal) - return returnVal; - } - - if (p->subscriberCount == 0 && p->pfnHook != 0) - return p->pfnHook(wParam, lParam); - - return 0; -} - -static int CallHookSubscribers(THook* p, WPARAM wParam, LPARAM lParam) -{ - if (p == NULL) - return -1; - - mir_cslock lck(p->csHook); - - // NOTE: We've got the critical section while all this lot are called. That's mostly safe, though. - for (int i = 0; i < p->subscriberCount; i++) { - THookSubscriber* s = &p->subscriber[i]; - - int returnVal; - switch (s->type) { - case 1: returnVal = s->pfnHook(wParam, lParam); break; - case 2: returnVal = s->pfnHookParam(wParam, lParam, s->lParam); break; - case 3: returnVal = s->pfnHookObj(s->object, wParam, lParam); break; - case 4: returnVal = s->pfnHookObjParam(s->object, wParam, lParam, s->lParam); break; - case 5: returnVal = SendMessage(s->hwnd, s->message, wParam, lParam); break; - default: continue; - } - if (returnVal) - return returnVal; - } - - // call the default hook if any - if (p->pfnHook != 0) - return p->pfnHook(wParam, lParam); - - return 0; -} - -enum { hookOk, hookEmpty, hookInvalid }; - -__forceinline int checkHook(THook* p) -{ - if (p == NULL) - return hookInvalid; - - int ret; - __try - { - if (p->secretSignature != HOOK_SECRET_SIGNATURE) - ret = hookInvalid; - else if (p->subscriberCount == 0 && p->pfnHook == NULL) - ret = hookEmpty; - else - ret = hookOk; - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - ret = hookInvalid; - } - - return ret; -} - -static void CALLBACK HookToMainAPCFunc(ULONG_PTR dwParam) -{ - THookToMainThreadItem* item = (THookToMainThreadItem*)dwParam; - item->result = CallHookSubscribers(item->hook, item->wParam, item->lParam); - SetEvent(item->hDoneEvent); -} - -MIR_CORE_DLL(int) NotifyEventHooks(HANDLE hEvent, WPARAM wParam, LPARAM lParam) -{ - switch ( checkHook((THook*)hEvent)) { - case hookInvalid: return -1; - case hookEmpty: return 0; - } - - if ( GetCurrentThreadId() == mainThreadId) - return CallHookSubscribers((THook*)hEvent, wParam, lParam); - - THookToMainThreadItem item; - item.hDoneEvent = getThreadEvent(); - item.hook = (THook*)hEvent; - item.wParam = wParam; - item.lParam = lParam; - QueueMainThread(HookToMainAPCFunc, &item, item.hDoneEvent); - return item.result; -} - -MIR_CORE_DLL(int) NotifyFastHook(HANDLE hEvent, WPARAM wParam, LPARAM lParam) -{ - switch ( checkHook((THook*)hEvent)) { - case hookInvalid: return -1; - case hookEmpty: return 0; - } - - return CallHookSubscribers((THook*)hEvent, wParam, lParam); -} - -extern "C" MIR_CORE_DLL(int) GetSubscribersCount(THook* pHook) -{ - switch ( checkHook(pHook)) { - case hookInvalid: - case hookEmpty: return 0; - } - return pHook->subscriberCount; -} - -static HANDLE HookEventInt(int type, const char *name, MIRANDAHOOK hookProc, void* object, LPARAM lParam) -{ - mir_cslock lck(csHooks); - - int idx; - if ((idx = hooks.getIndex((THook*)name)) == -1) - return NULL; - - THook* p = hooks[ idx ]; - p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1)); - p->subscriber[ p->subscriberCount ].type = type; - p->subscriber[ p->subscriberCount ].pfnHook = hookProc; - p->subscriber[ p->subscriberCount ].object = object; - p->subscriber[ p->subscriberCount ].lParam = lParam; - p->subscriber[ p->subscriberCount ].hOwner = GetInstByAddress(hookProc); - p->subscriberCount++; - - return (HANDLE)((p->id << 16) | p->subscriberCount); -} - -MIR_CORE_DLL(HANDLE) HookEvent(const char *name, MIRANDAHOOK hookProc) -{ - return HookEventInt(1, name, hookProc, 0, 0); -} - -MIR_CORE_DLL(HANDLE) HookEventParam(const char *name, MIRANDAHOOKPARAM hookProc, LPARAM lParam) -{ - return HookEventInt(2, name, (MIRANDAHOOK)hookProc, 0, lParam); -} - -MIR_CORE_DLL(HANDLE) HookEventObj(const char *name, MIRANDAHOOKOBJ hookProc, void* object) -{ - return HookEventInt(3, name, (MIRANDAHOOK)hookProc, object, 0); -} - -MIR_CORE_DLL(HANDLE) HookEventObjParam(const char *name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam) -{ - return HookEventInt(4, name, (MIRANDAHOOK)hookProc, object, lParam); -} - -MIR_CORE_DLL(HANDLE) HookEventMessage(const char *name, HWND hwnd, UINT message) -{ - mir_cslock lck(csHooks); - - int idx; - if ((idx = hooks.getIndex((THook*)name)) == -1) - return NULL; - - THook* p = hooks[ idx ]; - p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1)); - p->subscriber[ p->subscriberCount ].type = 5; - p->subscriber[ p->subscriberCount ].hwnd = hwnd; - p->subscriber[ p->subscriberCount ].message = message; - p->subscriberCount++; - return (HANDLE)((p->id << 16) | p->subscriberCount); -} - -MIR_CORE_DLL(int) UnhookEvent(HANDLE hHook) -{ - if (hHook == NULL) - return 0; - - int hookId = (int)hHook >> 16; - int subscriberId = ((int)hHook & 0xFFFF) - 1; - - mir_cslock lck(csHooks); - - THook* p = NULL; - for (int i = 0; i < hooks.getCount(); i++) - if (hooks[i]->id == hookId) { - p = hooks[i]; - break; - } - - if (p == NULL) - return 1; - - if (subscriberId >= p->subscriberCount || subscriberId < 0) - return 1; - - p->subscriber[subscriberId].type = 0; - p->subscriber[subscriberId].pfnHook = NULL; - p->subscriber[subscriberId].hOwner = NULL; - while (p->subscriberCount && p->subscriber[p->subscriberCount-1].type == 0) - p->subscriberCount--; - if (p->subscriberCount == 0) { - mir_free(p->subscriber); - p->subscriber = NULL; - } - return 0; -} - -MIR_CORE_DLL(void) KillModuleEventHooks(HINSTANCE hInst) -{ - mir_cslock lck(csHooks); - - for (int i = hooks.getCount()-1; i >= 0; i--) { - if (hooks[i]->subscriberCount == 0) - continue; - - for (int j = hooks[i]->subscriberCount-1; j >= 0; j--) { - if (hooks[i]->subscriber[j].hOwner != hInst) - continue; - - char szModuleName[ MAX_PATH ]; - GetModuleFileNameA(hooks[i]->subscriber[j].hOwner, szModuleName, sizeof(szModuleName)); - UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1)); - if (hooks[i]->subscriberCount == 0) - break; - } - } -} - -MIR_CORE_DLL(void) KillObjectEventHooks(void* pObject) -{ - mir_cslock lck(csHooks); - - for (int i = hooks.getCount()-1; i >= 0; i--) { - if (hooks[i]->subscriberCount == 0) - continue; - - for (int j = hooks[i]->subscriberCount-1; j >= 0; j--) { - if (hooks[i]->subscriber[j].object == pObject) { - UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1)); - if (hooks[i]->subscriberCount == 0) - break; - } - } - } -} - -static void DestroyHooks() -{ - mir_cslock lck(csHooks); - - for (int i=0; i < hooks.getCount(); i++) { - THook* p = hooks[i]; - if (p->subscriberCount) - mir_free(p->subscriber); - DeleteCriticalSection(&p->csHook); - mir_free(p); - } -} - -/////////////////////SERVICES - -static __inline TService* FindServiceByName(const char *name) -{ - unsigned hash = mir_hashstr(name); - return services.find((TService*)&hash); -} - -static HANDLE CreateServiceInt(int type, const char *name, MIRANDASERVICE serviceProc, void* object, LPARAM lParam) -{ - if (name == NULL) - return NULL; - - TService tmp; - tmp.nameHash = mir_hashstr(name); - - mir_cslock lck(csServices); - - if (services.getIndex(&tmp) != -1) - return NULL; - - TService* p = (TService*)mir_alloc(sizeof(*p) + strlen(name)); - strcpy(p->name, name); - p->nameHash = tmp.nameHash; - p->pfnService = serviceProc; - p->hOwner = GetInstByAddress(serviceProc); - p->flags = type; - p->lParam = lParam; - p->object = object; - services.insert(p); - - return (HANDLE)tmp.nameHash; -} - -MIR_CORE_DLL(HANDLE) CreateServiceFunction(const char *name, MIRANDASERVICE serviceProc) -{ - return CreateServiceInt(0, name, serviceProc, 0, 0); -} - -MIR_CORE_DLL(HANDLE) CreateServiceFunctionParam(const char *name, MIRANDASERVICEPARAM serviceProc, LPARAM lParam) -{ - return CreateServiceInt(1, name, (MIRANDASERVICE)serviceProc, 0, lParam); -} - -MIR_CORE_DLL(HANDLE) CreateServiceFunctionObj(const char *name, MIRANDASERVICEOBJ serviceProc, void* object) -{ - return CreateServiceInt(2, name, (MIRANDASERVICE)serviceProc, object, 0); -} - -MIR_CORE_DLL(HANDLE) CreateServiceFunctionObjParam(const char *name, MIRANDASERVICEOBJPARAM serviceProc, void* object, LPARAM lParam) -{ - return CreateServiceInt(3, name, (MIRANDASERVICE)serviceProc, object, lParam); -} - -MIR_CORE_DLL(int) DestroyServiceFunction(HANDLE hService) -{ - mir_cslock lck(csServices); - - int idx; - if ((idx = services.getIndex((TService*)&hService)) != -1) { - mir_free(services[idx]); - services.remove(idx); - } - - return 0; -} - -MIR_CORE_DLL(int) ServiceExists(const char *name) -{ - if (name == NULL) - return FALSE; - - mir_cslock lck(csServices); - return FindServiceByName(name) != NULL; -} - -MIR_CORE_DLL(INT_PTR) CallService(const char *name, WPARAM wParam, LPARAM lParam) -{ - if (name == NULL) - return CALLSERVICE_NOTFOUND; - - TService *pService; - { - mir_cslock lck(csServices); - if ((pService = FindServiceByName(name)) == NULL) - return CALLSERVICE_NOTFOUND; - } - - MIRANDASERVICE pfnService = pService->pfnService; - int flags = pService->flags; - LPARAM fnParam = pService->lParam; - void* object = pService->object; - switch(flags) { - case 1: return ((MIRANDASERVICEPARAM)pfnService)(wParam, lParam, fnParam); - case 2: return ((MIRANDASERVICEOBJ)pfnService)(object, wParam, lParam); - case 3: return ((MIRANDASERVICEOBJPARAM)pfnService)(object, wParam, lParam, fnParam); - default: return pfnService(wParam, lParam); -} } - -static void CALLBACK CallServiceToMainAPCFunc(ULONG_PTR dwParam) -{ - TServiceToMainThreadItem *item = (TServiceToMainThreadItem*) dwParam; - item->result = CallService(item->name, item->wParam, item->lParam); - SetEvent(item->hDoneEvent); -} - -MIR_CORE_DLL(INT_PTR) CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam) -{ - if (name == NULL) - return CALLSERVICE_NOTFOUND; - - // the service is looked up within the main thread, since the time it takes - // for the APC queue to clear the service being called maybe removed. - // even thou it may exists before the call, the critsec can't be locked between calls. - if (GetCurrentThreadId() == mainThreadId) - return CallService(name, wParam, lParam); - - TServiceToMainThreadItem item; - item.wParam = wParam; - item.lParam = lParam; - item.name = name; - item.hDoneEvent = getThreadEvent(); - QueueMainThread(CallServiceToMainAPCFunc, &item, item.hDoneEvent); - return item.result; -} - -MIR_CORE_DLL(int) CallFunctionAsync(void (__stdcall *func)(void *), void *arg) -{ - if (GetCurrentThreadId() == mainThreadId) - func(arg); - else - QueueMainThread((PAPCFUNC)func, arg, 0); - return 0; -} - -MIR_CORE_DLL(void) KillModuleServices(HINSTANCE hInst) -{ - mir_cslock lck(csServices); - - for (int i = services.getCount()-1; i >= 0; i--) { - if (services[i]->hOwner == hInst) { - char szModuleName[ MAX_PATH ]; - GetModuleFileNameA(services[i]->hOwner, szModuleName, sizeof(szModuleName)); - DestroyServiceFunction((HANDLE)services[i]->nameHash); - } - } -} - -MIR_CORE_DLL(void) KillObjectServices(void* pObject) -{ - mir_cslock lck(csServices); - - for (int i = services.getCount()-1; i >= 0; i--) - if (services[i]->object == pObject) - DestroyServiceFunction((HANDLE)services[i]->nameHash); -} - -static void DestroyServices() -{ - mir_cslock lck(csServices); - - for (int j=0; j < services.getCount(); j++) - mir_free(services[j]); -} - -/////////////////////////////////////////////////////////////////////////////// - -static int sttComparePlugins(const HINSTANCE__* p1, const HINSTANCE__* p2) -{ - if (p1 == p2) - return 0; - - return (p1 < p2) ? -1 : 1; -} - -LIST pluginListAddr(10, sttComparePlugins); - -MIR_CORE_DLL(void) RegisterModule(HINSTANCE hInst) -{ - pluginListAddr.insert(hInst); -} - -MIR_CORE_DLL(void) UnregisterModule(HINSTANCE hInst) -{ - pluginListAddr.remove(hInst); -} - -MIR_CORE_DLL(HINSTANCE) GetInstByAddress(void* codePtr) -{ - if (pluginListAddr.getCount() == 0) - return NULL; - - int idx; - List_GetIndex((SortedList*)&pluginListAddr, codePtr, &idx); - if (idx > 0) - idx--; - - HINSTANCE result = pluginListAddr[idx]; - if (result < hInst && codePtr > hInst) - result = hInst; - else if (idx == 0 && codePtr < (void*)result) - result = NULL; - - return result; -} - -/////////////////////////////////////////////////////////////////////////////// - -int InitialiseModularEngine(void) -{ - InitializeCriticalSection(&csHooks); - InitializeCriticalSection(&csServices); - - mainThreadId = GetCurrentThreadId(); - return 0; -} - -void DestroyModularEngine(void) -{ - DestroyHooks(); - DeleteCriticalSection(&csHooks); - - DestroyServices(); - DeleteCriticalSection(&csServices); -} diff --git a/src/mir_core/mstring.cpp b/src/mir_core/mstring.cpp deleted file mode 100644 index 8d071b61c1..0000000000 --- a/src/mir_core/mstring.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// CMBaseString - -class CNilMStringData : public CMStringData -{ -public: - CNilMStringData(); - -public: - wchar_t achNil[2]; -}; - -CNilMStringData::CNilMStringData() -{ - nRefs = 2; // Never gets freed - nDataLength = 0; - nAllocLength = 0; - achNil[0] = 0; - achNil[1] = 0; -} - -static CNilMStringData m_nil; - -///////////////////////////////////////////////////////////////////////////////////////// -// CMBaseString - -MIR_CORE_DLL(CMStringData*) mirstr_allocate(int nChars, int nCharSize) -{ - nChars++; // nil char - size_t nDataBytes = nCharSize * nChars; - size_t nTotalSize = nDataBytes + sizeof(CMStringData); - - CMStringData *pData = static_cast(malloc(nTotalSize)); - if (pData == NULL) - return NULL; - - pData->nRefs = 1; - pData->nAllocLength = nChars - 1; - pData->nDataLength = 0; - return pData; -} - -MIR_CORE_DLL(void) mirstr_free(CMStringData *pData) -{ - free(pData); -} - -MIR_CORE_DLL(CMStringData*) mirstr_realloc(CMStringData* pData, int nChars, int nCharSize) -{ - nChars++; // nil char - ULONG nDataBytes = nCharSize * nChars; - ULONG nTotalSize = nDataBytes + sizeof(CMStringData); - - CMStringData *pNewData = static_cast(realloc(pData, nTotalSize)); - if (pNewData == NULL) - return NULL; - - pNewData->nAllocLength = nChars - 1; - return pNewData; -} - -MIR_CORE_DLL(CMStringData*) mirstr_getNil() -{ - m_nil.AddRef(); - return &m_nil; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CMStringData - -MIR_CORE_DLL(void) mirstr_lock(CMStringData* pThis) -{ - pThis->nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary - if (pThis->nRefs == 0) - pThis->nRefs = -1; -} - -MIR_CORE_DLL(void) mirstr_release(CMStringData* pThis) -{ - if (InterlockedDecrement(&pThis->nRefs) <= 0) - mirstr_free(pThis); -} - -MIR_CORE_DLL(void) mirstr_unlock(CMStringData* pThis) -{ - if (pThis->IsLocked()) - { - pThis->nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary - if (pThis->nRefs == 0) - pThis->nRefs = 1; - } -} diff --git a/src/mir_core/path.cpp b/src/mir_core/path.cpp deleted file mode 100644 index ab0ee26b14..0000000000 --- a/src/mir_core/path.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -static char szMirandaPath[MAX_PATH]; -static WCHAR szMirandaPathW[MAX_PATH]; - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(int) PathIsAbsolute(const char *path) -{ - if (path && strlen(path) > 2) - if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) - return 1; - return 0; -} - -MIR_CORE_DLL(int) PathToRelative(const char *pSrc, char *pOut, const char *pBase) -{ - if (!pSrc || !pSrc[0] || strlen(pSrc) > MAX_PATH) - return 0; - - if (!PathIsAbsolute(pSrc)) - strncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); - else { - if (pBase == NULL) - pBase = szMirandaPath; - - size_t cbBaseLen = strlen(pBase); - if (!strnicmp(pSrc, pBase, cbBaseLen)) - strncpy_s(pOut, MAX_PATH, pSrc + cbBaseLen, _TRUNCATE); - else - strncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); - } - - return (int)strlen(pOut); -} - -MIR_CORE_DLL(int) PathToAbsolute(const char *pSrc, char *pOut, const char *base) -{ - if (!pSrc || !pSrc[0] || strlen(pSrc) > MAX_PATH) { - *pOut = 0; - return 0; - } - - char buf[MAX_PATH]; - if (pSrc[0] < ' ') - strncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); - - if (PathIsAbsolute(pSrc)) - return GetFullPathNameA(pSrc, MAX_PATH, pOut, NULL); - - if (base == NULL) - base = szMirandaPath; - - if (pSrc[0] == '\\') - pSrc++; - mir_snprintf(buf, SIZEOF(buf), "%s%s", base, pSrc); - return GetFullPathNameA(buf, SIZEOF(buf), pOut, NULL); -} - -MIR_CORE_DLL(void) CreatePathToFile(char *szFilePath) -{ - char *pszLastBackslash = strrchr(szFilePath, '\\'); - if (pszLastBackslash == NULL) - return; - - *pszLastBackslash = '\0'; - CreateDirectoryTree(szFilePath); - *pszLastBackslash = '\\'; -} - -MIR_CORE_DLL(int) CreateDirectoryTree(const char *szDir) -{ - char szTestDir[MAX_PATH]; - mir_strncpy(szTestDir, szDir, SIZEOF(szTestDir)); - - DWORD dwAttributes = GetFileAttributesA(szTestDir); - if (dwAttributes != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) - return 0; - - char *pszLastBackslash = strrchr(szTestDir, '\\'); - if (pszLastBackslash == NULL) - return 0; - - *pszLastBackslash = '\0'; - CreateDirectoryTree(szTestDir); - *pszLastBackslash = '\\'; - return (CreateDirectoryA(szTestDir, NULL) == 0) ? GetLastError() : 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(int) PathIsAbsoluteW(const WCHAR *path) -{ - if (path && wcslen(path) > 2) - if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) - return 1; - return 0; -} - -MIR_CORE_DLL(int) PathToRelativeW(const WCHAR *pSrc, WCHAR *pOut, const WCHAR *pBase) -{ - if (!pSrc || !pSrc[0] || wcslen(pSrc) > MAX_PATH) - return 0; - - if (!PathIsAbsoluteW(pSrc)) - wcsncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); - else { - if (pBase == NULL) - pBase = szMirandaPathW; - - size_t cbBaseLen = wcslen(pBase); - if (!wcsnicmp(pSrc, pBase, cbBaseLen)) - wcsncpy_s(pOut, MAX_PATH, pSrc + cbBaseLen, _TRUNCATE); - else - wcsncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); - } - return (int)wcslen(pOut); -} - -MIR_CORE_DLL(int) PathToAbsoluteW(const WCHAR *pSrc, WCHAR *pOut, const WCHAR *base) -{ - if (!pSrc || !pSrc[0] || wcslen(pSrc) > MAX_PATH) { - *pOut = 0; - return 0; - } - - WCHAR buf[MAX_PATH]; - if (pSrc[0] < ' ') - return mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); - - if (PathIsAbsoluteW(pSrc)) - return GetFullPathName(pSrc, MAX_PATH, pOut, NULL); - - if (base == NULL) - base = szMirandaPathW; - - if (pSrc[0] == '\\') - pSrc++; - - mir_sntprintf(buf, MAX_PATH, _T("%s%s"), base, pSrc); - return GetFullPathName(buf, MAX_PATH, pOut, NULL); -} - -MIR_CORE_DLL(void) CreatePathToFileW(WCHAR *wszFilePath) -{ - WCHAR *pszLastBackslash = wcsrchr(wszFilePath, '\\'); - if (pszLastBackslash == NULL) - return; - - *pszLastBackslash = '\0'; - CreateDirectoryTreeW(wszFilePath); - *pszLastBackslash = '\\'; -} - -MIR_CORE_DLL(int) CreateDirectoryTreeW(const WCHAR *szDir) -{ - WCHAR szTestDir[MAX_PATH]; - mir_wstrncpy(szTestDir, szDir, SIZEOF(szTestDir)); - - DWORD dwAttributes = GetFileAttributesW(szTestDir); - if (dwAttributes != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) - return 0; - - WCHAR *pszLastBackslash = wcsrchr(szTestDir, '\\'); - if (pszLastBackslash == NULL) - return 0; - - *pszLastBackslash = '\0'; - CreateDirectoryTreeW(szTestDir); - *pszLastBackslash = '\\'; - return (CreateDirectoryW(szTestDir, NULL) == 0) ? GetLastError() : 0; -} - -int InitPathUtils(void) -{ - GetModuleFileNameA(hInst, szMirandaPath, SIZEOF(szMirandaPath)); - char *p = strrchr(szMirandaPath, '\\'); - if (p) - p[1] = 0; - - GetModuleFileNameW(hInst, szMirandaPathW, SIZEOF(szMirandaPathW)); - WCHAR *tp = wcsrchr(szMirandaPathW, '\\'); - if (tp) - tp[1] = 0; - return 0; -} diff --git a/src/mir_core/protos.cpp b/src/mir_core/protos.cpp deleted file mode 100644 index 7015647bc3..0000000000 --- a/src/mir_core/protos.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-14 Miranda NG project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -#include -#include -#include -#include - -static HANDLE hAckEvent; - -void InitProtocols() -{ - hAckEvent = CreateHookableEvent(ME_PROTO_ACK); -} - -void UninitProtocols() -{ - if (hAckEvent) { - DestroyHookableEvent(hAckEvent); - hAckEvent = NULL; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(void) ProtoLogA(struct PROTO_INTERFACE *pThis, LPCSTR szFormat, va_list args) -{ - char buf[4096]; - int res = _vsnprintf(buf, sizeof(buf), szFormat, args); - CallService(MS_NETLIB_LOG, (WPARAM)pThis->m_hNetlibUser, (LPARAM)((res != -1) ? buf : CMStringA().FormatV(szFormat, args))); -} - -MIR_CORE_DLL(void) ProtoLogW(struct PROTO_INTERFACE *pThis, LPCWSTR wszFormat, va_list args) -{ - WCHAR buf[4096]; - int res = _vsnwprintf(buf, SIZEOF(buf), wszFormat, args); - CallService(MS_NETLIB_LOGW, (WPARAM)pThis->m_hNetlibUser, (LPARAM)((res != -1) ? buf : CMStringW().FormatV(wszFormat, args))); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(INT_PTR) ProtoBroadcastAck(const char *szModule, MCONTACT hContact, int type, int result, HANDLE hProcess, LPARAM lParam) -{ - if (type == ACKTYPE_AVATAR && hProcess) { - PROTO_AVATAR_INFORMATION* ai = (PROTO_AVATAR_INFORMATION*)hProcess; - if (ai->cbSize == sizeof(PROTO_AVATAR_INFORMATION)) { - PROTO_AVATAR_INFORMATIONW aiw = { sizeof(aiw), ai->hContact, ai->format }; - MultiByteToWideChar(CP_ACP, 0, ai->filename, -1, aiw.filename, SIZEOF(aiw.filename)); - - hProcess = &aiw; - ACKDATA ack = { sizeof(ACKDATA), szModule, hContact, type, result, hProcess, lParam }; - return NotifyEventHooks(hAckEvent, 0, (LPARAM)&ack); - } - } - - ACKDATA ack = { sizeof(ACKDATA), szModule, hContact, type, result, hProcess, lParam }; - return NotifyEventHooks(hAckEvent, 0, (LPARAM)&ack); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(INT_PTR) ProtoCallService(const char *szModule, const char *szService, WPARAM wParam, LPARAM lParam) -{ - if (szModule == NULL || szService == NULL) - return false; - - char str[MAXMODULELABELLENGTH * 2]; - strncpy_s(str, szModule, _TRUNCATE); - strncat_s(str, szService, _TRUNCATE); - return CallService(str, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(int) ProtoServiceExists(const char *szModule, const char *szService) -{ - if (szModule == NULL || szService == NULL) - return false; - - char str[MAXMODULELABELLENGTH * 2]; - strncpy_s(str, szModule, _TRUNCATE); - strncat_s(str, szService, _TRUNCATE); - return ServiceExists(str); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(void) ProtoConstructor(PROTO_INTERFACE *pThis, LPCSTR pszModuleName, LPCTSTR ptszUserName) -{ - pThis->m_iVersion = 2; - pThis->m_iStatus = pThis->m_iDesiredStatus = ID_STATUS_OFFLINE; - pThis->m_szModuleName = mir_strdup(pszModuleName); - pThis->m_hProtoIcon = (HANDLE)CallService("Skin2/Icons/IsManaged", (WPARAM)LoadSkinnedProtoIcon(pszModuleName, ID_STATUS_ONLINE), 0); - pThis->m_tszUserName = mir_tstrdup(ptszUserName); -} - -MIR_CORE_DLL(void) ProtoDestructor(PROTO_INTERFACE *pThis) -{ - mir_free(pThis->m_szModuleName); - mir_free(pThis->m_tszUserName); -} - -MIR_CORE_DLL(void) ProtoCreateService(PROTO_INTERFACE *pThis, const char* szService, ProtoServiceFunc serviceProc) -{ - char str[MAXMODULELABELLENGTH * 2]; - strncpy_s(str, pThis->m_szModuleName, _TRUNCATE); - strncat_s(str, szService, _TRUNCATE); - ::CreateServiceFunctionObj(str, (MIRANDASERVICEOBJ)*(void**)&serviceProc, pThis); -} - -MIR_CORE_DLL(void) ProtoCreateServiceParam(PROTO_INTERFACE *pThis, const char* szService, ProtoServiceFuncParam serviceProc, LPARAM lParam) -{ - char str[MAXMODULELABELLENGTH * 2]; - strncpy_s(str, pThis->m_szModuleName, _TRUNCATE); - strncat_s(str, szService, _TRUNCATE); - ::CreateServiceFunctionObjParam(str, (MIRANDASERVICEOBJPARAM)*(void**)&serviceProc, pThis, lParam); -} - -MIR_CORE_DLL(void) ProtoHookEvent(PROTO_INTERFACE *pThis, const char* szEvent, ProtoEventFunc handler) -{ - ::HookEventObj(szEvent, (MIRANDAHOOKOBJ)*(void**)&handler, pThis); -} - -MIR_CORE_DLL(HANDLE) ProtoCreateHookableEvent(PROTO_INTERFACE *pThis, const char* szName) -{ - char str[MAXMODULELABELLENGTH * 2]; - strncpy_s(str, pThis->m_szModuleName, _TRUNCATE); - strncat_s(str, szName, _TRUNCATE); - return CreateHookableEvent(str); -} - -MIR_CORE_DLL(void) ProtoForkThread(PROTO_INTERFACE *pThis, ProtoThreadFunc pFunc, void *param) -{ - UINT threadID; - CloseHandle((HANDLE)::mir_forkthreadowner((pThreadFuncOwner)*(void**)&pFunc, pThis, param, &threadID)); -} - -MIR_CORE_DLL(HANDLE) ProtoForkThreadEx(PROTO_INTERFACE *pThis, ProtoThreadFunc pFunc, void *param, UINT* threadID) -{ - UINT lthreadID; - return (HANDLE)::mir_forkthreadowner((pThreadFuncOwner)*(void**)&pFunc, pThis, param, threadID ? threadID : <hreadID); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(LPCTSTR) ProtoGetAvatarExtension(int format) -{ - if (format == PA_FORMAT_PNG) - return _T(".png"); - if (format == PA_FORMAT_JPEG) - return _T(".jpg"); - if (format == PA_FORMAT_ICON) - return _T(".ico"); - if (format == PA_FORMAT_BMP) - return _T(".bmp"); - if (format == PA_FORMAT_GIF) - return _T(".gif"); - if (format == PA_FORMAT_SWF) - return _T(".swf"); - if (format == PA_FORMAT_XML) - return _T(".xml"); - - return _T(""); -} - -MIR_CORE_DLL(int) ProtoGetAvatarFormat(const TCHAR *ptszFileName) -{ - if (ptszFileName == NULL) - return PA_FORMAT_UNKNOWN; - - const TCHAR *ptszExt = _tcsrchr(ptszFileName, '.'); - if (ptszExt == NULL) - return PA_FORMAT_UNKNOWN; - - if (!_tcsicmp(ptszExt, _T(".png"))) - return PA_FORMAT_PNG; - - if (!_tcsicmp(ptszExt, _T(".jpg")) || !_tcsicmp(ptszExt, _T(".jpeg"))) - return PA_FORMAT_JPEG; - - if (!_tcsicmp(ptszExt, _T(".ico"))) - return PA_FORMAT_ICON; - - if (!_tcsicmp(ptszExt, _T(".bmp")) || !_tcsicmp(ptszExt, _T(".rle"))) - return PA_FORMAT_BMP; - - if (!_tcsicmp(ptszExt, _T(".gif"))) - return PA_FORMAT_GIF; - - if (!_tcsicmp(ptszExt, _T(".swf"))) - return PA_FORMAT_SWF; - - if (!_tcsicmp(ptszExt, _T(".xml"))) - return PA_FORMAT_XML; - - return PA_FORMAT_UNKNOWN; -} - -MIR_CORE_DLL(int) ProtoGetBufferFormat(const void *pBuffer, const TCHAR **ptszExtension) -{ - if (!memcmp(pBuffer, "%PNG", 4)) { - if (ptszExtension) *ptszExtension = _T(".png"); - return PA_FORMAT_PNG; - } - - if (!memcmp(pBuffer, "GIF8", 4)) { - if (ptszExtension) *ptszExtension = _T(".gif"); - return PA_FORMAT_GIF; - } - - if (!memicmp(pBuffer, "> (32-(n)))) - -static void shaHashBlock(mir_sha1_ctx *ctx) -{ - int t; - unsigned long A, B, C, D, E, TEMP; - - for (t = 16; t <= 79; t++) - ctx->W[t] = - SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); - - A = ctx->H[0]; - B = ctx->H[1]; - C = ctx->H[2]; - D = ctx->H[3]; - E = ctx->H[4]; - - for (t = 0; t <= 19; t++) { - TEMP = SHA_ROTL(A, 5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (t = 20; t <= 39; t++) { - TEMP = SHA_ROTL(A, 5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (t = 40; t <= 59; t++) { - TEMP = SHA_ROTL(A, 5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (t = 60; t <= 79; t++) { - TEMP = SHA_ROTL(A, 5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - - ctx->H[0] += A; - ctx->H[1] += B; - ctx->H[2] += C; - ctx->H[3] += D; - ctx->H[4] += E; -} - -MIR_CORE_DLL(void) mir_sha1_init(mir_sha1_ctx *ctx) -{ - ctx->lenW = 0; - ctx->sizeHi = ctx->sizeLo = 0; - - /* Initialize H with the magic constants (see FIPS180 for constants) - */ - ctx->H[0] = 0x67452301L; - ctx->H[1] = 0xefcdab89L; - ctx->H[2] = 0x98badcfeL; - ctx->H[3] = 0x10325476L; - ctx->H[4] = 0xc3d2e1f0L; - - for (int i = 0; i < 80; i++) - ctx->W[i] = 0; -} - -MIR_CORE_DLL(void) mir_sha1_append(mir_sha1_ctx *ctx, const BYTE *dataIn, int len) -{ - /* Read the data into W and process blocks as they get full - */ - for (int i = 0; i < len; i++) { - ctx->W[ctx->lenW / 4] <<= 8; - ctx->W[ctx->lenW / 4] |= (unsigned long)dataIn[i]; - if ((++ctx->lenW) % 64 == 0) { - shaHashBlock(ctx); - ctx->lenW = 0; - } - ctx->sizeLo += 8; - ctx->sizeHi += (ctx->sizeLo < 8); - } -} - -MIR_CORE_DLL(void) mir_sha1_finish(mir_sha1_ctx *ctx, BYTE hashout[20]) -{ - unsigned char pad0x80 = 0x80; - unsigned char pad0x00 = 0x00; - unsigned char padlen[8]; - int i; - - /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length - */ - padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); - padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); - padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); - padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); - padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); - padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); - padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); - padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); - mir_sha1_append(ctx, &pad0x80, 1); - while (ctx->lenW != 56) - mir_sha1_append(ctx, &pad0x00, 1); - mir_sha1_append(ctx, padlen, 8); - - /* Output hash - */ - for (i = 0; i < 20; i++) { - hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); - ctx->H[i / 4] <<= 8; - } - - /* - * Re-initialize the context (also zeroizes contents) - */ - mir_sha1_init(ctx); -} - -MIR_CORE_DLL(void) mir_sha1_hash(BYTE *dataIn, int len, BYTE hashout[20]) -{ - mir_sha1_ctx ctx; - - mir_sha1_init(&ctx); - mir_sha1_append(&ctx, dataIn, len); - mir_sha1_finish(&ctx, hashout); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(void) mir_hmac_sha1(BYTE hashout[MIR_SHA1_HASH_SIZE], const BYTE *key, size_t keylen, const BYTE *text, size_t textlen) -{ - const unsigned SHA_BLOCKSIZE = 64; - - BYTE mdkey[MIR_SHA1_HASH_SIZE], k_ipad[SHA_BLOCKSIZE], k_opad[SHA_BLOCKSIZE]; - mir_sha1_ctx ctx; - - if (keylen > SHA_BLOCKSIZE) { - mir_sha1_init(&ctx); - mir_sha1_append(&ctx, key, (int)keylen); - mir_sha1_finish(&ctx, mdkey); - keylen = 20; - key = mdkey; - } - - memcpy(k_ipad, key, keylen); - memcpy(k_opad, key, keylen); - memset(k_ipad+keylen, 0x36, SHA_BLOCKSIZE - keylen); - memset(k_opad+keylen, 0x5c, SHA_BLOCKSIZE - keylen); - - for (unsigned i = 0; i < keylen; i++) { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - - mir_sha1_init(&ctx); - mir_sha1_append(&ctx, k_ipad, SHA_BLOCKSIZE); - mir_sha1_append(&ctx, text, (int)textlen); - mir_sha1_finish(&ctx, hashout); - - mir_sha1_init(&ctx); - mir_sha1_append(&ctx, k_opad, SHA_BLOCKSIZE); - mir_sha1_append(&ctx, hashout, MIR_SHA1_HASH_SIZE); - mir_sha1_finish(&ctx, hashout); -} diff --git a/src/mir_core/src/cmdline.cpp b/src/mir_core/src/cmdline.cpp new file mode 100644 index 0000000000..1b9bc11c20 --- /dev/null +++ b/src/mir_core/src/cmdline.cpp @@ -0,0 +1,89 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-14 Miranda NG project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +/* command line support */ + +struct CmdLineParam +{ + __inline CmdLineParam(LPCTSTR _name, LPCTSTR _value) : + name(_name), value(_value) + {} + + LPCTSTR name, value; +}; + +static int CompareParams(const CmdLineParam *p1, const CmdLineParam *p2) +{ + return _tcscmp(p1->name, p2->name); +} + +static OBJLIST arParams(5, CompareParams); + +MIR_CORE_DLL(void) CmdLine_Parse(LPTSTR ptszCmdLine) +{ + bool bPrevSpace = true; + for (LPTSTR p = ptszCmdLine; *p; p++) { + if ( *p == ' ' || *p == '\t') { + *p = 0; + bPrevSpace = true; + continue; + } + + // new word beginning + if (bPrevSpace) { + bPrevSpace = false; + if (*p != '/' && *p != '-') // not an option - skip it + continue; + } + else continue; // skip a text that isn't an option + + TCHAR *pOptionName = p+1; + if ((p = _tcspbrk(pOptionName, _T(" \t=:"))) == NULL) { // no more text in string + arParams.insert(new CmdLineParam(pOptionName, _T(""))); + break; + } + + if (*p == ' ' || *p == '\t') { + arParams.insert(new CmdLineParam(pOptionName, _T(""))); + p--; // the cycle will wipe this space automatically + continue; + } + + // parameter with value + *p = 0; + arParams.insert(new CmdLineParam(pOptionName, ++p)); + if ((p = _tcspbrk(p, _T(" \t"))) == NULL) // no more text in string + break; + + p--; // the cycle will wipe this space automatically + } +} + +MIR_CORE_DLL(LPCTSTR) CmdLine_GetOption(const TCHAR* ptszParameter) +{ + CmdLineParam tmp(ptszParameter, 0); + int idx = arParams.getIndex(&tmp); + return (idx == -1) ? NULL : arParams[idx].value; +} diff --git a/src/mir_core/src/commonheaders.h b/src/mir_core/src/commonheaders.h new file mode 100644 index 0000000000..083ccd8e87 --- /dev/null +++ b/src/mir_core/src/commonheaders.h @@ -0,0 +1,69 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#define WINVER 0x0700 +#define _WIN32_WINNT 0x0700 +#define _WIN32_IE 0x0601 + +#define INCL_WINSOCK_API_TYPEDEFS 1 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "miranda.h" + +#include +#include + + +extern TCHAR tszDefaultLang[100]; + +void GetDefaultLang(); \ No newline at end of file diff --git a/src/mir_core/src/db.cpp b/src/mir_core/src/db.cpp new file mode 100644 index 0000000000..079225682a --- /dev/null +++ b/src/mir_core/src/db.cpp @@ -0,0 +1,370 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +MIDatabase *currDb = NULL; + +///////////////////////////////////////////////////////////////////////////////////////// +// getting data + +MIR_CORE_DLL(int) db_get_b(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) +{ + if (currDb != NULL) { + DBVARIANT dbv; + if (!currDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) + { + switch(dbv.type) { + case DBVT_BYTE: return dbv.bVal; + case DBVT_WORD: return BYTE(dbv.wVal); + case DBVT_DWORD: return BYTE(dbv.dVal); + } + currDb->FreeVariant(&dbv); + } + } + return errorValue; +} + +MIR_CORE_DLL(int) db_get_w(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) +{ + if (currDb != NULL) { + DBVARIANT dbv; + if (!currDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { + switch(dbv.type) { + case DBVT_BYTE: return dbv.bVal; + case DBVT_WORD: return dbv.wVal; + case DBVT_DWORD: return WORD(dbv.dVal); + } + currDb->FreeVariant(&dbv); + } + } + return errorValue; +} + +MIR_CORE_DLL(DWORD) db_get_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD errorValue) +{ + if (currDb != NULL) { + DBVARIANT dbv; + if (!currDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { + switch(dbv.type) { + case DBVT_BYTE: return dbv.bVal; + case DBVT_WORD: return dbv.wVal; + case DBVT_DWORD: return dbv.dVal; + default: currDb->FreeVariant(&dbv); + } + currDb->FreeVariant(&dbv); + } + } + + return errorValue; +} + +MIR_CORE_DLL(INT_PTR) db_get(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) +{ + if (currDb == NULL) + return 1; + + return currDb->GetContactSetting(hContact, szModule, szSetting, dbv); +} + +MIR_CORE_DLL(INT_PTR) db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType) +{ + if (currDb == NULL) + return 1; + + dbv->type = (BYTE)nType; + return currDb->GetContactSettingStr(hContact, szModule, szSetting, dbv); +} + +MIR_CORE_DLL(char*) db_get_sa(MCONTACT hContact, const char *szModule, const char *szSetting) +{ + if (currDb == NULL) + return NULL; + + DBVARIANT dbv = { DBVT_ASCIIZ }; + return currDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv) ? NULL : dbv.pszVal; +} + +MIR_CORE_DLL(wchar_t*) db_get_wsa(MCONTACT hContact, const char *szModule, const char *szSetting) +{ + if (currDb == NULL) + return NULL; + + DBVARIANT dbv = { DBVT_WCHAR }; + return currDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv) ? NULL : dbv.pwszVal; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// getting static data + +MIR_CORE_DLL(int) db_get_static(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) +{ + if (currDb == NULL) + return 1; + + DBVARIANT dbv; + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = pDest; + dbv.cchVal = cbDest; + return currDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(int) db_get_static_utf(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) +{ + if (currDb == NULL) + return 1; + + DBVARIANT dbv; + dbv.type = DBVT_UTF8; + dbv.pszVal = pDest; + dbv.cchVal = cbDest; + return currDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(int) db_get_wstatic(MCONTACT hContact, const char *szModule, const char *szSetting, WCHAR *pDest, int cbDest) +{ + if (currDb == NULL) + return 1; + + DBVARIANT dbv; + dbv.type = DBVT_WCHAR; + dbv.pwszVal = pDest; + dbv.cchVal = cbDest; + return currDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// setting data + +MIR_CORE_DLL(INT_PTR) db_set(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) +{ + if (currDb == NULL) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value = *dbv; + return currDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_b(MCONTACT hContact, const char *szModule, const char *szSetting, BYTE val) +{ + if (currDb == NULL) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_BYTE; + cws.value.bVal = val; + return currDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_w(MCONTACT hContact, const char *szModule, const char *szSetting, WORD val) +{ + if (currDb == NULL) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_WORD; + cws.value.wVal = val; + return currDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD val) +{ + if (currDb == NULL) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_DWORD; + cws.value.dVal = val; + return currDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_s(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) +{ + if (currDb == NULL) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_ASCIIZ; + cws.value.pszVal = (char*)(val == NULL ? "" : val); + return currDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_ws(MCONTACT hContact, const char *szModule, const char *szSetting, const WCHAR *val) +{ + if (currDb == NULL) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_WCHAR; + cws.value.pwszVal = (WCHAR*)(val == NULL ? L"" : val); + return currDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_utf(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) +{ + if (currDb == NULL) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_UTF8; + cws.value.pszVal = (char*)(val == NULL ? "" : val); + return currDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_blob(MCONTACT hContact, const char *szModule, const char *szSetting, void *val, unsigned len) +{ + if (currDb == NULL) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_BLOB; + cws.value.cpbVal = (WORD)len; + cws.value.pbVal = (unsigned char*)val; + return currDb->WriteContactSetting(hContact, &cws); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// events + +MIR_CORE_DLL(HANDLE) db_event_add(MCONTACT hContact, DBEVENTINFO *dbei) +{ + return (currDb == NULL) ? 0 : currDb->AddEvent(hContact, dbei); +} + +MIR_CORE_DLL(int) db_event_count(MCONTACT hContact) +{ + return (currDb == NULL) ? 0 : currDb->GetEventCount(hContact); +} + +MIR_CORE_DLL(int) db_event_delete(MCONTACT hContact, HANDLE hDbEvent) +{ + return (currDb == NULL) ? 0 : currDb->DeleteEvent(hContact, hDbEvent); +} + +MIR_CORE_DLL(HANDLE) db_event_first(MCONTACT hContact) +{ + return (currDb == NULL) ? 0 : currDb->FindFirstEvent(hContact); +} + +MIR_CORE_DLL(HANDLE) db_event_firstUnread(MCONTACT hContact) +{ + return (currDb == NULL) ? 0 : currDb->FindFirstUnreadEvent(hContact); +} + +MIR_CORE_DLL(int) db_event_get(HANDLE hDbEvent, DBEVENTINFO *dbei) +{ + return (currDb == NULL) ? 1 : currDb->GetEvent(hDbEvent, dbei); +} + +MIR_CORE_DLL(int) db_event_getBlobSize(HANDLE hDbEvent) +{ + return (currDb == NULL) ? 0 : currDb->GetBlobSize(hDbEvent); +} + +MIR_CORE_DLL(MCONTACT) db_event_getContact(HANDLE hDbEvent) +{ + return (currDb == NULL) ? 0 : currDb->GetEventContact(hDbEvent); +} + +MIR_CORE_DLL(HANDLE) db_event_last(MCONTACT hContact) +{ + return (currDb == NULL) ? 0 : currDb->FindLastEvent(hContact); +} + +MIR_CORE_DLL(int) db_event_markRead(MCONTACT hContact, HANDLE hDbEvent) +{ + return (currDb == NULL) ? 0 : currDb->MarkEventRead(hContact, hDbEvent); +} + +MIR_CORE_DLL(HANDLE) db_event_next(MCONTACT hContact, HANDLE hDbEvent) +{ + return (currDb == NULL) ? 0 : currDb->FindNextEvent(hContact, hDbEvent); +} + +MIR_CORE_DLL(HANDLE) db_event_prev(MCONTACT hContact, HANDLE hDbEvent) +{ + return (currDb == NULL) ? 0 : currDb->FindPrevEvent(hContact, hDbEvent); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// misc functions + +MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv) +{ + return (currDb == NULL) ? 1 : currDb->FreeVariant(dbv); +} + +MIR_CORE_DLL(INT_PTR) db_unset(MCONTACT hContact, const char *szModule, const char *szSetting) +{ + if (currDb == NULL) + return 1; + + return currDb->DeleteContactSetting(hContact, szModule, szSetting); +} + +MIR_CORE_DLL(DBCachedContact*) db_get_contact(MCONTACT hContact) +{ + return (currDb == NULL) ? NULL : currDb->m_cache->GetCachedContact(hContact); +} + +MIR_CORE_DLL(MCONTACT) db_find_first(const char *szProto) +{ + return (currDb == NULL) ? NULL : currDb->FindFirstContact(szProto); +} + +MIR_CORE_DLL(MCONTACT) db_find_next(MCONTACT hContact, const char *szProto) +{ + return (currDb == NULL) ? NULL : currDb->FindNextContact(hContact, szProto); +} + +extern "C" MIR_CORE_DLL(void) db_setCurrent(MIDatabase *_db) +{ + currDb = _db; + + // try to get the langpack's name from a profile + ptrT langpack(db_get_tsa(NULL, "Langpack", "Current")); + if (langpack && langpack[0] != '\0') + LoadLangPack(langpack); + else + GetDefaultLang(); +} + +MIR_CORE_DLL(BOOL) db_set_resident(const char *szModule, const char *szService, BOOL bEnable) +{ + if (currDb == NULL || szModule == NULL || szService == NULL) + return FALSE; + + char str[MAXMODULELABELLENGTH * 2]; + mir_snprintf(str, SIZEOF(str), "%s/%s", szModule, szService); + return currDb->SetSettingResident(bEnable, str); +} diff --git a/src/mir_core/src/http.cpp b/src/mir_core/src/http.cpp new file mode 100644 index 0000000000..b47cdd4e9c --- /dev/null +++ b/src/mir_core/src/http.cpp @@ -0,0 +1,168 @@ +/* +Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "commonheaders.h" + +///////////////////////////////////////////////////////////////////////////////////////// + +static const char szHexDigits[] = "0123456789ABCDEF"; + +MIR_CORE_DLL(char*) mir_urlEncode(const char *szUrl) +{ + if (szUrl == NULL) + return NULL; + + const BYTE *s; + int outputLen; + for (outputLen = 0, s = (const BYTE*)szUrl; *s; s++) { + if (('0' <= *s && *s <= '9') || //0-9 + ('A' <= *s && *s <= 'Z') || //ABC...XYZ + ('a' <= *s && *s <= 'z') || //abc...xyz + *s == '-' || *s == '_' || *s == '.' || *s == ' ') outputLen++; + else outputLen += 3; + } + + char *szOutput = (char*)mir_alloc(outputLen+1); + if (szOutput == NULL) + return NULL; + + char *d = szOutput; + for (s = (const BYTE*)szUrl; *s; s++) { + if (('0' <= *s && *s <= '9') || //0-9 + ('A' <= *s && *s <= 'Z') || //ABC...XYZ + ('a' <= *s && *s <= 'z') || //abc...xyz + *s == '-' || *s == '_' || *s == '.') *d++ = *s; + else if (*s == ' ') *d++='+'; + else { + *d++ = '%'; + *d++ = szHexDigits[*s >> 4]; + *d++ = szHexDigits[*s & 0xF]; + } + } + *d = '\0'; + return szOutput; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +MIR_CORE_DLL(char*) mir_base64_encode(const BYTE *input, unsigned inputLen) +{ + if (input == NULL) + return NULL; + + unsigned outputLen = mir_base64_encode_bufsize(inputLen); + char *output = (char*)mir_alloc(outputLen); + if (output == NULL) + return NULL; + + return mir_base64_encodebuf(input, inputLen, output, outputLen); +} + +MIR_CORE_DLL(char*) mir_base64_encodebuf(const BYTE *input, unsigned inputLen, char *output, unsigned outputLen) +{ + if (input == NULL) + return NULL; + + if (outputLen < mir_base64_encode_bufsize(inputLen)) + return NULL; + + char *p = output; + for (unsigned i=0; i < inputLen; ) { + int rest = 0; + BYTE chr[3]; + chr[0] = input[i++]; + chr[1] = (i < inputLen) ? input[i++] : rest++, 0; + chr[2] = (i < inputLen) ? input[i++] : rest++, 0; + + *p++ = cb64[ chr[0] >> 2 ]; + *p++ = cb64[ ((chr[0] & 0x03) << 4) | (chr[1] >> 4) ]; + int b2 = ((chr[1] & 0x0F) << 2) | (chr[2] >> 6), + b3 = chr[2] & 0x3F; + + if (rest == 2) { *p++ = '='; *p++ = '='; } + else if (rest == 1) { *p++ = cb64[b2]; *p++ = '='; } + else { *p++ = cb64[b2]; *p++ = cb64[b3]; } + } + + *p = 0; + return output; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static BYTE Base64DecodeTable[] = +{ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 +}; + +MIR_CORE_DLL(void*) mir_base64_decode(const char *input, unsigned *outputLen) +{ + if (input == NULL) + return NULL; + + size_t length = strlen(input); + size_t nLength = (length / 4) * 3; + const char *stop = input + length; + + char *output = (char *)mir_alloc(nLength+1); + char *p = output; + + while (input < stop) { + BYTE e[4]; + for (int i=0; i < 4; ) { + if (*input == '\n' || *input == '\r') // simply skip a char + input++; + else if (*input == 0) // do not advance input + e[i++] = (BYTE)-1; + else + e[i++] = Base64DecodeTable[*input++]; + } + + if (e[0] == (BYTE)-1 || e[1] == (BYTE)-1) + break; + + *p++ = (e[0] << 2) | (e[1] >> 4); + if (e[2] != (BYTE)-1) + *p++ = ((e[1] & 15) << 4) | (e[2] >> 2); + if (e[3] != (BYTE)-1) + *p++ = ((e[2] & 3) << 6) | e[3]; + } + + *p = 0; + + if (outputLen != NULL) + *outputLen = p - output; + + return output; +} diff --git a/src/mir_core/src/icons.cpp b/src/mir_core/src/icons.cpp new file mode 100644 index 0000000000..77c924be25 --- /dev/null +++ b/src/mir_core/src/icons.cpp @@ -0,0 +1,77 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-14 Miranda NG project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +#include +#include "..\src\core\stdplug.h" + +MIR_CORE_DLL(void) Icon_Register(HINSTANCE hInst, const char *szSection, IconItem *pIcons, size_t iCount, char *prefix, int hLangpack) +{ + TCHAR szFile[MAX_PATH]; + GetModuleFileName(hInst, szFile, MAX_PATH); + + SKINICONDESC sid = { sizeof(sid) }; + sid.ptszDefaultFile = szFile; + sid.pszSection = (char*)szSection; + sid.flags = SIDF_PATH_TCHAR; + + for (unsigned i = 0; i < iCount; i++) { + char szSetting[100]; + if (prefix) { + mir_snprintf(szSetting, SIZEOF(szSetting), "%s_%s", prefix, pIcons[i].szName); + sid.pszName = szSetting; + } + else sid.pszName = pIcons[i].szName; + + sid.cx = sid.cy = pIcons[i].size; + sid.pszDescription = pIcons[i].szDescr; + sid.iDefaultIndex = -pIcons[i].defIconID; + pIcons[i].hIcolib = (HANDLE)CallService("Skin2/Icons/AddIcon", hLangpack, (LPARAM)&sid); + } +} + +MIR_CORE_DLL(void) Icon_RegisterT(HINSTANCE hInst, const TCHAR *szSection, IconItemT *pIcons, size_t iCount, char *prefix, int hLangpack) +{ + TCHAR szFile[MAX_PATH]; + GetModuleFileName(hInst, szFile, MAX_PATH); + + SKINICONDESC sid = { sizeof(sid) }; + sid.ptszDefaultFile = szFile; + sid.ptszSection = (TCHAR*)szSection; + sid.flags = SIDF_ALL_TCHAR; + + for (unsigned i = 0; i < iCount; i++) { + char szSetting[100]; + if (prefix) { + mir_snprintf(szSetting, SIZEOF(szSetting), "%s_%s", prefix, pIcons[i].szName); + sid.pszName = szSetting; + } + else sid.pszName = pIcons[i].szName; + + sid.cx = sid.cy = pIcons[i].size; + sid.ptszDescription = pIcons[i].tszDescr; + sid.iDefaultIndex = -pIcons[i].defIconID; + pIcons[i].hIcolib = (HANDLE)CallService("Skin2/Icons/AddIcon", hLangpack, (LPARAM)&sid); + } +} diff --git a/src/mir_core/src/json/JSONChildren.cpp b/src/mir_core/src/json/JSONChildren.cpp new file mode 100644 index 0000000000..1eb9e29d46 --- /dev/null +++ b/src/mir_core/src/json/JSONChildren.cpp @@ -0,0 +1,98 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" + +#include "JSONChildren.h" +#include "JSONNode.h" + +void jsonChildren::inc(void){ + if (mysize == mycapacity){ //it's full + if (!mycapacity){ //the array hasn't been created yet + JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); + #ifdef JSON_LESS_MEMORY + array = json_malloc(1); + mycapacity = 1; + #else + array = json_malloc(8); //8 seems average for JSON, and it's only 64 bytes + mycapacity = 8; + #endif + } else { + #ifdef JSON_LESS_MEMORY + mycapacity += 1; //increment the size of the array + #else + mycapacity <<= 1; //double the size of the array + #endif + array = json_realloc(array, mycapacity); + } + } +} + +void jsonChildren::inc(json_index_t amount){ + if (!amount) return; + if (mysize + amount >= mycapacity){ //it's full + if (!mycapacity){ //the array hasn't been created yet + JSON_ASSERT(!array, JSON_TEXT("Expanding a 0 capacity array, but not null")); + #ifdef JSON_LESS_MEMORY + array = json_malloc(amount); + mycapacity = amount; + #else + array = json_malloc(amount > 8 ? amount : 8); //8 seems average for JSON, and it's only 64 bytes + mycapacity = amount > 8 ? amount : 8; + #endif + } else { + #ifdef JSON_LESS_MEMORY + mycapacity = mysize + amount; //increment the size of the array + #else + while(mysize + amount > mycapacity){ + mycapacity <<= 1; //double the size of the array + } + #endif + array = json_realloc(array, mycapacity); + } + } +} + +//actually deletes everything within the vector, this is safe to do on an empty or even a null array +void jsonChildren::deleteAll(void){ + json_foreach((*this), runner){ + JSON_ASSERT(*runner, JSON_TEXT("a null pointer within the children")); + JSONNode::deleteJSONNode(*runner); //this is why I can't do forward declaration + } +} + +void jsonChildren::doerase(JSONNode ** position, json_index_t number){ + JSON_ASSERT(array, JSON_TEXT("erasing something from a null array 2")); + JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 2")); + JSON_ASSERT(position + number <= array + mysize, JSON_TEXT("erasing out of bounds 2")); + if (position + number >= array + mysize){ + mysize = (json_index_t)(position - array); + #ifndef JSON_ISO_STRICT + JSON_ASSERT((long long)position - (long long)array >= 0, JSON_TEXT("doing negative allocation")); + #endif + } else { + memmove(position, position + number, (mysize - (position - array) - number) * sizeof(JSONNode *)); + mysize -= number; + } +} diff --git a/src/mir_core/src/json/JSONChildren.h b/src/mir_core/src/json/JSONChildren.h new file mode 100644 index 0000000000..ce697ffd77 --- /dev/null +++ b/src/mir_core/src/json/JSONChildren.h @@ -0,0 +1,232 @@ +#ifndef JSONCHILDREN_H +#define JSONCHILDREN_H + +#include "JSONMemory.h" +#include "JSONDebug.h" //for JSON_ASSERT macro + +#define json_foreach(children, iterator)\ + JSONNode ** iterator = children.begin();\ + for(JSONNode ** iterator##_end = children.end(); iterator != iterator##_end; ++iterator) + +/* + This class is essentially a vector that has been heavily optimized for the specific purpose + of holding JSONNode children. It acts the same way as a vector, it has a automatically + expanding array. On destruction, this container automatically destroys everything contained + in it as well, so that you libJSON doesn't have to do that. + + T is JSONNode*, I can't define it that way directly because JSONNode uses this container, and because + the container deletes the children automatically, forward declaration can't be used + */ + +class JSONNode; //forward declaration + +class jsonChildren { +public: + //starts completely empty and the array is not allocated + jsonChildren(void) : array(0), mysize(0), mycapacity(0) { } + + //deletes the array and everything that is contained within it (using delete) + ~jsonChildren(void){ + if (array){ //the following function calls are safe, but take more time than a check here + deleteAll(); + libjson_free(array); + } + } + + //increase the size of the array + void inc(json_index_t amount); + void inc(void); + + //Adds something to the vector, doubling the array if necessary + void push_back(JSONNode * item){ + inc(); + array[mysize++] = item; + } + + //Adds something to the front of the vector, doubling the array if necessary + void push_front(JSONNode * item){ + inc(); + memmove(array + 1, array, mysize++ * sizeof(JSONNode *)); + array[0] = item; + } + + //gets an item out of the vector by it's position + inline JSONNode * operator[] (json_index_t position) const { + JSON_ASSERT(position < mysize, JSON_TEXT("Using [] out of bounds")); + JSON_ASSERT(position < mycapacity, JSON_TEXT("Using [] out of bounds")); + JSON_ASSERT(array, JSON_TEXT("Array is null")); + return array[position]; + } + + //returns the allocated capacity, but keep in mind that some might not be valid + inline json_index_t capacity() const { + return mycapacity; + } + + //returns the number of valid objects within the vector + inline json_index_t size() const { + return mysize; + } + + //tests whether or not the vector is empty + inline bool empty() const { + return mysize == 0; + } + + //clears (and deletes) everything from the vector and sets it's size to 0 + inline void clear() { + if (array){ //don't bother clearing anything if there is nothing in it + JSON_ASSERT(mycapacity != 0, JSON_TEXT("mycapacity is not zero, but array is null")); + deleteAll(); + mysize = 0; + } + JSON_ASSERT(mysize == 0, JSON_TEXT("mysize is not zero after clear")); + } + + //returns the beginning of the array + inline JSONNode ** begin(void) const { + return array; + } + + //returns the end of the array + inline JSONNode ** end(void) const { + return array + mysize; + } + + //makes sure that even after shirnking and expanding, the iterator is in same relative position + struct iteratorKeeper { + public: + #ifdef JSON_LIBRARY + iteratorKeeper(jsonChildren * pthis, JSONNode ** & position) : + myRelativeOffset((json_index_t)(position - pthis -> array)), + #else + iteratorKeeper(jsonChildren * pthis, JSONNode ** & position, bool reverse = false) : + myRelativeOffset(reverse ? (json_index_t)(pthis -> array + (size_t)pthis -> mysize - position) : (json_index_t)(position - pthis -> array)), + myReverse(reverse), + #endif + myChildren(pthis), + myPos(position){} + + ~iteratorKeeper(void){ + #ifdef JSON_LIBRARY + myPos = myChildren -> array + myRelativeOffset; + #else + if (myReverse){ + myPos = myChildren -> array + myChildren -> mysize - myRelativeOffset; + } else { + myPos = myChildren -> array + myRelativeOffset; + } + #endif + } + private: + iteratorKeeper(const iteratorKeeper &); + iteratorKeeper & operator = (const iteratorKeeper &); + + jsonChildren * myChildren; + JSONNode ** & myPos; + json_index_t myRelativeOffset; + #ifndef JSON_LIBRARY + bool myReverse BITS(1); + #endif + }; + + //This function DOES NOT delete the item it points to + inline void erase(JSONNode ** & position){ + JSON_ASSERT(array, JSON_TEXT("erasing something from a null array 1")); + JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array 1")); + JSON_ASSERT(position <= array + mysize, JSON_TEXT("erasing out of bounds 1")); + memmove(position, position + 1, (mysize-- - (position - array) - 1) * sizeof(JSONNode *)); + iteratorKeeper ik(this, position); + shrink(); + } + + //This function DOES NOT delete the item it points to + inline void erase(JSONNode ** & position, json_index_t number){ + doerase(position, number); + iteratorKeeper ik(this, position); + shrink(); + } + + //This function DOES NOT delete the item it points to + inline void erase(JSONNode ** position, json_index_t number, JSONNode ** & starter){ + doerase(position, number); + iteratorKeeper ik(this, starter); + shrink(); + } + + #ifdef JSON_LIBRARY + void insert(JSONNode ** & position, JSONNode * item){ + #else + void insert(JSONNode ** & position, JSONNode * item, bool reverse = false){ + #endif + //position isnt relative to array because of realloc + JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 1")); + JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 1")); + { + #ifdef JSON_LIBRARY + iteratorKeeper ik(this, position); + #else + iteratorKeeper ik(this, position, reverse); + #endif + inc(); + } + memmove(position + 1, position, (mysize++ - (position - array)) * sizeof(JSONNode *)); + *position = item; + } + + void insert(JSONNode ** & position, JSONNode ** items, json_index_t num){ + JSON_ASSERT(position >= array, JSON_TEXT("position is beneath the start of the array insert 2")); + JSON_ASSERT(position <= array + mysize, JSON_TEXT("position is above the end of the array insert 2")); + { + iteratorKeeper ik(this, position); + inc(num); + } + const size_t ptrs = ((JSONNode **)(array + mysize)) - position; + memmove(position + num, position, ptrs * sizeof(JSONNode *)); + memcpy(position, items, num * sizeof(JSONNode *)); + mysize += num; + } + + inline void reserve(json_index_t amount){ + JSON_ASSERT(!array, JSON_TEXT("reserve is not meant to expand a preexisting array")); + JSON_ASSERT(!mycapacity, JSON_TEXT("reservec is not meant to expand a preexisting array")); + JSON_ASSERT(!mysize, JSON_TEXT("reserves is not meant to expand a preexisting array")); + array = json_malloc(mycapacity = amount); + } + + inline void reserve2(json_index_t amount){ + if (array){ + if (mycapacity < amount) inc(amount - mycapacity); + } else { + reserve(amount); + } + } + + //shrinks the array to only as large as it needs to be to hold everything within it + inline void shrink() { + if (mysize == 0){ //size is zero, we should completely free the array + libjson_free(array); //free does checks for a null pointer, so don't bother checking + array = 0; + #ifdef JSON_LESS_MEMORY + } else { //need to shrink it, using realloc + JSON_ASSERT(array, JSON_TEXT("shrinking a null array that is not size 0")); + array = json_realloc(array, mysize); + #endif + } + mycapacity = mysize; + } +JSON_PRIVATE + //to make sure it's not copyable + jsonChildren(const jsonChildren &); + jsonChildren & operator = (const jsonChildren &); + + void deleteAll(void); //implemented in JSONNode.cpp + void doerase(JSONNode ** position, json_index_t number); + + JSONNode ** array; //the expandable array + + json_index_t mysize; //the number of valid items + json_index_t mycapacity; //the number of possible items +}; + +#endif diff --git a/src/mir_core/src/json/JSONDebug.cpp b/src/mir_core/src/json/JSONDebug.cpp new file mode 100644 index 0000000000..e5ba81a188 --- /dev/null +++ b/src/mir_core/src/json/JSONDebug.cpp @@ -0,0 +1,66 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" + +#include + +#ifdef JSON_DEBUG + +#ifdef JSON_STDERROR + #include //need std::cerr +#else + //otherwise, use a callback to tell the end user what happened + json_error_callback_t ErrorCallback = 0; + void JSONDebug::register_callback(json_error_callback_t callback){ + ErrorCallback = callback; + } +#endif + +//Something went wrong or an assert failed +void JSONDebug::_JSON_FAIL(const json_string & msg){ + #ifdef JSON_STDERROR //no callback, just use stderror + #ifndef JSON_UNICODE + std::cerr << msg << std::endl; + #else + std::cerr << std::string(msg.begin(), msg.end()) << std::endl; + #endif + #else + if (ErrorCallback){ //only do anything if the callback is registered + #ifdef JSON_LIBRARY + ErrorCallback(msg.c_str()); + #else + ErrorCallback(msg); + #endif + } + #endif +} + +//asserts that condition is true, more useful than cassert because it lets you keep going +void JSONDebug::_JSON_ASSERT(bool condition, const json_string & msg){ + if (!condition){ + _JSON_FAIL(msg); + } +} +#endif diff --git a/src/mir_core/src/json/JSONDebug.h b/src/mir_core/src/json/JSONDebug.h new file mode 100644 index 0000000000..ff1cedf8fc --- /dev/null +++ b/src/mir_core/src/json/JSONDebug.h @@ -0,0 +1,68 @@ +#ifndef JSON_DEBUG_H +#define JSON_DEBUG_H + +#include "JSONDefs.h" +#include "JSONOptions.h" + +#ifdef JSON_UNIT_TEST + #define JSON_PRIVATE +#else + #define JSON_PRIVATE private: +#endif + +#ifdef JSON_DEBUG + #ifdef JSON_SAFE + #define JSON_ASSERT_SAFE(condition, msg, code)\ + {\ + if (!(condition)) {\ + JSON_FAIL(msg);\ + code\ + }\ + } + #define JSON_FAIL_SAFE(msg, code)\ + {\ + JSON_FAIL(msg);\ + code\ + } + #else + #define JSON_ASSERT_SAFE(condition, msg, code) JSON_ASSERT(condition, msg) + #define JSON_FAIL_SAFE(msg, code) JSON_FAIL(msg) + #endif + + #define JSON_FAIL JSONDebug::_JSON_FAIL + #define JSON_ASSERT JSONDebug::_JSON_ASSERT + + class JSONDebug { + public: + #ifndef JSON_STDERROR + static void register_callback(json_error_callback_t callback); + #endif + static void _JSON_FAIL(const json_string & msg); + static void _JSON_ASSERT(bool condition, const json_string & msg); + }; +#else + #ifdef JSON_SAFE + #define JSON_ASSERT_SAFE(condition, msg, code)\ + {\ + if (!(condition)) {\ + code\ + }\ + } + #define JSON_FAIL_SAFE(msg, code)\ + {\ + code\ + } + #else + #define JSON_ASSERT_SAFE(condition, msg, code) + #define JSON_FAIL_SAFE(msg, code) + #endif + + #define JSON_ASSERT(condition, msg) + #define JSON_FAIL(msg) +#endif + +static const json_string EMPTY_STRING; +static const std::string EMPTY_STRING2; + +#endif + diff --git a/src/mir_core/src/json/JSONDefs.h b/src/mir_core/src/json/JSONDefs.h new file mode 100644 index 0000000000..9bcaa55b64 --- /dev/null +++ b/src/mir_core/src/json/JSONDefs.h @@ -0,0 +1,83 @@ +#ifndef JSONDEFS_H +#define JSONDEFS_H + +/* + Defines all of the types of functions and various other definitions + that are used in C applications, this is very useful if dynamically loading + the library instead of linking. +*/ + +#include "JSONOptions.h" + +#define JSON_NULL '\0' +#define JSON_STRING '\1' +#define JSON_NUMBER '\2' +#define JSON_BOOL '\3' +#define JSON_ARRAY '\4' +#define JSON_NODE '\5' + +#ifdef __cplusplus + #include +#endif + +#ifdef JSON_UNICODE + #ifdef JSON_ISO_STRICT + #error, You can not use unicode under ISO Strict C++ + #endif + #define json_char wchar_t + #define json_uchar wchar_t + #ifdef __cplusplus + #include //need wide characters + typedef std::wstring json_string; + #else + #include //need wide characters + #endif + #define JSON_TEXT(s) L ## s + #define json_strlen wcslen + #define json_strcmp wcscmp +#else + #define json_char char + #define json_uchar BYTE + #ifdef __cplusplus + typedef std::string json_string; + #endif + #define JSON_TEXT(s) s + #define json_strlen strlen + #define json_strcmp strcmp +#endif + +#ifdef JSON_LESS_MEMORY + #define BITS(x) :x //tells the compiler how many bits to use for a field + typedef float json_number; +#else + #define BITS(x) + typedef double json_number; +#endif + +#if defined JSON_DEBUG || defined JSON_SAFE + #ifdef JSON_LIBRARY + typedef void (*json_error_callback_t)(const json_char *); + #else + typedef void (*json_error_callback_t)(const json_string &); + #endif +#endif + +#ifdef JSON_INDEX_TYPE + typedef JSON_INDEX_TYPE json_index_t; +#else + typedef size_t json_index_t; +#endif + +typedef void (*json_mutex_callback_t)(void *); +typedef void (*json_free_t)(void *); +#ifndef JSON_LIBRARY + typedef void * (*json_malloc_t)(size_t); + typedef void * (*json_realloc_t)(void *, size_t); +#else + #define JSONNODE void //so that JSONNODE* is void* + typedef JSONNODE** JSONNODE_ITERATOR; + typedef void * (*json_malloc_t)(size_t); + typedef void * (*json_realloc_t)(void *, size_t); +#endif + +#endif //JSONDEFS_H diff --git a/src/mir_core/src/json/JSONIterators.cpp b/src/mir_core/src/json/JSONIterators.cpp new file mode 100644 index 0000000000..1ff164e1be --- /dev/null +++ b/src/mir_core/src/json/JSONIterators.cpp @@ -0,0 +1,240 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" + +#include "JSONNode.h" + +#ifdef JSON_ITERATORS + #ifdef JSON_REF_COUNT + #define JSON_ASSERT_UNIQUE(x) JSON_ASSERT(internal -> refcount == 1, json_string(JSON_TEXT(x)) + JSON_TEXT(" in non single reference")) + #else + #define JSON_ASSERT_UNIQUE(x) (void)0 + #endif + + #ifdef JSON_MUTEX_CALLBACKS + #define JSON_MUTEX_COPY2 ,internal -> mylock + #else + #define JSON_MUTEX_COPY2 + #endif + +JSONNode::json_iterator JSONNode::find(const json_string & name_t){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); + makeUniqueInternal(); + if (JSONNode ** res = internal -> at(name_t)) { + return ptr_to_json_iterator(res); + } + return end(); +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode::json_iterator JSONNode::find_nocase(const json_string & name_t){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); + makeUniqueInternal(); + if (JSONNode ** res = internal -> at_nocase(name_t)) { + return ptr_to_json_iterator(res); + } + return end(); + } +#endif + +JSONNode::json_iterator JSONNode::erase(json_iterator pos){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("erase 1"); + JSON_ASSERT_SAFE(pos < end(), JSON_TEXT("erase out of range"), return end();); + JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("erase out of range"), return begin();); + deleteJSONNode(*(json_iterator_ptr(pos))); + internal -> Children.erase(json_iterator_ptr(pos)); + return (empty()) ? end() : pos; +} + +JSONNode::json_iterator JSONNode::erase(json_iterator _start, const json_iterator & _end){ + if (_start == _end) return _start; + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("erase 3"); + JSON_ASSERT_SAFE(_start <= end(), JSON_TEXT("erase out of lo range"), return end();); + JSON_ASSERT_SAFE(_end <= end(), JSON_TEXT("erase out of hi range"), return end();); + JSON_ASSERT_SAFE(_start >= begin(), JSON_TEXT("erase out of lo range"), return begin();); + JSON_ASSERT_SAFE(_end >= begin(), JSON_TEXT("erase out of hi range"), return begin();); + for (JSONNode ** pos = json_iterator_ptr(_start); pos < json_iterator_ptr(_end); ++pos){ + deleteJSONNode(*pos); + } + + internal -> Children.erase(json_iterator_ptr(_start), json_iterator_ptr(_end) - json_iterator_ptr(_start)); + return (empty()) ? end() : _start; +} + +#ifdef JSON_LIBRARY +JSONNode::json_iterator JSONNode::insert(json_iterator pos, JSONNode * x){ +#else +JSONNode::json_iterator JSONNode::insert(json_iterator pos, const JSONNode & x){ +#endif + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("insert 1"); + if (json_iterator_ptr(pos) >= internal -> Children.end()) { + internal -> push_back(x); + return end() - 1; + } + JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of lo range"), return begin();); + #ifdef JSON_LIBRARY + internal -> Children.insert(json_iterator_ptr(pos), x); + #else + internal -> Children.insert(json_iterator_ptr(pos), newJSONNode(x)); + #endif + return pos; +} + +JSONNode::json_iterator JSONNode::insertFFF(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("insertFFF"); + JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of high range"), return end();); + JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of low range"), return begin();); + const size_t num = _end - _start; + json_auto mem(num); + JSONNode ** runner = mem.ptr; + for (JSONNode ** po = _start; po < _end; ++po){ + *runner++=newJSONNode(*(*po) JSON_MUTEX_COPY2); + } + internal -> Children.insert(json_iterator_ptr(pos), mem.ptr, num); + return pos; +} + +#ifndef JSON_LIBRARY + JSONNode::const_iterator JSONNode::find(const json_string & name_t) const { + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); + if (JSONNode ** res = internal -> at(name_t)) { + return JSONNode::const_iterator(res); + } + return JSONNode::const_iterator(internal -> end()); + } + + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode::const_iterator JSONNode::find_nocase(const json_string & name_t) const { + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("finding a non-iteratable node")); + if (JSONNode ** res = internal -> at_nocase(name_t)) { + return JSONNode::const_iterator(res); + } + return JSONNode::const_iterator(internal -> end()); + } + #endif + + JSONNode::reverse_iterator JSONNode::erase(reverse_iterator pos){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("erase 2"); + JSON_ASSERT_SAFE(pos < rend(), JSON_TEXT("erase out of range"), return rend();); + JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("erase out of range"), return rbegin();); + deleteJSONNode(*(pos.it)); + internal -> Children.erase(pos.it); + return (empty()) ? rend() : pos + 1; + } + + JSONNode::reverse_iterator JSONNode::erase(reverse_iterator _start, const reverse_iterator & _end){ + if (_start == _end) return _start; + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("erase 4"); + JSON_ASSERT_SAFE(_start <= rend(), JSON_TEXT("erase out of lo range"), return rend();); + JSON_ASSERT_SAFE(_end <= rend(), JSON_TEXT("erase out of hi range"), return rend();); + JSON_ASSERT_SAFE(_start >= rbegin(), JSON_TEXT("erase out of lo range"), return rbegin();); + JSON_ASSERT_SAFE(_end >= rbegin(), JSON_TEXT("erase out of hi range"), return rbegin();); + for (JSONNode ** pos = _start.it; pos > _end.it; --pos){ + deleteJSONNode(*pos); + } + const size_t num = _start.it - _end.it; + internal -> Children.erase(_end.it + 1, num, _start.it); + return (empty()) ? rend() : _start + num; + } + + JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const JSONNode & x){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("insert 1"); + if (pos.it < internal -> Children.begin()) { + internal -> push_front(x); + return rend() - 1; + } + JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); + internal -> Children.insert(++pos.it, newJSONNode(x), true); + return pos; + } + + JSONNode::reverse_iterator JSONNode::insertRFF(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("insert RFF"); + JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend();); + JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); + const size_t num = _end - _start; + json_auto mem(num); + JSONNode ** runner = mem.ptr + num; + for (JSONNode ** po = _start; po < _end; ++po){ //fill it backwards + *(--runner) = newJSONNode(*(*po) JSON_MUTEX_COPY2); + } + internal -> Children.insert(++pos.it, mem.ptr, num); + return pos - num + 1; + } + + JSONNode::iterator JSONNode::insertFRR(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("insert FRR"); + JSON_ASSERT_SAFE(pos <= end(), JSON_TEXT("insert out of range"), return end();); + JSON_ASSERT_SAFE(pos >= begin(), JSON_TEXT("insert out of range"), return begin();); + const size_t num = _start - _end; + json_auto mem(num); + JSONNode ** runner = mem.ptr; + for (JSONNode ** po = _start; po > _end; --po){ + *runner++=newJSONNode(*(*po) JSON_MUTEX_COPY2); + } + internal -> Children.insert(pos.it, mem.ptr, num); + return pos; + } + + JSONNode::reverse_iterator JSONNode::insertRRR(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("erasing a non-iteratable node")); + JSON_ASSERT_UNIQUE("insert RRR"); + JSON_ASSERT_SAFE(pos <= rend(), JSON_TEXT("insert out of range"), return rend();); + JSON_ASSERT_SAFE(pos >= rbegin(), JSON_TEXT("insert out of range"), return rbegin();); + const size_t num = _start - _end; + json_auto mem(num); + JSONNode ** runner = mem.ptr; + for (JSONNode ** po = _start; po > _end; --po){ + *runner++=newJSONNode(*(*po) JSON_MUTEX_COPY2); + } + internal -> Children.insert(++pos.it, mem.ptr, num); + return pos - num + 1; + } +#endif + +#endif diff --git a/src/mir_core/src/json/JSONMemory.cpp b/src/mir_core/src/json/JSONMemory.cpp new file mode 100644 index 0000000000..dfe757b5c1 --- /dev/null +++ b/src/mir_core/src/json/JSONMemory.cpp @@ -0,0 +1,107 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" + +#include "JSONMemory.h" +#include "JSONNode.h" + +#ifdef JSON_MEMORY_MANAGE + void auto_expand::purge(void){ + for(std::map::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ + #if defined(JSON_DEBUG) || defined(JSON_SAFE) + void * temp = (void*)i -> first; //because its pass by reference + libjson_free(temp); + #else + libjson_free((void*)i -> first); + #endif + } + } + + void auto_expand_node::purge(void){ + for(std::map::iterator i = mymap.begin(), en = mymap.end(); i != en; ++i){ + JSONNode::deleteJSONNode((JSONNode *)i -> second); + } + } +#endif + +#ifdef JSON_MEMORY_CALLBACKS + +json_malloc_t mymalloc = 0; +json_realloc_t myrealloc = 0; +json_free_t myfree = 0; + +void * JSONMemory::json_malloc(size_t siz){ + if (mymalloc){ + #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful + void * result = mymalloc(siz); + JSON_ASSERT(result, JSON_TEXT("out of memory")); + return result; + #else + return mymalloc((unsigned long)siz); + #endif + } + #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful + void * result = malloc(siz); + JSON_ASSERT(result, JSON_TEXT("out of memory")); + return result; + #else + return malloc(siz); + #endif +} + +void * JSONMemory::json_realloc(void * ptr, size_t siz){ + if (myrealloc){ + #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful + void * result = myrealloc(ptr, siz); + JSON_ASSERT(result, JSON_TEXT("out of memory")); + return result; + #else + return myrealloc(ptr, (unsigned long)siz); + #endif + } + #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful + void * result = realloc(ptr, siz); + JSON_ASSERT(result, JSON_TEXT("out of memory")); + return result; + #else + return realloc(ptr, siz); + #endif +} + +void JSONMemory::json_free(void * ptr){ + if (myfree){ + myfree(ptr); + } else { + free(ptr); + } +} + +void JSONMemory::registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre){ + mymalloc = mal; + myrealloc = real; + myfree = fre; +} + +#endif diff --git a/src/mir_core/src/json/JSONMemory.h b/src/mir_core/src/json/JSONMemory.h new file mode 100644 index 0000000000..32e8c3f4ef --- /dev/null +++ b/src/mir_core/src/json/JSONMemory.h @@ -0,0 +1,134 @@ +#ifndef JSON_MEMORY_H +#define JSON_MEMORY_H + +#include //for malloc, realloc, and free +#include //for memmove +#include "JSONOptions.h" +#include "JSONDebug.h" + +#if defined(JSON_DEBUG) || defined(JSON_SAFE) + #define JSON_FREE_PASSTYPE & +#else + #define JSON_FREE_PASSTYPE +#endif + +#ifdef JSON_MEMORY_CALLBACKS + class JSONMemory { + public: + static void * json_malloc(size_t siz); + static void * json_realloc(void * ptr, size_t siz); + static void json_free(void * ptr); + static void registerMemoryCallbacks(json_malloc_t mal, json_realloc_t real, json_free_t fre); + }; + + template static inline T * json_malloc(size_t count){ + return (T *)JSONMemory::json_malloc(sizeof(T) * count); + } + + template static inline T * json_realloc(T * ptr, size_t count){ + return (T *)JSONMemory::json_realloc(ptr, sizeof(T) * count); + } + + template static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr){ + JSONMemory::json_free(ptr); + #if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again + ptr = 0; + #endif + } +#else + template + static inline T * json_malloc(size_t count){ + #ifdef JSON_DEBUG //in debug mode, see if the malloc was successful + void * result = malloc(count * sizeof(T)); + JSON_ASSERT(result, JSON_TEXT("out of memory")); + #ifdef JSON_NULL_MEMORY + memset(result, '\0', count * sizeof(T)); + #endif + return (T *)result; + #else + return (T *)malloc(count * sizeof(T)); + #endif + } + + template + static inline void libjson_free(T * JSON_FREE_PASSTYPE ptr){ + free(ptr); + #if defined(JSON_DEBUG) || defined(JSON_SAFE) //in debug or safe mode, set the pointer to 0 so that it can't be used again + ptr = 0; + #endif + } + + template + static inline T * json_realloc(T * ptr, size_t count){ + #ifdef JSON_DEBUG //in debug mode, check the results of realloc to be sure it was successful + void * result = realloc(ptr, count * sizeof(T)); + JSON_ASSERT(result, JSON_TEXT("out of memory")); + #ifdef JSON_NULL_MEMORY + memset(result, '\0', count * sizeof(T)); + #endif + return (T *)result; + #else + return (T *)realloc(ptr, count * sizeof(T)); + #endif + } +#endif + +#ifdef JSON_MEMORY_MANAGE + #include + class JSONNode; + struct auto_expand { + auto_expand(void) : mymap() {} + ~auto_expand(void){ purge(); } + void purge(void); + inline void clear(void){ purge(); mymap.clear(); } + inline void * insert(void * ptr){ mymap[ptr] = ptr; return ptr; } + inline void remove(void * ptr){ + std::map::iterator i = mymap.find(ptr); + JSON_ASSERT(i != mymap.end(), JSON_TEXT("Removing a non-managed item")); + mymap.erase(i); + } + std::map mymap; + }; + + struct auto_expand_node { + auto_expand_node(void) : mymap() {} + ~auto_expand_node(void){ purge(); } + void purge(void); + inline void clear(void){ purge(); mymap.clear(); } + inline JSONNode * insert(JSONNode * ptr){ mymap[ptr] = ptr; return ptr; } + inline void remove(void * ptr){ + std::map::iterator i = mymap.find(ptr); + if(i != mymap.end()) mymap.erase(i); + } + std::map mymap; + }; +#endif + +//The C++ way, use an self-deleting pointer and let the optimizer decide when it gets destroyed +template +class json_auto { + public: + json_auto(void) : ptr(0){} + json_auto(size_t count) : ptr(json_malloc(count)) {} + ~json_auto(void){ + libjson_free(ptr); + } + void set(T * p){ + ptr = p; + } + T * ptr; + private: + json_auto(const json_auto &); + json_auto & operator = (const json_auto &); +}; + +//Clears a string, if required, frees the memory +static inline void clearString(json_string & str){ + #ifdef JSON_LESS_MEMORY + json_string().swap(str); + #else + str.clear(); + #endif +} + +#endif diff --git a/src/mir_core/src/json/JSONNode.cpp b/src/mir_core/src/json/JSONNode.cpp new file mode 100644 index 0000000000..b1a492b5a6 --- /dev/null +++ b/src/mir_core/src/json/JSONNode.cpp @@ -0,0 +1,312 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" + +#include "JSONNode.h" + +#ifdef JSON_UNIT_TEST + int allocCount = 0; + int deallocCount = 0; + int internalAllocCount = 0; + int internalDeallocCount = 0; + int JSONNode::getNodeAllocationCount(void){ return allocCount; } + int JSONNode::getNodeDeallocationCount(void){ return deallocCount; } + int JSONNode::getInternalAllocationCount(void){ return internalAllocCount; } + int JSONNode::getInternalDeallocationCount(void){ return internalDeallocCount; } + void JSONNode::incAllocCount(void){ ++allocCount; } + void JSONNode::decAllocCount(void){ ++deallocCount; } + void JSONNode::incinternalAllocCount(void){ ++internalAllocCount; } + void JSONNode::decinternalAllocCount(void){ ++internalDeallocCount; } +#endif + +#define IMPLEMENT_CTOR(type)\ + JSONNode::JSONNode(const json_string & name_t, type value_t) : internal(internalJSONNode::newInternal()) {\ + internal -> Set(value_t);\ + internal -> setname(name_t);\ + incAllocCount();\ + } +IMPLEMENT_FOR_ALL_TYPES(IMPLEMENT_CTOR) + +#ifndef JSON_LIBRARY + JSONNode::JSONNode(const json_string & name_t, const json_char * value_t) : internal(internalJSONNode::newInternal()) { + internal -> Set(json_string(value_t)); + internal -> setname(name_t); + incAllocCount(); + } +#endif + +JSONNode JSONNode::as_node(void) const { + JSON_CHECK_INTERNAL(); + if (type() == JSON_NODE){ + return *this; + } else if (type() == JSON_ARRAY){ + JSONNode res = duplicate(); + res.internal -> _type = JSON_NODE; + return res; + } + #ifdef JSON_MUTEX_CALLBACKS + if (internal -> mylock){ + JSONNode res = JSONNode(JSON_NODE); + res.set_mutex(internal -> mylock); + return res; + } + #endif + return JSONNode(JSON_NODE); +} + +JSONNode JSONNode::as_array(void) const { + JSON_CHECK_INTERNAL(); + if (type() == JSON_ARRAY){ + return *this; + } else if (type() == JSON_NODE){ + JSONNode res = duplicate(); + res.internal -> _type = JSON_ARRAY; + json_foreach(res.internal -> Children, runner){ + (*runner) -> set_name(JSON_TEXT("")); + } + return res; + } + #ifdef JSON_MUTEX_CALLBACKS + if (internal -> mylock){ + JSONNode res = JSONNode(JSON_ARRAY); + res.set_mutex(internal -> mylock); + return res; + } + #endif + return JSONNode(JSON_ARRAY); +} + +void JSONNode::cast(char newtype){ + JSON_CHECK_INTERNAL(); + if (newtype == type()) return; + + switch(newtype){ + case JSON_NULL: + nullify(); + return; + case JSON_STRING: + *this = as_string(); + return; + case JSON_NUMBER: + *this = as_float(); + return; + case JSON_BOOL: + *this = as_bool(); + return; + case JSON_ARRAY: + *this = as_array(); + return; + case JSON_NODE: + *this = as_node(); + return; + } + JSON_FAIL(JSON_TEXT("cast to unknown type")); +} + +//different just to supress the warning +#ifdef JSON_REF_COUNT +void JSONNode::merge(JSONNode & other){ +#else +void JSONNode::merge(JSONNode &) { +#endif + JSON_CHECK_INTERNAL(); + #ifdef JSON_REF_COUNT + if (internal == other.internal) return; + JSON_ASSERT(*this == other, JSON_TEXT("merging two nodes that aren't equal")); + if (internal -> refcount < other.internal -> refcount){ + *this = other; + } else { + other = *this; + } + #endif +} + +#ifdef JSON_REF_COUNT + void JSONNode::merge(JSONNode * other){ + JSON_CHECK_INTERNAL(); + if (internal == other -> internal) return; + *other = *this; + } + + //different just to supress the warning + void JSONNode::merge(unsigned int num, ...) { +#else + void JSONNode::merge(unsigned int, ...) { +#endif + JSON_CHECK_INTERNAL(); + #ifdef JSON_REF_COUNT + va_list args; + va_start(args, num); + for(unsigned int i=0; i < num; ++i){ + merge(va_arg(args, JSONNode*)); + } + va_end(args); + #endif +} + +JSONNode JSONNode::duplicate(void) const { + JSON_CHECK_INTERNAL(); + JSONNode mycopy(*this); + #ifdef JSON_REF_COUNT + JSON_ASSERT(internal == mycopy.internal, JSON_TEXT("copy ctor failed to ref count correctly")); + mycopy.makeUniqueInternal(); + #endif + JSON_ASSERT(internal != mycopy.internal, JSON_TEXT("makeUniqueInternal failed")); + return mycopy; +} + +JSONNode & JSONNode::at(json_index_t pos){ + JSON_CHECK_INTERNAL(); + if (pos >= internal -> size()) { + JSON_FAIL(JSON_TEXT("at() out of bounds")); + throw std::out_of_range(EMPTY_STRING2); + } + return (*this)[pos]; +} + +const JSONNode & JSONNode::at(json_index_t pos) const { + JSON_CHECK_INTERNAL(); + if (pos >= internal -> size()) { + JSON_FAIL(JSON_TEXT("at() const out of bounds")); + throw std::out_of_range(EMPTY_STRING2); + } + return (*this)[pos]; +} + +JSONNode & JSONNode::operator[](json_index_t pos){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] out of bounds")); + makeUniqueInternal(); + return *(internal -> at(pos)); +} + +const JSONNode & JSONNode::operator[](json_index_t pos) const { + JSON_CHECK_INTERNAL(); + JSON_ASSERT(pos < internal -> size(), JSON_TEXT("[] const out of bounds")); + return *(internal -> at(pos)); +} + +JSONNode & JSONNode::at(const json_string & name_t){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); + makeUniqueInternal(); + if (JSONNode ** res = internal -> at(name_t)) { + return *(*res); + } + JSON_FAIL(json_string(JSON_TEXT("at could not find child by name: ")) + name_t); + throw std::out_of_range(EMPTY_STRING2); +} + +const JSONNode & JSONNode::at(const json_string & name_t) const { + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); + if (JSONNode ** res = internal -> at(name_t)) { + return *(*res); + } + JSON_FAIL(json_string(JSON_TEXT("at const could not find child by name: ")) + name_t); + throw std::out_of_range(EMPTY_STRING2); +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode & JSONNode::at_nocase(const json_string & name_t){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); + makeUniqueInternal(); + if (JSONNode ** res = internal -> at_nocase(name_t)) { + return *(*res); + } + JSON_FAIL(json_string(JSON_TEXT("at_nocase could not find child by name: ")) + name_t); + throw std::out_of_range(EMPTY_STRING2); + } + + const JSONNode & JSONNode::at_nocase(const json_string & name_t) const { + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("at a non-iteratable node")); + if (JSONNode ** res = internal -> at_nocase(name_t)) { + return *(*res); + } + JSON_FAIL(json_string(JSON_TEXT("at_nocase const could not find child by name: ")) + name_t); + throw std::out_of_range(EMPTY_STRING2); + } +#endif + +#ifndef JSON_LIBRARY + struct auto_delete { + public: + auto_delete(JSONNode *node) : mynode(node){}; + ~auto_delete(void){ JSONNode::deleteJSONNode(mynode); }; + JSONNode * mynode; + private: + auto_delete(const auto_delete &); + auto_delete & operator = (const auto_delete &); + }; +#endif + +JSONNode JSON_PTR_LIB JSONNode::pop_back(json_index_t pos){ + JSON_CHECK_INTERNAL(); + if (pos >= internal -> size()) { + JSON_FAIL(JSON_TEXT("pop_back out of bounds")); + throw std::out_of_range(EMPTY_STRING2); + } + makeUniqueInternal(); + #ifdef JSON_LIBRARY + return internal -> pop_back(pos); + #else + auto_delete temp(internal -> pop_back(pos)); + return *temp.mynode; + #endif +} + +JSONNode JSON_PTR_LIB JSONNode::pop_back(const json_string & name_t){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("popping a non-iteratable node")); + #ifdef JSON_LIBRARY + return internal -> pop_back(name_t); + #else + if (JSONNode * res = internal -> pop_back(name_t)) { + auto_delete temp(res); + return *(temp.mynode); + } + JSON_FAIL(json_string(JSON_TEXT("pop_back const could not find child by name: ")) + name_t); + throw std::out_of_range(EMPTY_STRING2); + #endif +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode JSON_PTR_LIB JSONNode::pop_back_nocase(const json_string & name_t){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE, JSON_TEXT("popping a non-iteratable node")); + #ifdef JSON_LIBRARY + return internal -> pop_back_nocase(name_t); + #else + if (JSONNode * res = internal -> pop_back_nocase(name_t)) { + auto_delete temp(res); + return *(temp.mynode); + } + JSON_FAIL(json_string(JSON_TEXT("pop_back_nocase could not find child by name: ")) + name_t); + throw std::out_of_range(EMPTY_STRING2); + #endif + } +#endif diff --git a/src/mir_core/src/json/JSONNode.h b/src/mir_core/src/json/JSONNode.h new file mode 100644 index 0000000000..dfb6ff01f3 --- /dev/null +++ b/src/mir_core/src/json/JSONNode.h @@ -0,0 +1,851 @@ +#ifndef JSONNODE_H +#define JSONNODE_H + +#include "JSONDefs.h" //for string type +#include "internalJSONNode.h" //internal structure for json value + +#ifdef JSON_BINARY + #include "JSON_Base64.h" +#endif + +#ifndef JSON_REF_COUNT + #define makeUniqueInternal() (void)0 +#endif + +#define JSON_CHECK_INTERNAL() JSON_ASSERT(internal, JSON_TEXT("no internal")) + +#ifdef JSON_MUTEX_CALLBACKS + #define JSON_MUTEX_COPY_DECL ,void * parentMutex + #define JSON_MUTEX_COPY_DECL2 ,void * parentMutex = 0 +#else + #define JSON_MUTEX_COPY_DECL + #define JSON_MUTEX_COPY_DECL2 +#endif + +#ifdef JSON_LIBRARY + #define JSON_PTR_LIB * + #define JSON_NEW(x) JSONNode::newJSONNode_Shallow(x) + #define DECLARE_FOR_ALL_TYPES(foo)\ + foo(long);\ + foo(double);\ + foo(bool);\ + foo(const json_string &); + #define DECLARE_FOR_ALL_TYPES_CONST(foo)\ + foo(long) const;\ + foo(double) const;\ + foo(bool) const;\ + foo(const json_string &) const;\ + foo(const JSONNode &) const; + #define IMPLEMENT_FOR_ALL_NUMBERS(foo)\ + foo(long)\ + foo(double) + +#else + #define JSON_PTR_LIB + #define JSON_NEW(x) x + #define DECLARE_FOR_ALL_TYPES(foo)\ + foo(char); foo(unsigned char);\ + foo(short); foo(unsigned short);\ + foo(int); foo(unsigned int);\ + foo(long); foo(unsigned long);\ + foo(float); foo(double);\ + foo(bool);\ + foo(const json_string &);\ + foo(const json_char *); + #define DECLARE_FOR_ALL_TYPES_CONST(foo)\ + foo(char) const; foo(unsigned char) const;\ + foo(short) const; foo(unsigned short) const;\ + foo(int) const; foo(unsigned int) const;\ + foo(long) const; foo(unsigned long) const;\ + foo(float) const; foo(double) const;\ + foo(bool) const;\ + foo(const json_string &) const;\ + foo(const JSONNode &) const;\ + foo(const json_char *) const; + #define IMPLEMENT_FOR_ALL_NUMBERS(foo)\ + foo(char) foo(unsigned char)\ + foo(short) foo(unsigned short)\ + foo(int) foo(unsigned int)\ + foo(long) foo(unsigned long)\ + foo(float) foo(double) +#endif +#define IMPLEMENT_FOR_ALL_TYPES(foo)\ + IMPLEMENT_FOR_ALL_NUMBERS(foo)\ + foo(const json_string &)\ + foo(bool) +/* + This class is mostly just a wrapper class around internalJSONNode, this class keeps + the reference count and handles copy on write and such. This class is also responsible + for argument checking and throwing exceptions if needed. +*/ + +class JSONNode { +public: + explicit JSONNode(char mytype = JSON_NODE); + #define DECLARE_CTOR(type) JSONNode(const json_string & name_t, type value_t) + DECLARE_FOR_ALL_TYPES(DECLARE_CTOR) + + JSONNode(const JSONNode & orig); + ~JSONNode(void); + + json_index_t size(void) const; + bool empty(void) const; + void clear(void); + unsigned char type(void) const; + + const json_char* name(void) const; + void set_name(const json_string & newname); + #ifdef JSON_COMMENTS + void set_comment(const json_string & comment); + json_string get_comment(void) const; + #endif + #ifndef JSON_PREPARSE + void preparse(void); + #endif + #ifdef JSON_VALIDATE + #ifndef JSON_SAFE + #error JSON_VALIDATE also requires JSON_SAFE + #endif + bool validate(void); + #endif + + json_string as_string(void) const; + long as_int(void) const; + double as_float(void) const; + bool as_bool(void) const; + JSONNode as_node(void) const; + JSONNode as_array(void) const; + + #ifdef JSON_BINARY + std::string as_binary(void) const; + void set_binary(const unsigned char * bin, json_index_t bytes); + #endif + + JSONNode & at(json_index_t pos); + const JSONNode & at(json_index_t pos) const; + JSONNode & operator[](json_index_t pos); + const JSONNode & operator[](json_index_t pos) const; + + JSONNode & at(const json_string & name_t); + const JSONNode & at(const json_string & name_t) const; + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode & at_nocase(const json_string & name_t); + const JSONNode & at_nocase(const json_string & name_t) const; + #endif + JSONNode & operator[](const json_string & name_t); + const JSONNode & operator[](const json_string & name_t) const; + #ifdef JSON_LIBRARY + void push_back(JSONNode *node); + #else + void push_back(const JSONNode & node); + #endif + void reserve(json_index_t size); + JSONNode JSON_PTR_LIB pop_back(json_index_t pos); + JSONNode JSON_PTR_LIB pop_back(const json_string & name_t); + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode JSON_PTR_LIB pop_back_nocase(const json_string & name_t); + #endif + + DECLARE_FOR_ALL_TYPES(JSONNode & operator = ) + JSONNode & operator = (const JSONNode &); + DECLARE_FOR_ALL_TYPES_CONST(bool operator ==) + DECLARE_FOR_ALL_TYPES_CONST(bool operator !=) + + void nullify(void); + void swap(JSONNode & other); + void merge(JSONNode & other); + void merge(unsigned int num, ...); + JSONNode duplicate(void) const; + void cast(char newtype); + + //iterator + #ifdef JSON_ITERATORS + #ifndef JSON_LIBRARY + #define json_iterator_ptr(iter) iter.it + #define ptr_to_json_iterator(iter) json_iterator(iter) + struct iterator { + inline iterator& operator ++(void){ ++it; return *this; } + inline iterator& operator --(void){ --it; return *this; } + inline iterator& operator +=(long i){ it += i; return *this; } + inline iterator& operator -=(long i){ it -= i; return *this; } + inline iterator operator ++(int){ + iterator result(*this); + ++it; + return result; + } + inline iterator operator --(int){ + iterator result(*this); + --it; + return result; + } + inline iterator operator +(long i) const { + iterator result(*this); + result.it += i; + return result; + } + inline iterator operator -(long i) const { + iterator result(*this); + result.it -= i; + return result; + } + inline JSONNode& operator [](size_t pos) const { return *it[pos]; }; + inline JSONNode& operator *(void) const { return *(*it); } + inline bool operator == (const iterator & other) const { return it == other.it; } + inline bool operator != (const iterator & other) const { return it != other.it; } + inline bool operator > (const iterator & other) const { return it > other.it; } + inline bool operator >= (const iterator & other) const { return it >= other.it; } + inline bool operator < (const iterator & other) const { return it < other.it; } + inline bool operator <= (const iterator & other) const { return it <= other.it; } + inline iterator & operator = (const iterator & orig){ it = orig.it; return *this; } + iterator (const iterator & orig) : it(orig.it) {} + private: + JSONNode ** it; + iterator(JSONNode ** starter) : it(starter) {} + friend class JSONNode; + }; + typedef iterator json_iterator; + + struct const_iterator { + inline const_iterator& operator ++(void){ ++it; return *this; } + inline const_iterator& operator --(void){ --it; return *this; } + inline const_iterator& operator +=(long i){ it += i; return *this; } + inline const_iterator& operator -=(long i){ it -= i; return *this; } + inline const_iterator operator ++(int){ + const_iterator result(*this); + ++it; + return result; + } + inline const_iterator operator --(int){ + const_iterator result(*this); + --it; + return result; + } + inline const_iterator operator +(long i) const { + const_iterator result(*this); + result.it += i; + return result; + } + inline const_iterator operator -(long i) const { + const_iterator result(*this); + result.it -= i; + return result; + } + inline const JSONNode& operator [](size_t pos) const { return const_cast(*it[pos]); }; + inline const JSONNode& operator *(void) const { return const_cast(*(*it)); } + inline bool operator == (const const_iterator & other) const { return it == other.it; } + inline bool operator != (const const_iterator & other) const { return it != other.it; } + inline bool operator > (const const_iterator & other) const { return it > other.it; } + inline bool operator >= (const const_iterator & other) const { return it >= other.it; } + inline bool operator < (const const_iterator & other) const { return it < other.it; } + inline bool operator <= (const const_iterator & other) const { return it <= other.it; } + inline const_iterator & operator = (const const_iterator & orig){ it = orig.it; return *this; } + const_iterator (const const_iterator & orig) : it(orig.it) {} + private: + JSONNode ** it; + const_iterator(JSONNode ** starter) : it(starter) {} + friend class JSONNode; + }; + const_iterator begin(void) const; + const_iterator end(void) const; + + struct reverse_iterator { + inline reverse_iterator& operator ++(void){ --it; return *this; } + inline reverse_iterator& operator --(void){ ++it; return *this; } + inline reverse_iterator& operator +=(long i){ it -= i; return *this; } + inline reverse_iterator& operator -=(long i){ it += i; return *this; } + inline reverse_iterator operator ++(int){ + reverse_iterator result(*this); + --it; + return result; + } + inline reverse_iterator operator --(int){ + reverse_iterator result(*this); + ++it; + return result; + } + inline reverse_iterator operator +(long i) const { + reverse_iterator result(*this); + result.it -= i; + return result; + } + inline reverse_iterator operator -(long i) const { + reverse_iterator result(*this); + result.it += i; + return result; + } + inline JSONNode& operator [](size_t pos) const { return *it[pos]; }; + inline JSONNode& operator *(void) const { return *(*it); } + inline bool operator == (const reverse_iterator & other) const { return it == other.it; } + inline bool operator != (const reverse_iterator & other) const { return it != other.it; } + inline bool operator < (const reverse_iterator & other) const { return it > other.it; } + inline bool operator <= (const reverse_iterator & other) const { return it >= other.it; } + inline bool operator > (const reverse_iterator & other) const { return it < other.it; } + inline bool operator >= (const reverse_iterator & other) const { return it <= other.it; } + inline reverse_iterator & operator = (const reverse_iterator & orig){ it = orig.it; return *this; } + reverse_iterator (const reverse_iterator & orig) : it(orig.it) {} + private: + JSONNode ** it; + reverse_iterator(JSONNode ** starter) : it(starter) {} + friend class JSONNode; + }; + reverse_iterator rbegin(void); + reverse_iterator rend(void); + + struct reverse_const_iterator { + inline reverse_const_iterator& operator ++(void){ --it; return *this; } + inline reverse_const_iterator& operator --(void){ ++it; return *this; } + inline reverse_const_iterator& operator +=(long i){ it -= i; return *this; } + inline reverse_const_iterator& operator -=(long i){ it += i; return *this; } + inline reverse_const_iterator operator ++(int){ + reverse_const_iterator result(*this); + --it; + return result; + } + inline reverse_const_iterator operator --(int){ + reverse_const_iterator result(*this); + ++it; + return result; + } + inline reverse_const_iterator operator +(long i) const { + reverse_const_iterator result(*this); + result.it -= i; + return result; + } + inline reverse_const_iterator operator -(long i) const { + reverse_const_iterator result(*this); + result.it += i; + return result; + } + inline const JSONNode& operator [](size_t pos) const { return const_cast(*it[pos]); }; + inline const JSONNode& operator *(void) const { return const_cast(*(*it)); } + inline bool operator == (const reverse_const_iterator & other) const { return it == other.it; } + inline bool operator != (const reverse_const_iterator & other) const { return it != other.it; } + inline bool operator < (const reverse_const_iterator & other) const { return it > other.it; } + inline bool operator <= (const reverse_const_iterator & other) const { return it >= other.it; } + inline bool operator > (const reverse_const_iterator & other) const { return it < other.it; } + inline bool operator >= (const reverse_const_iterator & other) const { return it <= other.it; } + inline reverse_const_iterator & operator = (const reverse_const_iterator & orig){ it = orig.it; return *this; } + reverse_const_iterator (const reverse_const_iterator & orig) : it(orig.it) {} + private: + JSONNode ** it; + reverse_const_iterator(JSONNode ** starter) : it(starter) {} + friend class JSONNode; + }; + reverse_const_iterator rbegin(void) const; + reverse_const_iterator rend(void) const; + + const_iterator find(const json_string & name_t) const; + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + const_iterator find_nocase(const json_string & name_t) const; + #endif + + reverse_iterator erase(reverse_iterator pos); + reverse_iterator erase(reverse_iterator start, const reverse_iterator & end); + + iterator insert(iterator pos, const JSONNode & x); + reverse_iterator insert(reverse_iterator pos, const JSONNode & x); + iterator insert(iterator pos, const reverse_iterator & _start, const reverse_iterator & _end); + reverse_iterator insert(reverse_iterator pos, const iterator & _start, const iterator & _end); + reverse_iterator insert(reverse_iterator pos, const reverse_iterator & _start, const reverse_iterator & _end); + + json_iterator insert(json_iterator pos, const const_iterator & _start, const const_iterator & _end); + reverse_iterator insert(reverse_iterator pos, const const_iterator & _start, const const_iterator & _end); + json_iterator insert(json_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end); + reverse_iterator insert(reverse_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end); + #else + typedef JSONNode** json_iterator; + #define json_iterator_ptr(iter) iter + #define ptr_to_json_iterator(iter) iter + json_iterator insert(json_iterator pos, JSONNode * x); + #endif + + json_iterator begin(void); + json_iterator end(void); + + json_iterator find(const json_string & name_t); + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + json_iterator find_nocase(const json_string & name_t); + #endif + json_iterator erase(json_iterator pos); + json_iterator erase(json_iterator start, const json_iterator & end); + json_iterator insert(json_iterator pos, const json_iterator & _start, const json_iterator & _end); + #endif + + #ifdef JSON_MUTEX_CALLBACKS + static void register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock); + #ifdef JSON_MUTEX_MANAGE + static void register_mutex_destructor(json_mutex_callback_t destroy); + #endif + static void set_global_mutex(void * mutex); + void set_mutex(void * mutex); + void lock(int thread); + void unlock(int thread); + struct auto_lock { + public: + auto_lock(JSONNode & node, int thread) : mynode(&node), mythread(thread){ + mynode -> lock(mythread); + } + auto_lock(JSONNode *node, int thread) : mynode(node), mythread(thread){ + mynode -> lock(mythread); + } + ~auto_lock(void){ + mynode -> unlock(mythread); + } + private: + auto_lock & operator = (const auto_lock &); + auto_lock(const auto_lock &); + JSONNode * mynode; + int mythread; + }; + static void * getThisLock(JSONNode * pthis); + #endif + + #ifdef JSON_UNIT_TEST + static int getNodeAllocationCount(void); + static int getNodeDeallocationCount(void); + static int getInternalAllocationCount(void); + static int getInternalDeallocationCount(void); + static void incAllocCount(void); + static void decAllocCount(void); + static void incinternalAllocCount(void); + static void decinternalAllocCount(void); + #endif + + #ifdef JSON_WRITER + json_string write(void); + json_string write_formatted(void); + #endif + + #ifdef JSON_DEBUG + #ifndef JSON_LIBRARY + JSONNode dump(void) const; + #endif + #endif + static void deleteJSONNode(JSONNode * ptr); + static JSONNode * newJSONNode_Shallow(const JSONNode & orig); +JSON_PRIVATE + static JSONNode * newJSONNode(const JSONNode & orig JSON_MUTEX_COPY_DECL2); + static JSONNode * newJSONNode(internalJSONNode * internal_t); + //used by JSONWorker + JSONNode(const json_string & unparsed) : internal(internalJSONNode::newInternal(unparsed)) { //root, specialized because it can only be array or node + incAllocCount(); + } + JSONNode(internalJSONNode * internal_t) : internal(internal_t){ //do not increment anything, this is only used in one case and it's already taken care of + incAllocCount(); + } + JSONNode(bool, JSONNode & orig); + + void decRef(void); //decrements internal's counter, deletes it if needed + #ifdef JSON_REF_COUNT + void makeUniqueInternal(void); //makes internal it's own + void merge(JSONNode * other); + #endif + + #ifdef JSON_DEBUG + #ifndef JSON_LIBRARY + JSONNode dump(size_t & totalmemory); + #endif + #endif + + #ifdef JSON_ITERATORS + #ifndef JSON_LIBRARY + json_iterator insertFRR(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end); + reverse_iterator insertRRR(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end); + reverse_iterator insertRFF(reverse_iterator pos, JSONNode ** const _start, JSONNode ** const _end); + #endif + json_iterator insertFFF(json_iterator pos, JSONNode ** const _start, JSONNode ** const _end); + #endif + + mutable internalJSONNode * internal; + friend class JSONWorker; + friend class internalJSONNode; +}; + +/* + Implementations are here to keep the class declaration cleaner. They can't be placed in a different + file because they are inlined. +*/ +inline JSONNode::JSONNode(char mytype) : internal(internalJSONNode::newInternal(mytype)) { + JSON_ASSERT((mytype == JSON_NULL) || + (mytype == JSON_STRING) || + (mytype == JSON_NUMBER) || + (mytype == JSON_BOOL) || + (mytype == JSON_ARRAY) || + (mytype == JSON_NODE), JSON_TEXT("Not a proper JSON type")); + incAllocCount(); +} +inline JSONNode::JSONNode(const JSONNode & orig): internal(orig.internal -> incRef()) { + incAllocCount(); +} +//this allows a temp node to simply transfer its contents, even with ref counting off +inline JSONNode::JSONNode(bool, JSONNode & orig): internal(orig.internal){ + orig.internal = 0; + incAllocCount(); +} +inline JSONNode::~JSONNode(void){ + if (internal) decRef(); + decAllocCount(); +} +inline json_index_t JSONNode::size(void) const { + JSON_CHECK_INTERNAL(); + return internal -> size(); +} +inline bool JSONNode::empty(void) const { + JSON_CHECK_INTERNAL(); + return internal -> empty(); +} +inline void JSONNode::clear(void){ + JSON_CHECK_INTERNAL(); + if (!empty()) { + makeUniqueInternal(); + internal -> Children.clear(); + } +} +inline unsigned char JSONNode::type(void) const { + JSON_CHECK_INTERNAL(); + return internal -> type(); +} +inline const json_char* JSONNode::name(void) const { + JSON_CHECK_INTERNAL(); + return internal -> name(); +} +inline void JSONNode::set_name(const json_string & newname){ + JSON_CHECK_INTERNAL(); + makeUniqueInternal(); + internal -> setname(newname); +} +#ifdef JSON_COMMENTS + inline void JSONNode::set_comment(const json_string & newname){ + JSON_CHECK_INTERNAL(); + makeUniqueInternal(); + internal -> setcomment(newname); + } + inline json_string JSONNode::get_comment(void) const { + JSON_CHECK_INTERNAL(); + return internal -> getcomment(); + } +#endif +inline json_string JSONNode::as_string(void) const { + JSON_CHECK_INTERNAL(); + return internal -> as_string(); +} +inline long JSONNode::as_int(void) const { + JSON_CHECK_INTERNAL(); + return internal -> as_int(); +} +inline double JSONNode::as_float(void) const { + JSON_CHECK_INTERNAL(); + return internal -> as_float(); +} +inline bool JSONNode::as_bool(void) const { + JSON_CHECK_INTERNAL(); + return internal -> as_bool(); +} +#ifdef JSON_BINARY + inline void JSONNode::set_binary(const unsigned char * bin, json_index_t bytes){ + JSON_CHECK_INTERNAL(); + *this = JSONBase64::json_encode64(bin, bytes); + } + inline std::string JSONNode::as_binary(void) const { + JSON_ASSERT_SAFE(type() == JSON_STRING, JSON_TEXT("using as_binary for a non-string type"), return EMPTY_STRING2;); + JSON_CHECK_INTERNAL(); + return JSONBase64::json_decode64(as_string()); + } +#endif +inline JSONNode & JSONNode::operator[](const json_string & name_t){ + JSON_CHECK_INTERNAL(); + makeUniqueInternal(); + return *(*(internal -> at(name_t))); +} +inline const JSONNode & JSONNode::operator[](const json_string & name_t) const { + JSON_CHECK_INTERNAL(); + return *(*(internal -> at(name_t))); +} +#ifdef JSON_LIBRARY +inline void JSONNode::push_back(JSONNode * child){ +#else +inline void JSONNode::push_back(const JSONNode & child){ +#endif + JSON_CHECK_INTERNAL(); + makeUniqueInternal(); + internal -> push_back(child); +} + +inline void JSONNode::reserve(json_index_t size){ + makeUniqueInternal(); + internal -> reserve(size); +} +inline JSONNode & JSONNode::operator = (const JSONNode & orig){ + JSON_CHECK_INTERNAL(); + #ifdef JSON_REF_COUNT + if (internal == orig.internal) return *this; //don't want it accidentally deleting itself + #endif + decRef(); //dereference my current one + internal = orig.internal -> incRef(); //increase reference of original + return *this; +} +#ifndef JSON_LIBRARY + inline JSONNode & JSONNode::operator = (const json_char * val){ + JSON_CHECK_INTERNAL(); + *this = json_string(val); + return *this; + } +#endif + +#define NODE_SET_TYPED(type)\ + inline JSONNode & JSONNode::operator = (type val){\ + JSON_CHECK_INTERNAL();\ + makeUniqueInternal();\ + internal -> Set(val);\ + return *this;\ + } +IMPLEMENT_FOR_ALL_TYPES(NODE_SET_TYPED) + +/* + This section is the equality operators +*/ +#define NODE_CHECK_EQUALITY(type)\ + inline bool JSONNode::operator == (type val) const {\ + JSON_CHECK_INTERNAL();\ + return internal -> IsEqualToNum(val);\ + } +IMPLEMENT_FOR_ALL_NUMBERS(NODE_CHECK_EQUALITY) +inline bool JSONNode::operator == (const json_string & val) const { + JSON_CHECK_INTERNAL(); + return internal -> IsEqualTo(val); +} +#ifndef JSON_LIBRARY + inline bool JSONNode::operator == (const json_char * val) const { + JSON_CHECK_INTERNAL(); + return *this == json_string(val); + } +#endif +inline bool JSONNode::operator == (bool val) const { + JSON_CHECK_INTERNAL(); + return internal -> IsEqualTo(val); +} +inline bool JSONNode::operator == (const JSONNode & val) const { + JSON_CHECK_INTERNAL(); + return internal -> IsEqualTo(val.internal); +} + +/* + This section is the inequality operators +*/ + +#define NODE_CHECK_INEQUALITY(type)\ + inline bool JSONNode::operator != (type val) const {\ + JSON_CHECK_INTERNAL();\ + return !(*this == val);\ + } +IMPLEMENT_FOR_ALL_TYPES(NODE_CHECK_INEQUALITY) +NODE_CHECK_INEQUALITY(const JSONNode &) +#ifndef JSON_LIBRARY + NODE_CHECK_INEQUALITY(const json_char * ) +#endif + +inline void JSONNode::nullify(void){ + JSON_CHECK_INTERNAL(); + makeUniqueInternal(); + internal -> Nullify(); +} +inline void JSONNode::swap(JSONNode & other){ + JSON_CHECK_INTERNAL(); + internalJSONNode * temp = other.internal; + other.internal = internal; + internal = temp; + JSON_CHECK_INTERNAL(); +} +inline void JSONNode::decRef(void){ //decrements internal's counter, deletes it if needed + JSON_CHECK_INTERNAL(); + #ifdef JSON_REF_COUNT + internal -> decRef(); + if (internal -> hasNoReferences()) { + internalJSONNode::deleteInternal(internal); + } + #else + internalJSONNode::deleteInternal(internal); + #endif +} +#ifdef JSON_REF_COUNT + inline void JSONNode::makeUniqueInternal() { //makes internal it's own + JSON_CHECK_INTERNAL(); + internal = internal -> makeUnique(); //might return itself or a new one that's exactly the same + } +#endif +#ifdef JSON_ITERATORS + inline JSONNode::json_iterator JSONNode::begin(void){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); + makeUniqueInternal(); + return json_iterator(internal -> begin()); + } + inline JSONNode::json_iterator JSONNode::end(void){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); + makeUniqueInternal(); + return json_iterator(internal -> end()); + } + + #ifndef JSON_LIBRARY + inline JSONNode::const_iterator JSONNode::begin(void) const { + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); + return JSONNode::const_iterator(internal -> begin()); + } + inline JSONNode::const_iterator JSONNode::end(void) const { + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); + return JSONNode::const_iterator(internal -> end()); + } + inline JSONNode::reverse_iterator JSONNode::rbegin(void){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); + makeUniqueInternal(); + return JSONNode::reverse_iterator(internal -> end() - 1); + } + inline JSONNode::reverse_iterator JSONNode::rend(void){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); + makeUniqueInternal(); + return JSONNode::reverse_iterator(internal -> begin() - 1); + } + inline JSONNode::reverse_const_iterator JSONNode::rbegin(void) const { + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); + return JSONNode::reverse_const_iterator(internal -> end() - 1); + } + inline JSONNode::reverse_const_iterator JSONNode::rend(void) const { + JSON_CHECK_INTERNAL(); + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("iterating a non-iteratable node")); + return JSONNode::reverse_const_iterator(internal -> begin() - 1); + } + + inline JSONNode::iterator JSONNode::insert(json_iterator pos, const const_iterator & _start, const const_iterator & _end){ + return insertFFF(pos, _start.it, _end.it); + } + + inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const const_iterator & _start, const const_iterator & _end){ + return insertRFF(pos, _start.it, _end.it); + } + + inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const iterator & _start, const iterator & _end){ + return insertRFF(pos, _start.it, _end.it); + } + + inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end){ + return insertRRR(pos, _start.it, _end.it); + } + + inline JSONNode::reverse_iterator JSONNode::insert(reverse_iterator pos, const reverse_iterator & _start, const reverse_iterator & _end){ + return insertRRR(pos, _start.it, _end.it); + } + + inline JSONNode::iterator JSONNode::insert(json_iterator pos, const reverse_const_iterator & _start, const reverse_const_iterator & _end){ + return insertFRR(pos, _start.it, _end.it); + } + + inline JSONNode::iterator JSONNode::insert(iterator pos, const reverse_iterator & _start, const reverse_iterator & _end){ + return insertFRR(pos, _start.it, _end.it); + } + #endif + + inline JSONNode::json_iterator JSONNode::insert(json_iterator pos, const json_iterator & _start, const json_iterator & _end){ + return insertFFF(pos, json_iterator_ptr(_start), json_iterator_ptr(_end)); + } +#endif +#ifdef JSON_WRITER + inline json_string JSONNode::write(void){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Writing a non-writable node"), return JSON_TEXT("");); + return internal -> Write(0xFFFFFFFF, true); + } + inline json_string JSONNode::write_formatted(void){ + JSON_CHECK_INTERNAL(); + JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Writing a non-writable node"), return JSON_TEXT("");); + return internal -> Write(0, true); + } +#endif +#ifndef JSON_PREPARSE + inline void JSONNode::preparse(void){ + JSON_CHECK_INTERNAL(); + internal -> preparse(); + } +#endif +#ifdef JSON_VALIDATE + inline bool JSONNode::validate(void){ + JSON_CHECK_INTERNAL(); + if (type() == JSON_NULL) return false; + JSON_ASSERT_SAFE(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Validating non root node"), return false;); + #ifndef JSON_PREPARSE + internal -> Fetch(); //will nullify it if it's bad + #endif + if (type() == JSON_NULL) return false; + return internal -> validate(); + } +#endif +#ifdef JSON_DEBUG + #ifndef JSON_LIBRARY + inline JSONNode JSONNode::dump(void) const { + JSON_CHECK_INTERNAL(); + JSONNode dumpage(JSON_NODE); + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); + size_t total = 0; + JSONNode node = internal -> Dump(total); + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("total bytes used"), total))); + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), sizeof(JSONNode)))); + dumpage.push_back(JSON_NEW(node)); + return dumpage; + } + inline JSONNode JSONNode::dump(size_t & totalmemory){ + JSON_CHECK_INTERNAL(); + JSONNode dumpage(JSON_NODE); + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), sizeof(JSONNode)))); + dumpage.push_back(JSON_NEW(internal -> Dump(totalmemory))); + return dumpage; + } + #endif +#endif + +inline void JSONNode::deleteJSONNode(JSONNode * ptr){ + #ifdef JSON_MEMORY_CALLBACKS + ptr -> ~JSONNode(); + libjson_free(ptr); + #else + delete ptr; + #endif +} +inline JSONNode * _newJSONNode(const JSONNode & orig){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) JSONNode(orig); + #else + return new JSONNode(orig); + #endif +} +inline JSONNode * JSONNode::newJSONNode(const JSONNode & orig JSON_MUTEX_COPY_DECL){ + #ifdef JSON_MUTEX_CALLBACKS + if (parentMutex){ + JSONNode * temp = _newJSONNode(orig); + temp -> set_mutex(parentMutex); + return temp; + } + #endif + return _newJSONNode(orig); +} +inline JSONNode * JSONNode::newJSONNode(internalJSONNode * internal_t){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) JSONNode(internal_t); + #else + return new JSONNode(internal_t); + #endif +} + +inline JSONNode * JSONNode::newJSONNode_Shallow(const JSONNode & orig){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) JSONNode(true, const_cast(orig)); + #else + return new JSONNode(true, const_cast(orig)); + #endif +} +#endif diff --git a/src/mir_core/src/json/JSONNode_Mutex.cpp b/src/mir_core/src/json/JSONNode_Mutex.cpp new file mode 100644 index 0000000000..497e867f62 --- /dev/null +++ b/src/mir_core/src/json/JSONNode_Mutex.cpp @@ -0,0 +1,214 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" +#include + +#ifdef JSON_MUTEX_CALLBACKS + +json_mutex_callback_t json_lock_callback = 0; +json_mutex_callback_t json_unlock_callback = 0; +void * global_mutex = 0; +void * manager_mutex = 0; + +struct AutoLock { + AutoLock(void){ + json_lock_callback(manager_mutex); + } + ~AutoLock(void){ + json_unlock_callback(manager_mutex); + } +}; + +#include +#ifdef JSON_MUTEX_MANAGE + json_mutex_callback_t json_destroy = 0; + std::map mutex_manager; + + //make sure that the global mutex is taken care of too + struct auto_global { + auto_global(void){} + ~auto_global(void){ + if (global_mutex){ + JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("No json_destroy in mutex managed mode"), return;); + json_destroy(global_mutex); + } + } + }; + auto_global cleanupGlobal; +#endif + +void JSONNode::register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock){ + json_lock_callback = lock; + json_unlock_callback = unlock; + manager_mutex = manager_lock; +} + +void JSONNode::set_global_mutex(void * mutex){ + global_mutex = mutex; +} + +void JSONNode::set_mutex(void * mutex){ + makeUniqueInternal(); + internal -> _set_mutex(mutex); +} + +std::map > threadlocks; + +void * JSONNode::getThisLock(JSONNode * pthis){ + if (pthis -> internal -> mylock){ + return pthis -> internal -> mylock; + } + JSON_ASSERT_SAFE(global_mutex, JSON_TEXT("No global_mutex"), return 0;); + return global_mutex; +} + +void JSONNode::lock(int thread){ + JSON_ASSERT_SAFE(json_lock_callback, JSON_TEXT("No locking callback"), return;); + + AutoLock lockControl; + + //first, figure out what needs to be locked + void * thislock = getThisLock(this); + #ifdef JSON_SAFE + if (!thislock) return; + #endif + + //make sure that the same thread isn't locking it more than once (possible due to complex ref counting) + std::map >::iterator it = threadlocks.find(thread); + if (it == threadlocks.end()) { + std::map newthread; + newthread[thislock] = 1; + threadlocks.insert(std::pair >(thread, newthread)); + } else { //this thread already has some things locked, check if the current mutex is + std::map & newthread = it -> second; + std::map::iterator locker = newthread.find(thislock); + if (locker == newthread.end()) { //current mutex is not locked, set it to locked + newthread.insert(std::pair(thislock, 1)); + } else { //it's already locked, don't relock it + ++(locker -> second); + return; //don't try to relock, it will deadlock the program + } + } + + //if I need to, lock it + json_lock_callback(thislock); +} + +void JSONNode::unlock(int thread){ + JSON_ASSERT_SAFE(json_unlock_callback, JSON_TEXT("No unlocking callback"), return;); + + AutoLock lockControl; + + //first, figure out what needs to be locked + void * thislock = getThisLock(this); + #ifdef JSON_SAFE + if (!thislock) return; + #endif + + //get it out of the map + std::map >::iterator it = threadlocks.find(thread); + JSON_ASSERT_SAFE(it != threadlocks.end(), JSON_TEXT("thread unlocking something it didn't lock"), return;); + + //get the mutex out of the thread + std::map & newthread = it -> second; + std::map::iterator locker = newthread.find(thislock); + JSON_ASSERT_SAFE(locker != newthread.end(), JSON_TEXT("thread unlocking mutex it didn't lock"), return;); + + //unlock it + if (--(locker -> second)) return; //other nodes is this same thread still have a lock on it + + //if I need to, unlock it + newthread.erase(locker); + json_unlock_callback(thislock); +} + +#ifdef JSON_MUTEX_MANAGE + void JSONNode::register_mutex_destructor(json_mutex_callback_t destroy){ + json_destroy = destroy; + } +#endif + +void internalJSONNode::_set_mutex(void * mutex, bool unset){ + if (unset) _unset_mutex(); //for reference counting + mylock = mutex; + if (mutex){ + #ifdef JSON_MUTEX_MANAGE + std::map::iterator it = mutex_manager.find(mutex); + if (it == mutex_manager.end()) { + mutex_manager.insert(std::pair(mutex, 1)); + } else { + ++it -> second; + } + #endif + json_foreach(Children, myrunner){ + (*myrunner) -> set_mutex(mutex); + } + } +} + +void internalJSONNode::_unset_mutex(void){ + #ifdef JSON_MUTEX_MANAGE + if (mylock){ + std::map::iterator it = mutex_manager.find(mylock); + JSON_ASSERT_SAFE(it != mutex_manager.end(), JSON_TEXT("Mutex not managed"), return;); + --it -> second; + if (it -> second == 0){ + JSON_ASSERT_SAFE(json_destroy, JSON_TEXT("You didn't register a destructor for mutexes"), return;); + mutex_manager.erase(it); + } + } + #endif +} + +#ifdef JSON_DEBUG + #ifndef JSON_LIBRARY + JSONNode internalJSONNode::DumpMutex(void) const { + JSONNode mut(JSON_NODE); + mut.set_name(JSON_TEXT("mylock")); + #ifdef JSON_MUTEX_MANAGE + if (mylock){ + mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)mylock))); + std::map::iterator it = mutex_manager.find(mylock); + if (it == mutex_manager.end()) { + mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), JSON_TEXT("error")))); + } else { + mut.push_back(JSON_NEW(JSONNode(JSON_TEXT("references"), it -> second))); + } + } else { + mut = (long)mylock; + } + #else + mut = (long)mylock; + #endif + return mut; + } + #endif +#endif + +#else + #ifdef JSON_MUTEX_MANAGE + #error You can not have JSON_MUTEX_MANAGE on without JSON_MUTEX_CALLBACKS + #endif +#endif diff --git a/src/mir_core/src/json/JSONOptions.h b/src/mir_core/src/json/JSONOptions.h new file mode 100644 index 0000000000..d4bd343677 --- /dev/null +++ b/src/mir_core/src/json/JSONOptions.h @@ -0,0 +1,188 @@ +#ifndef JSON_OPTIONS_H +#define JSON_OPTIONS_H + +/** + * This file holds all of the compiling options for easy access and so + * that you don't have to remember them, or look them up all the time + */ + +/* + * JSON_LIBRARY must be declared if libjson is compiled as a static or dynamic + * library. This exposes a C-style interface, but none of the inner workings of libjson + */ +#define JSON_LIBRARY + +/* + * JSON_DEBUG is used to perform extra error checking. Because libjson usually + * does on the fly parsing, validation is impossible, so this option will allow + * you to register an error callback so that you can record what is going wrong + * before the library crashes. This option does not protect from these errors, + * it simply tells you about them, which is nice for debugging, but not preferable + * for release candidates + */ +//#define JSON_DEBUG + +/* + * JSON_SAFE performs similarly to JSON_DEBUG, except this option does protect + * from the errors that it encounters. This option is recommended for those who + * feel it's possible for their program to encounter invalid json. + */ +#define JSON_SAFE + +/* + * JSON_STDERROR routes error messages to cerr instead of a callback, this + * option hides the callback registering function. This will usually display + * messages in the console + */ +//#define JSON_STDERROR + +/* + * JSON_PREPARSE causes all parsing to be done immediately. By default, libjson + * parses nodes on the fly as they are needed, this makes parsing much faster if + * your program gets a lot of information that it doesn't need. An example of + * this would be a client application communicating with a server if the server + * returns things like last modified date and other things that you don't use. + */ +//#define JSON_PREPARSE + +/* + * JSON_LESS_MEMORY will force libjson to let go of memory as quickly as it can + * this is recommended for software that has to run on less than optimal machines. + * It will cut libjson's memory usage by about 20%, but also run slightly slower. + * It's recommended that you also compile using the -Os option, as this will also + * reduce the size of the library + */ +//#define JSON_LESS_MEMORY + +/* + * JSON_UNICODE tells libjson to use wstrings instead of regular strings, this + * means that libjson supports the full array of unicode characters, but also takes + * much more memory and processing power. + */ +//#define JSON_UNICODE + +/* + * JSON_REF_COUNT causes libjson to reference count JSONNodes, which makes copying + * and passing them around much faster. It is recommended that this stay on for + * most uses + */ +#define JSON_REF_COUNT + +/* + * JSON_BINARY is used to support binary, which is base64 encoded and decoded by libjson, + * if this option is not turned on, no base64 support is included + */ +//#define JSON_BINARY + +/* + * JSON_MEMORY_CALLBACKS exposes functions to register callbacks for allocating, resizing, + * and freeing memory. Because libjson is designed for costomizability, it is feasible + * that some users would like to further add speed by having the library utilize a memory + * pool. With this option turned on, the default behavior is still done internally unless + * a callback is registered. So you can have this option on and mot use it. + */ +#define JSON_MEMORY_CALLBACKS + +/* + * JSON_MEMORY_MANAGE is used to create functionality to automatically track and clean + * up memory that has been allocated by the user. This includes strings, binary data, and + * nodes. It also exposes bulk delete functions. + */ +//#define JSON_MEMORY_MANAGE + +/* + * JSON_MUTEX_CALLBACKS exposes functions to register callbacks to lock and unlock + * mutexs and functions to lock and unlock JSONNodes and all of it's children. This + * does not prevent other threads from accessing the node, but will prevent them from + * locking it. It is much easier for the end programmer to allow libjson to manage + * your mutexs because of reference counting and manipulating trees, libjson automatically + * tracks mutex controls for you, so you only ever lock what you need to + */ +//#define JSON_MUTEX_CALLBACKS + +/* + * JSON_MUTEX_MANAGE lets you set mutexes and forget them, libjson will not only keep + * track of the mutex, but also keep a count of how many nodes are using it, and delete + * it when there are no more references + */ +//#define JSON_MUTEX_MANAGE + +/* + * JSON_ISO_STRICT turns off all code that uses non-standard C++. This removes all + * references to long long and long double as well as a few others + */ +//#define JSON_ISO_STRICT + +/* + * JSON_ITERATORS turns on all of libjson's iterating functionality. This would usually + * only be turned off while compiling for use with C + */ +//#define JSON_ITERATORS + +/* + * JSON_WRITER turns on libjson's writing capabilties. Without this libjson can only + * read and parse json, this allows it to write back out + */ +#define JSON_WRITER + +/* + * JSON_NEWLINE affects how libjson writes. If this option is turned on, libjson + * will use whatever it's defined as for the newline signifier, otherwise, it will use + * standard unix \n. + */ +//#define JSON_NEWLINE "\r\n" //\r\n is standard for most windows and dos programs + +/* + * JSON_COMMENTS tells libjson to store and write comments. libjson always supports + * parsing json that has comments in it as it simply ignores them, but with this option + * it keeps the comments and allows you to insert further comments + */ +//#define JSON_COMMENTS + +/* + * JSON_INDENT affects how libjson writes. If this option is turned on, libjson + * will use \t to indent formatted json, otherwise it will use the number of characters + * that you specify. If this is not turned on, then it will use the tab (\t) character + */ +//#define JSON_INDENT " " + +/* + * JSON_WRITE_BASH_COMMENTS will cause libjson to write all comments in bash (#) style + * if this option is not turned on, then it will use C-style comments. Bash comments are + * all single line + */ +//#define JSON_WRITE_BASH_COMMENTS + +/* + * JSON_WRITE_SINGLE_LINE_COMMENTS will cause libjson to write all comments in using // + * notation, or (#) if that option is on. Some parsers do not support multiline C comments + * although, this option is not needed for bash comments, as they are all single line anyway + */ +//#define JSON_WRITE_SINGLE_LINE_COMMENTS + +/* + * JSON_VALIDATE turns on validation features of libjson. This option requires JSON_SAFE + */ +//#define JSON_VALIDATE + +/* + * JSON_CASE_INSENSITIVE_FUNCTIONS turns on funtions for finding child nodes in a case- + * insenititve way + */ +//#define JSON_CASE_INSENSITIVE_FUNCTIONS + +/* + * JSON_UNIT_TEST is used to maintain and debug the libjson. It makes all private + * members and functions public so that tests can do checks of the inner workings + * of libjson. This should not be turned on by end users. + */ +//#define JSON_UNIT_TEST + +/* + * JSON_INDEX_TYPE allows you th change the size type for the children functions. If this + * option is not used then unsigned int is used. This option is useful for cutting down + * on memory, or using huge numbers of child nodes (over 4 billion) + */ +//#define JSON_INDEX_TYPE unsigned int + +#endif diff --git a/src/mir_core/src/json/JSONWorker.cpp b/src/mir_core/src/json/JSONWorker.cpp new file mode 100644 index 0000000000..cf8254a357 --- /dev/null +++ b/src/mir_core/src/json/JSONWorker.cpp @@ -0,0 +1,698 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" + +#include "JSONWorker.h" + +#ifdef JSON_VALIDATE +JSONNode JSONWorker::validate(const json_string & json){ + JSONNode res = parse(json); + if (!res.validate()) { + throw std::invalid_argument(EMPTY_STRING2); + } + return JSONNode(true, res); //forces it to simply return the original interal, even with ref counting off +} +#endif + +JSONNode JSONWorker::parse(const json_string & json){ + json_auto s; + #if defined JSON_DEBUG || defined JSON_SAFE + json_char lastchar; + s.set(RemoveWhiteSpace(json, lastchar)); + #else + s.set(RemoveWhiteSpace(json)); + #endif + + #ifdef JSON_COMMENTS + json_char firstchar = s.ptr[0]; + json_string _comment; + json_char * runner = s.ptr; + if (firstchar == '\5') { //multiple comments will be consolidated into one + newcomment: + while(*(++runner) != '\5') { + JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed")); + _comment += *runner; + } + firstchar = *(++runner); //step past the trailing tag + if (firstchar == '\5') { + _comment += '\n'; + goto newcomment; + } + } + #else + const json_char firstchar = s.ptr[0]; + #endif + + switch (firstchar){ + case '{': + case '[': + #if defined JSON_DEBUG || defined JSON_SAFE + if (firstchar == '[') { + if (lastchar != ']') { + JSON_FAIL(JSON_TEXT("Missing final ]")); + break; + } + } else { + if (lastchar != '}') { + JSON_FAIL(JSON_TEXT("Missing final }")); + break; + } + } + #endif + #ifdef JSON_COMMENTS + JSONNode foo(runner); + foo.set_comment(_comment); + return JSONNode(true, foo); //forces it to simply return the original interal, even with ref counting off + #else + return JSONNode(s.ptr); + #endif + } + + JSON_FAIL(JSON_TEXT("Not JSON!")); + throw std::invalid_argument(EMPTY_STRING2); +} + +#define QUOTECASE()\ + case JSON_TEXT('\"'):\ + while (*(++p) != JSON_TEXT('\"')) {\ + JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), return json_string::npos;);\ + }\ + break; + +#ifdef JSON_DEBUG + #define NULLCASE(error)\ + case JSON_TEXT('\0'):\ + JSON_FAIL_SAFE(error, return json_string::npos;);\ + break; +#else + #define NULLCASE(error) +#endif + +#define BRACKET(left, right)\ + case left: {\ + size_t brac = 1;\ + while (brac){\ + switch (*(++p)) {\ + case right:\ + --brac;\ + break;\ + case left:\ + ++brac;\ + break;\ + QUOTECASE()\ + NULLCASE(JSON_TEXT("Null terminator inside of a bracket"))\ + }\ + }\ + break;}\ + case right:\ + return json_string::npos; + +size_t JSONWorker::FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos){ + const json_char * start = value_t.c_str(); + const json_char * p = start + pos; //start at the correct offset + do { + if (*p == ch) return p - start; + switch (*p){ + BRACKET(JSON_TEXT('['), JSON_TEXT(']')) + BRACKET(JSON_TEXT('{'), JSON_TEXT('}')) + QUOTECASE() + } + } while(*(++p)); + return json_string::npos; +} + +#ifdef JSON_COMMENTS + #define COMMENT_DELIMITER() *runner++='\5' + #define AND_RUNNER ,runner + inline void SingleLineComment(const json_char * & p, json_char * & runner){ + COMMENT_DELIMITER(); + while((*(++p)) && (*p != JSON_TEXT('\n'))) { + *runner++=*p; + } + COMMENT_DELIMITER(); + } +#else + #define COMMENT_DELIMITER() (void)0 + #define AND_RUNNER +#endif + +inline void SingleLineComment(const json_char * & p){ + while((*(++p)) && (*p != JSON_TEXT('\n'))); +} + +#if defined JSON_DEBUG || defined JSON_SAFE + json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t, json_char & last){ +#else + json_char * JSONWorker::RemoveWhiteSpace(const json_string & value_t){ +#endif + json_char * result; + json_char * runner = result = json_malloc(value_t.length() + 1); //dealing with raw memory is faster than adding to a json_string + JSON_ASSERT(result, JSON_TEXT("Out of memory")); + const json_char * p = value_t.c_str(); + while(*p){ + switch(*p){ + case JSON_TEXT(' '): //defined as white space + case JSON_TEXT('\t'): //defined as white space + case JSON_TEXT('\n'): //defined as white space + case JSON_TEXT('\r'): //defined as white space + break; + case JSON_TEXT('/'): //a C comment + if (*(++p) == JSON_TEXT('*')) { //a multiline comment + COMMENT_DELIMITER(); + while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))) { + JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), COMMENT_DELIMITER(); goto endofloop;); + *runner++=*p; + } + ++p; + COMMENT_DELIMITER(); + break; + } + //Should be a single line C comment, so let it fall through to use the bash comment stripper + JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;); + case JSON_TEXT('#'): //a bash comment + SingleLineComment(p AND_RUNNER); + break; + case JSON_TEXT('\"'): //a quote + *runner++=JSON_TEXT('\"'); + while(*(++p) != JSON_TEXT('\"')) { //find the end of the quotation, as white space is preserved within it + JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a quotation"), goto endofloop;); + switch(*p){ + case JSON_TEXT('\\'): + *runner++=JSON_TEXT('\\'); + *runner++=(*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p; //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on + break; + default: + *runner++=*p; + break; + } + } + //no break, let it fall through so that the trailing quote gets added + default: + JSON_ASSERT_SAFE((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); + JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;); + *runner++=*p; + break; + } + ++p; + } + #ifdef JSON_SAFE + endofloop: + #endif + #if defined JSON_DEBUG || defined JSON_SAFE + last = *(runner - 1); + #endif + *runner = JSON_TEXT('\0'); + return result; + } + +json_string JSONWorker::RemoveWhiteSpaceAndComments(const json_string & value_t){ + json_string result; + result.reserve(value_t.length()); + const json_char * p = value_t.c_str(); + while(*p){ + switch(*p){ + case JSON_TEXT(' '): //defined as white space + case JSON_TEXT('\t'): //defined as white space + case JSON_TEXT('\n'): //defined as white space + case JSON_TEXT('\r'): //defined as white space + break; + case JSON_TEXT('/'): //a C comment + if (*(++p) == JSON_TEXT('*')) { //a multiline comment + while ((*(++p) != JSON_TEXT('*')) || (*(p + 1) != JSON_TEXT('/'))) { + JSON_ASSERT_SAFE(*p, JSON_TEXT("Null terminator inside of a multiline quote"), goto endofloop;); + } + ++p; + break; + } + //Should be a single line C comment, so let it fall through to use the bash comment stripper + JSON_ASSERT_SAFE(*p == JSON_TEXT('/'), JSON_TEXT("stray / character, not quoted, or a comment"), goto endofloop;); + case JSON_TEXT('#'): //a bash comment + SingleLineComment(p); + break; + case JSON_TEXT('\"'): //a quote + result += JSON_TEXT('\"'); + while(*(++p) != JSON_TEXT('\"')) { //find the end of the quotation, as white space is preserved within it + JSON_ASSERT(*p, JSON_TEXT("Null terminator inside of a quotation")); + switch(*p){ + case JSON_TEXT('\\'): + result += JSON_TEXT('\\'); + result += (*++p == JSON_TEXT('\"')) ? JSON_TEXT('\1') : *p; //an escaped quote will reak havoc will all of my searching functions, so change it into an illegal character in JSON for convertion later on + break; + default: + result += *p; + break; + } + } + //no break, let it fall through so that the trailing quote gets added + default: + JSON_ASSERT_SAFE((json_uchar)*p >= 32, JSON_TEXT("Invalid JSON character detected (lo)"), goto endofloop;); + JSON_ASSERT_SAFE((json_uchar)*p <= 126, JSON_TEXT("Invalid JSON character detected (hi)"), goto endofloop;); + result += *p; + break; + } + ++p; + } + #ifdef JSON_SAFE + endofloop: + #endif + return result; +} + +/* + These three functions analyze json_string literals and convert them into std::strings + This includes dealing with special characters and utf characters + */ +#ifdef JSON_UNICODE + inline json_uchar SurrogatePair(const json_uchar hi, const json_uchar lo){ + JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit")); + JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("size of json_char is not 32-bit")); + return (((hi << 10) & 0x1FFC00) + 0x10000) | lo & 0x3FF; + } + + json_string JSONWorker::UTF(const json_char * & pos){ + json_string result; + json_uchar first = UTF8(pos); + if ((*(pos + 1) == '\\') && (*(pos + 2) == 'u')) { + pos += 2; + json_uchar second = UTF8(pos); + //surrogate pair, not two characters + if ((first > 0xD800) && (first < 0xDBFF) && (second > 0xDC00) && (second < 0xDFFF)) { + result += SurrogatePair(first, second); + } else { + result += first; + result += second; + } + } else { + result += first; + } + JSON_ASSERT(!result.empty(), JSON_TEXT("missing case, somehow UTF returned empty")); + return result; + } +#endif + +json_uchar JSONWorker::UTF8(const json_char * & pos){ + #ifdef JSON_UNICODE + ++pos; + json_uchar temp = Hex(pos) << 8; + ++pos; + return temp | Hex(pos); + #else + JSON_ASSERT(*(pos + 1) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hihi)")); + JSON_ASSERT(*(pos + 2) == JSON_TEXT('0'), JSON_TEXT("wide utf character (hilo)")); + pos += 3; + return Hex(pos); + #endif +} + +static json_char szU8Buffer[10]; + +json_char* JSONWorker::UTF8_2(const json_char * & pos){ + #ifdef JSON_UNICODE + ++pos; + json_uchar temp = Hex(pos) << 8; + ++pos; + *szU8Buffer = temp | Hex(pos); + szU8Buffer[1] = 0; + return szU8Buffer; + #else + union { + unsigned short uChar; + unsigned char uByte[2]; + }; + pos++; + strncpy(szU8Buffer+5,pos,4); + szU8Buffer[9] = 0; + uChar = strtoul(szU8Buffer+5,NULL,16); + if (uChar<0x80) { + szU8Buffer[0] = uChar; + szU8Buffer[1] = 0; + } else if (uChar<0x7ff) { + szU8Buffer[0] = 0xc0+(uByte[1]<<2)+(uByte[0]>>6); + szU8Buffer[1] = 0x80+(uByte[0]&0x3f); + szU8Buffer[2] = 0; + } else { + szU8Buffer[0] = 0xe0+(uByte[1]>>4); + szU8Buffer[1] = 0x80+((uByte[1]&0x0f)<<2)+(uByte[0]>>6); + szU8Buffer[2] = 0x80+(uByte[0]&0x3f); + szU8Buffer[3] = 0; + } + + pos += 3; + return szU8Buffer; + #endif +} + +json_char JSONWorker::Hex(const json_char * & pos){ + /* + takes the numeric value of the next two characters and convert them + \u0058 becomes 0x58 + + In case of \u, it's SpecialChar's responsibility to move past the first two chars + as this method is also used for \x + */ + //First character + json_uchar hi = *pos++ - 48; + if (hi > 48){ //A-F don't immediately follow 0-9, so have to pull them down a little + hi -= 39; + } else if (hi > 9){ //neither do a-f + hi -= 7; + } + //second character + json_uchar lo = *pos - 48; + if (lo > 48){ //A-F don't immediately follow 0-9, so have to pull them down a little + lo -= 39; + } else if (lo > 9){ //neither do a-f + lo -= 7; + } + //combine them + return (json_char)((hi << 4) | lo); +} + +inline json_char FromOctal(const json_char * & str){ + JSON_ASSERT(json_strlen(str) > 3, JSON_TEXT("Octal will go out of bounds")); + const json_uchar top = ((json_uchar)(*(str++) - 48)); + const json_uchar middle = (json_uchar)(*(str++) - 48); + const json_uchar bottom = (json_uchar)(*str - 48); + return (json_char)((top << 6) | (middle << 3) | bottom); +} + +void JSONWorker::SpecialChar(const json_char * & pos, json_string & res){ + /* + Since JSON uses forward slash escaping for special characters within strings, I have to + convert these escaped characters into C characters + */ + switch(*pos){ + case JSON_TEXT('\1'): //quote character (altered by RemoveWhiteSpace) + res += JSON_TEXT('\"'); + break; + case JSON_TEXT('t'): //tab character + res += JSON_TEXT('\t'); + break; + case JSON_TEXT('n'): //newline character + res += JSON_TEXT('\n'); + break; + case JSON_TEXT('r'): //return character + res += JSON_TEXT('\r'); + break; + case JSON_TEXT('\\'): //backslash + res += JSON_TEXT('\\'); + break; + case JSON_TEXT('/'): //forward slash + res += JSON_TEXT('/'); + break; + case JSON_TEXT('b'): //backspace + res += JSON_TEXT('\b'); + break; + case JSON_TEXT('f'): //formfeed + res += JSON_TEXT('\f'); + break; + case JSON_TEXT('v'): //vertical tab + res += JSON_TEXT('\v'); + break; + case JSON_TEXT('\''): //apostrophe + res += JSON_TEXT('\''); + break; + case JSON_TEXT('x'): //hexidecimal ascii code + res += Hex(++pos); + break; + case JSON_TEXT('u'): //utf character + #ifdef JSON_UNICODE + res += UTF(pos); + #else + //res += UTF8(pos); + res.append(UTF8_2(pos)); + #endif + break; + + //octal encoding + case JSON_TEXT('1'): + case JSON_TEXT('2'): + case JSON_TEXT('3'): + case JSON_TEXT('4'): + case JSON_TEXT('5'): + case JSON_TEXT('6'): + case JSON_TEXT('7'): + case JSON_TEXT('0'): + res += FromOctal(pos); + break; + + #ifdef JSON_DEBUG + default: + JSON_FAIL(JSON_TEXT("Unsupported escaped character")); + #endif + } +} + +#ifdef JSON_LESS_MEMORY + inline void doflag(const internalJSONNode * flag, bool which, bool x){ + if (which){ + flag -> _name_encoded = x; + } else { + flag -> _string_encoded = x; + } + } + + json_string JSONWorker::FixString(const json_string & value_t, const internalJSONNode * flag, bool which){ + #define setflag(x) doflag(flag, which, x) +#else + json_string JSONWorker::FixString(const json_string & value_t, bool & flag){ + #define setflag(x) flag = x +#endif + /* + Do things like unescaping + */ + setflag(false); + json_string res; + res.reserve(value_t.length()); //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating + const json_char * p = value_t.c_str(); + while(*p){ + switch (*p){ + case JSON_TEXT('\\'): + setflag(true); + SpecialChar(++p, res); + break; + default: + res += *p; + break; + } + ++p; + } + return res; +} + +#ifdef JSON_UNICODE + json_string JSONWorker::toSurrogatePair(json_uchar C){ + JSON_ASSERT(sizeof(unsigned int) == 4, JSON_TEXT("size of unsigned int is not 32-bit")); + JSON_ASSERT(sizeof(unsigned short) == 2, JSON_TEXT("size of unsigned short is not 16-bit")); + JSON_ASSERT(sizeof(json_uchar) == 4, JSON_TEXT("json_char is not 32-bit")); + //Compute the high surrogate + const unsigned int U = (C >> 16) & 31; + unsigned short HiSurrogate = 0xD800 | (((unsigned short)U - 1) << 6) | ((unsigned short)C) >> 10; + + //compute the low surrogate + unsigned short LoSurrogate = (unsigned short) (0xDC00 | ((unsigned short)C) & 1023); + + json_string res; + res += toUTF8(HiSurrogate); + res += toUTF8(LoSurrogate); + return res; + } +#endif + +json_string JSONWorker::toUTF8(json_uchar p){ + #ifdef JSON_UNICODE + if (p > 0xFFFF) return toSurrogatePair(p); + #endif + json_string res(JSON_TEXT("\\u")); + #ifdef JSON_UNICODE + json_uchar hihi = ((p & 0xF000) >> 12) + 48; + if (hihi > 57) hihi += 7; //A-F don't immediately follow 0-9, so have to further adjust those + json_uchar hilo = ((p & 0x0F00) >> 8) + 48; + if (hilo > 57) hilo += 7; //A-F don't immediately follow 0-9, so have to further adjust those + res += hihi; + res += hilo; + json_uchar hi = ((p & 0x00F0) >> 4) + 48; + #else + res += JSON_TEXT("00"); + json_uchar hi = (p >> 4) + 48; + #endif + //convert the character to be escaped into two digits between 0 and 15 + if (hi > 57) hi += 7; //A-F don't immediately follow 0-9, so have to further adjust those + json_uchar lo = (p & 0x000F) + 48; + if (lo > 57) lo += 7; //A-F don't immediately follow 0-9, so have to further adjust those + res += hi; + res += lo; + return res; +} + +json_string JSONWorker::UnfixString(const json_string & value_t, bool flag){ + if (!flag) return value_t; + /* + Re-escapes a json_string so that it can be written out into a JSON file + */ + json_string res; + res.reserve(value_t.length()); //since it goes one character at a time, want to reserve it first so that it doens't have to reallocating + const json_char * p = value_t.c_str(); + while(*p){ + switch(*p){ + case JSON_TEXT('\"'): //quote character + res += JSON_TEXT("\\\""); + break; + case JSON_TEXT('\t'): //tab character + res += JSON_TEXT("\\t"); + break; + case JSON_TEXT('\n'): //newline character + res += JSON_TEXT("\\n"); + break; + case JSON_TEXT('\r'): //return character + res += JSON_TEXT("\\r"); + break; + case JSON_TEXT('\\'): //backslash + res += JSON_TEXT("\\\\"); + break; + case JSON_TEXT('/'): //forward slash + res += JSON_TEXT("\\/"); + break; + case JSON_TEXT('\b'): //backspace + res += JSON_TEXT("\\b"); + break; + case JSON_TEXT('\f'): //formfeed + res += JSON_TEXT("\\f"); + break; + case JSON_TEXT('\v'): //vertical tab + res += JSON_TEXT("\\v"); + break; + case JSON_TEXT('\''): //apostrophe + res += JSON_TEXT("\\\'"); + break; + default: + /*if (((json_uchar)(*p) < 32) || ((json_uchar)(*p) > 126)) { + //res += toUTF8((json_uchar)(*p)); + } else*/ { + res += *p; + } + break; + } + ++p; + } + return res; +} + +//Create a childnode +#ifdef JSON_COMMENTS + #define ARRAY_PARAM bool array //Just to supress warnings +#else + #define ARRAY_PARAM bool +#endif +inline void JSONWorker::NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, ARRAY_PARAM){ + #ifdef JSON_COMMENTS + const json_char * runner = (array) ? value.c_str() : name.c_str(); + json_string _comment; + if (*runner == '\5') { //multiple comments will be consolidated into one + newcomment: + while(*(++runner) != '\5') { + JSON_ASSERT(*runner, JSON_TEXT("Removing white space failed")); + _comment += *runner; + } + if (*(++runner) == '\5') { //step past the trailing tag + _comment += '\n'; + goto newcomment; + } + } + internalJSONNode * myinternal; + if (array){ + myinternal = internalJSONNode::newInternal(name, runner); + } else { + myinternal = internalJSONNode::newInternal(++runner, value); + } + JSONNode * child = JSONNode::newJSONNode(myinternal); + child -> set_comment(_comment); + const_cast(parent) -> Children.push_back(child); //attach it to the parent node + #else + const_cast(parent) -> Children.push_back(JSONNode::newJSONNode(internalJSONNode::newInternal(name.c_str() + 1, value))); //attach it to the parent node + #endif +} + +//Create a subarray +void JSONWorker::DoArray(const internalJSONNode * parent, const json_string & value_t){ + /* + This takes an array and creates nodes out of them + */ + JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoArray is empty")); + JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('['), JSON_TEXT("DoArray is not an array"), parent -> Nullify(); return;); + const size_t len = value_t.length(); + if (len <= 2) return; // just a [] (blank array) + + //Not sure what's in the array, so we have to use commas + size_t starting = 1; //ignore the [ + size_t ending = FindNextRelevant(JSON_TEXT(','), value_t, 1); + while (ending != json_string::npos){ + #ifdef JSON_SAFE + json_string newValue = value_t.substr(starting, ending - starting); + JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;); + NewNode(parent, JSON_TEXT(""), newValue, true); + #else + NewNode(parent, JSON_TEXT(""), value_t.substr(starting, ending - starting), true); + #endif + starting = ending + 1; + ending = FindNextRelevant(JSON_TEXT(','), value_t, starting); + } + //since the last one will not find the comma, we have to add it here, but ignore the final ] + + #ifdef JSON_SAFE + json_string newValue = value_t.substr(starting, len - starting - 1); + JSON_ASSERT_SAFE(FindNextRelevant(JSON_TEXT(':'), newValue, 0) == json_string::npos, JSON_TEXT("Key/Value pairs are not allowed in arrays"), parent -> Nullify(); return;); + NewNode(parent, JSON_TEXT(""), newValue, true); + #else + NewNode(parent, JSON_TEXT(""), value_t.substr(starting, len - starting - 1), true); + #endif +} + +//Create all child nodes +void JSONWorker::DoNode(const internalJSONNode * parent, const json_string & value_t){ + /* + This take a node and creates its members and such + */ + JSON_ASSERT(!value_t.empty(), JSON_TEXT("DoNode is empty")); + JSON_ASSERT_SAFE(value_t[0] == JSON_TEXT('{'), JSON_TEXT("DoNode is not an node"), parent -> Nullify(); return;); + const size_t len = value_t.length(); + if (len <= 2) return; // just a {} (blank node) + + size_t name_starting = 1; //ignore the { + size_t name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, 1); //find where the name ends + JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;); + json_string name = value_t.substr(name_starting, name_ending - 2); //pull the name out + size_t value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending); //find the end of the value + while (value_ending != json_string::npos){ + NewNode(parent, name, value_t.substr(name_ending + 1, value_ending - name_ending - 1), false); + name_starting = value_ending + 1; + name_ending = FindNextRelevant(JSON_TEXT(':'), value_t, name_starting); + JSON_ASSERT_SAFE(name_ending != json_string::npos, JSON_TEXT("Missing :"), parent -> Nullify(); return;); + name = value_t.substr(name_starting, name_ending - name_starting - 1); + value_ending = FindNextRelevant(JSON_TEXT(','), value_t, name_ending); + } + //since the last one will not find the comma, we have to add it here + NewNode(parent, name, value_t.substr(name_ending + 1, len - name_ending - 2), false); +} diff --git a/src/mir_core/src/json/JSONWorker.h b/src/mir_core/src/json/JSONWorker.h new file mode 100644 index 0000000000..f425e12e86 --- /dev/null +++ b/src/mir_core/src/json/JSONWorker.h @@ -0,0 +1,46 @@ +#ifndef JSON_WORKER_H +#define JSON_WORKER_H + +#include "JSONNode.h" + +class JSONWorker { +public: + static JSONNode parse(const json_string & json); + #ifdef JSON_VALIDATE + static JSONNode validate(const json_string & json); + #endif + #if defined JSON_DEBUG || defined JSON_SAFE + static json_char * RemoveWhiteSpace(const json_string & value_t, json_char & last); + #else + static json_char * RemoveWhiteSpace(const json_string & value_t); + #endif + static json_string RemoveWhiteSpaceAndComments(const json_string & value_t); + + static void DoArray(const internalJSONNode * parent, const json_string & value_t); + static void DoNode(const internalJSONNode * parent, const json_string & value_t); + + #ifdef JSON_LESS_MEMORY + #define NAME_ENCODED this, true + #define STRING_ENCODED this, false + static json_string FixString(const json_string & value_t, const internalJSONNode * flag, bool which); + #else + #define NAME_ENCODED _name_encoded + #define STRING_ENCODED _string_encoded + static json_string FixString(const json_string & value_t, bool & flag); + #endif + static json_string UnfixString(const json_string & value_t, bool flag); +JSON_PRIVATE + static json_char Hex(const json_char * & pos); + static json_uchar UTF8(const json_char * & pos); + static json_char* UTF8_2(const json_char * & pos); + static json_string toUTF8(json_uchar p); + #ifdef JSON_UNICODE + static json_string UTF(const json_char * & pos); + static json_string toSurrogatePair(json_uchar pos); + #endif + static void SpecialChar(const json_char * & pos, json_string & res); + static size_t FindNextRelevant(json_char ch, const json_string & value_t, const size_t pos); + static void NewNode(const internalJSONNode * parent, const json_string & name, const json_string & value, bool array); +}; + +#endif diff --git a/src/mir_core/src/json/JSONWriter.cpp b/src/mir_core/src/json/JSONWriter.cpp new file mode 100644 index 0000000000..edf407d25d --- /dev/null +++ b/src/mir_core/src/json/JSONWriter.cpp @@ -0,0 +1,174 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" + +#include "JSONNode.h" +#ifdef JSON_WRITER +#include "JSONWorker.h" + +const static json_string WRITER_EMPTY; +#ifndef JSON_NEWLINE + const static json_string NEW_LINE(JSON_TEXT("\n")); +#else + const static json_string NEW_LINE(JSON_TEXT(JSON_NEWLINE)); +#endif + +#ifdef JSON_INDENT + const static json_string INDENT(JSON_TEXT(JSON_INDENT)); + + inline json_string makeIndent(unsigned int amount){ + if (amount == 0xFFFFFFFF) return WRITER_EMPTY; + json_string result; + result.reserve(amount); + for(unsigned int i=0; i < amount; ++i){ + result += INDENT; + } + return result; + } +#else + inline json_string makeIndent(unsigned int amount){ + if (amount == 0xFFFFFFFF) return WRITER_EMPTY; + return json_string(amount, JSON_TEXT('\t')); + } +#endif + +json_string internalJSONNode::WriteName(bool formatted, bool arrayChild) const { + if (arrayChild){ + return WRITER_EMPTY ; + } else { + return JSON_TEXT("\"") + JSONWorker::UnfixString(_name, _name_encoded) + ((formatted) ? JSON_TEXT("\" : ") : JSON_TEXT("\":")); + } +} + +json_string internalJSONNode::WriteChildren(unsigned int indent){ + //Iterate through the children and write them + if (Children.empty()) return WRITER_EMPTY; + + json_string indent_plus_one; + json_string indent_this; + json_string res; + //handle whether or not it's formatted JSON + if (indent != 0xFFFFFFFF){ //it's formatted, make the indentation strings + indent_this = NEW_LINE + makeIndent(indent); + indent_plus_one = NEW_LINE + makeIndent(++indent); + } + //else it's not formatted, leave the indentation strings empty + const size_t size_minus_one = Children.size() - 1; + size_t i=0; + json_foreach(Children, it){ + res += indent_plus_one + (*it) -> internal -> Write(indent, type() == JSON_ARRAY); + if (i < size_minus_one) res += JSON_TEXT(","); //the last one does not get a comma, but all of the others do + ++i; + } + return res + indent_this; +} + +#ifdef JSON_COMMENTS + #ifdef JSON_WRITE_BASH_COMMENTS + const static json_string SINGLELINE(JSON_TEXT("#")); + #else + const static json_string SINGLELINE(JSON_TEXT("//")); + #endif + + json_string internalJSONNode::WriteComment(unsigned int indent) const { + if (indent == 0xFFFFFFFF) return WRITER_EMPTY; + if (_comment.empty()) return WRITER_EMPTY; + size_t pos = _comment.find(JSON_TEXT('\n')); + if (pos == json_string::npos){ //Single line comment + return NEW_LINE + makeIndent(indent) + SINGLELINE + _comment + NEW_LINE + makeIndent(indent); + } + + /* + Multiline comments + */ + #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) + json_string result(NEW_LINE + makeIndent(indent)); + #else + json_string result(NEW_LINE + makeIndent(indent) + JSON_TEXT("/*") + NEW_LINE + makeIndent(indent + 1)); + #endif + size_t old = 0; + while(pos != json_string::npos){ + if (pos && _comment[pos - 1] == JSON_TEXT('\r')) --pos; + #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) + result += SINGLELINE; + #endif + result += _comment.substr(old, pos - old) + NEW_LINE; + #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) + result += makeIndent(indent); + #else + result += makeIndent(indent + 1); + #endif + old = (_comment[pos] == JSON_TEXT('\r')) ? pos + 2 : pos + 1; + pos = _comment.find(JSON_TEXT('\n'), old); + } + #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) + result += SINGLELINE; + #endif + result += _comment.substr(old, pos - old) + NEW_LINE + makeIndent(indent); + #if defined(JSON_WRITE_BASH_COMMENTS) || defined(JSON_WRITE_SINGLE_LINE_COMMENTS) + return result; + #else + return result + JSON_TEXT("*/") + NEW_LINE + makeIndent(indent); + #endif + } +#else + json_string internalJSONNode::WriteComment(unsigned int) const { + return WRITER_EMPTY; + } +#endif + +json_string internalJSONNode::Write(unsigned int indent, bool arrayChild){ + const bool formatted = indent != 0xFFFFFFFF; + + #ifndef JSON_PREPARSE + if (!(formatted || fetched)) { //It's not formatted or fetched, just do a raw dump + return WriteComment(indent) + WriteName(false, arrayChild) + _string; + } + #endif + + //It's either formatted or fetched + switch (type()) { + case JSON_NODE: //got members, write the members + Fetch(); + return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("{") + WriteChildren(indent) + JSON_TEXT("}"); + case JSON_ARRAY: //write out the child nodes int he array + Fetch(); + return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("[") + WriteChildren(indent) + JSON_TEXT("]"); + case JSON_NUMBER: //write out a literal, without quotes + case JSON_NULL: + case JSON_BOOL: + return WriteComment(indent) + WriteName(formatted, arrayChild) + _string; + } + + JSON_ASSERT_SAFE(type() == JSON_STRING, JSON_TEXT("Writing an unknown JSON node type"), return JSON_TEXT("");); + //If it go here, then it's a json_string + #ifndef JSON_PREPARSE + if (fetched) return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("\"") + JSONWorker::UnfixString(_string, _string_encoded) + JSON_TEXT("\""); //It's already been fetched, meaning that it's unescaped + return WriteComment(indent) + WriteName(formatted, arrayChild) + _string; //it hasn't yet been fetched, so it's already unescaped, just do a dump + #else + return WriteComment(indent) + WriteName(formatted, arrayChild) + JSON_TEXT("\"") + JSONWorker::UnfixString(_string, _string_encoded) + JSON_TEXT("\""); + #endif +} +#endif diff --git a/src/mir_core/src/json/NumberToString.h b/src/mir_core/src/json/NumberToString.h new file mode 100644 index 0000000000..a706372f92 --- /dev/null +++ b/src/mir_core/src/json/NumberToString.h @@ -0,0 +1,104 @@ +#ifndef NUMBERTOSTRING_H +#define NUMBERTOSTRING_H + +#include "JSONDebug.h" +#include "JSONMemory.h" +#include + +static unsigned int getlen(unsigned int size){ + switch (size){ + case 1: + return 5; //3 digits for the number, plus null terminator and negation + case 2: + return 7; //5 digits for the number, plus null terminator and negation + case 4: + return 12; //10 digits for the number, plus null terminator and negation + case 8: + return 22; //20 digits for the number, plus null terminator and negation + } + JSON_ASSERT(size == 16, JSON_TEXT("template is not recognized 2^x in size")); + return 41; //39 digits for the number, plus null terminator and negation +} + +class NumberToString { +public: + template + static json_string _itoa(T val, unsigned int size){ + long value = (long)val; + const unsigned int digits = getlen(size); + json_auto result(digits); + result.ptr[digits - 1] = JSON_TEXT('\0'); //null terminator + json_char * runner = &result.ptr[digits - 2]; + bool negative; + + //first thing, check if it's negative, if so, make it positive + if (value < 0){ + value = -value; + negative = true; + } else { + negative = false; + } + + //create the string + do { + *runner--=(json_char)(value % 10) + JSON_TEXT('0'); + } while(value /= 10); + + //if it's negative, add the negation + json_string res; + if (negative){ + *runner = JSON_TEXT('-'); + res = runner; + } else { + res = runner + 1; + } + return res; + } + + #ifndef JSON_LIBRARY + template + static json_string _uitoa(T val, unsigned int size){ + unsigned long value = val; + const unsigned int digits = getlen(size) - 1; //minus one because no '-' char + json_auto result(digits); + result.ptr[digits - 1] = JSON_TEXT('\0'); //null terminator + json_char * runner = &result.ptr[digits - 2]; + + //create the string + do { + *runner--=(json_char)(value % 10) + JSON_TEXT('0'); + } while(value /= 10); + + json_string res = runner + 1; + return res; + } + #endif + + template + static json_string _ftoa(T value){ + json_char result[64]; + #ifdef JSON_UNICODE + mir_snwprintf(result, 63, L"%f", value); + #else + mir_snprintf(result, 63, "%f", value); + #endif + //strip the trailing zeros + for(json_char * pos = &result[0]; *pos; ++pos){ + if (*pos == '.') { //only care about after the decimal + for(json_char * runner = pos + 1; *runner; ++runner){ + if (*runner != JSON_TEXT('0')) pos = runner + 1; + } + *pos = JSON_TEXT('\0'); + break; + } + } + return result; + } + + static inline bool areEqual(const double & one, const double & two){ + const double temp = one - two; + return (temp > 0.0) ? temp < 0.00001 : temp > -0.00001; + } +}; + +#endif diff --git a/src/mir_core/src/json/internalJSONNode.cpp b/src/mir_core/src/json/internalJSONNode.cpp new file mode 100644 index 0000000000..4b33ad9545 --- /dev/null +++ b/src/mir_core/src/json/internalJSONNode.cpp @@ -0,0 +1,568 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" +#include + +#include "internalJSONNode.h" +#include "NumberToString.h" //So that I can convert numbers into strings +#include "JSONNode.h" //To fill in the foreward declaration +#include "JSONWorker.h" //For fetching and parsing and such + +/* + The point of these constants is for faster assigning, if I + were to constantly assign to a string literal, there would be + lots of copies, but since strings are copy on write, this assignment + is much faster +*/ +static const json_string CONST_TRUE(JSON_TEXT("true")); +static const json_string CONST_FALSE(JSON_TEXT("false")); +static const json_string CONST_NULL(JSON_TEXT("null")); + +#ifdef JSON_UNIT_TEST + void internalJSONNode::incinternalAllocCount(void){ JSONNode::incinternalAllocCount(); } + void internalJSONNode::decinternalAllocCount(void){ JSONNode::decinternalAllocCount(); } +#endif + +internalJSONNode::internalJSONNode(const internalJSONNode & orig) : + _type(orig._type), _name(orig._name), _name_encoded(orig._name_encoded), Children(), + _string(orig._string), _string_encoded(orig._string_encoded), _value(orig._value) + initializeRefCount(1) + initializeFetch(orig.fetched) + initializeMutex(0) + initializeComment(orig._comment) + initializeValid(orig.isValid){ + + incinternalAllocCount(); + #ifdef JSON_MUTEX_CALLBACKS + _set_mutex(orig.mylock, false); + #endif + if (!orig.Children.empty()) { + Children.reserve(orig.Children.size()); + json_foreach(orig.Children, myrunner){ + Children.push_back(JSONNode::newJSONNode((*myrunner) -> duplicate())); + } + } +} + +#ifdef JSON_PREPARSE + #define SetFetchedFalseOrDo(code) code +#else + #define SetFetchedFalseOrDo(code) SetFetched(false) +#endif + +#ifdef JSON_VALIDATE + #define NOTVALID false +#else + #define NOTVALID +#endif + +//this one is specialized because the root can only be array or node +internalJSONNode::internalJSONNode(const json_string & unparsed) : _type(), _name(),_name_encoded(false), _string(unparsed), _string_encoded(), _value(), Children() + initializeMutex(0) + initializeRefCount(1) + initializeFetch(false) + initializeComment(0) + initializeValid(0){ + + incinternalAllocCount(); + switch (unparsed[0]) { + case JSON_TEXT('{'): //node + _type = JSON_NODE; + #ifdef JSON_PREPARSE + FetchNode(); + #endif + break; + case JSON_TEXT('['): //array + _type = JSON_ARRAY; + #ifdef JSON_PREPARSE + FetchArray(); + #endif + break; + default: + JSON_FAIL_SAFE(JSON_TEXT("root not starting with either { or ["), Nullify(NOTVALID);); + break; + } +} + +internalJSONNode::internalJSONNode(const json_string & name_t, const json_string & value_t) : _type(), _name_encoded(), _name(JSONWorker::FixString(name_t, NAME_ENCODED)), _string(), _string_encoded(), _value(), Children() + initializeMutex(0) + initializeRefCount(1) + initializeFetch(0) + initializeComment(0) + initializeValid(0){ + + incinternalAllocCount(); + + if (value_t.empty()) { + _type = JSON_NULL; + #ifdef JSON_VALIDATE + isValid = true; + #endif + SetFetched(true); + return; + } + + _string = value_t; + const json_char firstchar = value_t[0]; + #if defined JSON_DEBUG || defined JSON_SAFE + const json_char lastchar = value_t[value_t.length() - 1]; + #endif + + switch (firstchar){ + case JSON_TEXT('\"'): //a json_string literal, still escaped and with leading and trailing quotes + JSON_ASSERT_SAFE(lastchar == JSON_TEXT('\"'), JSON_TEXT("Unterminated quote"), Nullify(NOTVALID); return;); + _type = JSON_STRING; + SetFetchedFalseOrDo(FetchString()); + break; + case JSON_TEXT('{'): //a child node, or set of children + JSON_ASSERT_SAFE(lastchar == JSON_TEXT('}'), JSON_TEXT("Missing }"), Nullify(NOTVALID); return;); + _type = JSON_NODE; + SetFetchedFalseOrDo(FetchNode()); + break; + case JSON_TEXT('['): //an array + JSON_ASSERT_SAFE(lastchar == JSON_TEXT(']'), JSON_TEXT("Missing ]"), Nullify(NOTVALID); return;); + _type = JSON_ARRAY; + SetFetchedFalseOrDo(FetchArray()); + break; + case JSON_TEXT('t'): + JSON_ASSERT_SAFE(value_t == JSON_TEXT("true"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); + _value._bool = true; + _type = JSON_BOOL; + SetFetched(true); + break; + case JSON_TEXT('f'): + JSON_ASSERT_SAFE(value_t == JSON_TEXT("false"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); + _value._bool = false; + _type = JSON_BOOL; + SetFetched(true); + break; + case JSON_TEXT('n'): + JSON_ASSERT_SAFE(value_t == JSON_TEXT("null"), json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); + _type = JSON_NULL; + SetFetched(true); + #ifdef JSON_VALIDATE + isValid = true; + #endif + break; + default: + JSON_ASSERT_SAFE(value_t.find_first_not_of(JSON_TEXT("0123456789.e+-")) == json_string::npos, json_string(json_string(JSON_TEXT("unknown JSON literal: ")) + value_t).c_str(), Nullify(NOTVALID); return;); + _type = JSON_NUMBER; + SetFetchedFalseOrDo(FetchNumber()); + break; + } +} + +internalJSONNode::~internalJSONNode(void){ + decinternalAllocCount(); + #ifdef JSON_MUTEX_CALLBACKS + _unset_mutex(); + #endif + //DO NOT delete the children! It automatically gets removed +} + +void internalJSONNode::FetchString(void) const { + JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON json_string type is empty?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't start with a quotation?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('\"'), JSON_TEXT("JSON json_string type doesn't end with a quotation?"), Nullify(NOTVALID); return;); + _string = JSONWorker::FixString(_string.substr(1, _string.length() - 2), STRING_ENCODED); +} + +void internalJSONNode::FetchNode(void) const { + JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('{'), JSON_TEXT("JSON node type doesn't start with a bracket?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT('}'), JSON_TEXT("JSON node type doesn't end with a bracket?"), Nullify(NOTVALID); return;); + JSONWorker::DoNode(this, _string); + clearString(_string); +} + +void internalJSONNode::FetchArray(void) const { + JSON_ASSERT_SAFE(!_string.empty(), JSON_TEXT("JSON node type is empty?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[0] == JSON_TEXT('['), JSON_TEXT("JSON node type doesn't start with a square bracket?"), Nullify(NOTVALID); return;); + JSON_ASSERT_SAFE(_string[_string.length() - 1] == JSON_TEXT(']'), JSON_TEXT("JSON node type doesn't end with a square bracket?"), Nullify(NOTVALID); return;); + JSONWorker::DoArray(this, _string); + clearString(_string); +} + +void internalJSONNode::FetchNumber(void) const { + #ifdef JSON_UNICODE + { + const size_t len = _string.length(); + json_auto temp(len + 1); + wcstombs(temp.ptr, _string.c_str(), len); + temp.ptr[len] = '\0'; + _value._number = (json_number)atof(temp.ptr); + } + #else + _value._number = (json_number)atof(_string.c_str()); + #endif +} + +#ifndef JSON_PREPARSE + void internalJSONNode::Fetch(void) const { + if (fetched) return; + switch (type()) { + case JSON_STRING: + FetchString(); + break; + case JSON_NODE: + FetchNode(); + break; + case JSON_ARRAY: + FetchArray(); + break; + case JSON_NUMBER: + FetchNumber(); + break; + #if defined JSON_DEBUG || defined JSON_SAFE + default: + JSON_FAIL(JSON_TEXT("Fetching an unknown type")); + Nullify(NOTVALID); + #endif + } + fetched = true; + } +#endif + +void internalJSONNode::Set(const json_string & val){ + _type = JSON_STRING; + _string = val; + _string_encoded = true; + SetFetched(true); +} + +#ifdef JSON_LIBRARY + void internalJSONNode::Set(long val){ + _type = JSON_NUMBER; + _value._number = (json_number)val; + _string = NumberToString::_itoa(val, sizeof(long)); + SetFetched(true); + } + + void internalJSONNode::Set(json_number val){ + _type = JSON_NUMBER; + _value._number = val; + _string = NumberToString::_ftoa(val); + SetFetched(true); + } +#else + #define SET(converter, type)\ + void internalJSONNode::Set(type val){\ + _type = JSON_NUMBER;\ + _value._number = (json_number)val;\ + _string = NumberToString::converter(val, sizeof(type));\ + SetFetched(true);\ + } + #define SET_INTEGER(type) SET(_itoa, type) SET(_uitoa, unsigned type) + #define SET_FLOAT(type) \ + void internalJSONNode::Set(type val){\ + _type = JSON_NUMBER;\ + _value._number = (json_number)val;\ + _string = NumberToString::_ftoa(val);\ + SetFetched(true);\ + } + + SET_INTEGER(char) + SET_INTEGER(short) + SET_INTEGER(int) + SET_INTEGER(long) + #ifndef JSON_ISO_STRICT + SET_INTEGER(long long) + #endif + + SET_FLOAT(float) + SET_FLOAT(double) +#endif + +void internalJSONNode::Set(bool val){ + _type = JSON_BOOL; + _value._bool = val; + _string = val ? CONST_TRUE : CONST_FALSE; + SetFetched(true); +} + +bool internalJSONNode::IsEqualTo(const internalJSONNode * val) const { + #ifdef JSON_REF_COUNT + if (this == val) return true; //reference counting the same internal object, so they must be equal + #endif + if (type() != val -> type()) return false; //aren't even same type + if (_name != val -> _name) return false; //names aren't the same + if (type() == JSON_NULL) return true; //both null, can't be different + #ifndef JSON_PREPARSE + Fetch(); + val -> Fetch(); + #endif + switch (type()) { + case JSON_STRING: + return val -> _string == _string; + case JSON_NUMBER: + return NumberToString::areEqual(val -> _value._number, _value._number); + case JSON_BOOL: + return val -> _value._bool == _value._bool; + }; + + JSON_ASSERT(type() == JSON_NODE || type() == JSON_ARRAY, JSON_TEXT("Checking for equality, not sure what type")); + if (Children.size() != val -> Children.size()) return false; //if they arne't he same size then they certainly aren't equal + + //make sure each children is the same + JSONNode ** valrunner = val -> Children.begin(); + json_foreach(Children, myrunner){ + JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); + JSON_ASSERT(*valrunner, JSON_TEXT("a null pointer within the children")); + JSON_ASSERT(valrunner != val -> Children.end(), JSON_TEXT("at the end of other one's children, but they're the same size?")); + if (**myrunner != **valrunner) return false; + ++valrunner; + } + return true; +} + +#ifdef JSON_VALIDATE +void internalJSONNode::Nullify(bool validation) const { + isValid = validation; +#else +void internalJSONNode::Nullify(void) const { +#endif + _type = JSON_NULL; + _string = CONST_NULL; + SetFetched(true); +} + +#ifdef JSON_MUTEX_CALLBACKS + #define JSON_MUTEX_COPY ,mylock +#else + #define JSON_MUTEX_COPY +#endif + +#ifdef JSON_LIBRARY +void internalJSONNode::push_back(JSONNode *node){ +#else +void internalJSONNode::push_back(const JSONNode & node){ +#endif + JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing back to something that is not an array or object")); + #ifdef JSON_LIBRARY + #ifdef JSON_MUTEX_CALLBACKS + if (mylock) node -> set_mutex(mylock); + #endif + Children.push_back(node); + #else + Children.push_back(JSONNode::newJSONNode(node JSON_MUTEX_COPY)); + #endif +} + +void internalJSONNode::push_front(const JSONNode & node){ + JSON_ASSERT(type() == JSON_ARRAY || type() == JSON_NODE, JSON_TEXT("pushing front to something that is not an array or object")); + Children.push_front(JSONNode::newJSONNode(node JSON_MUTEX_COPY)); +} + +JSONNode * internalJSONNode::pop_back(json_index_t pos){ + JSONNode * result = Children[pos]; + JSONNode ** temp = Children.begin() + pos; + Children.erase(temp); + return result; +} + +JSONNode * internalJSONNode::pop_back(const json_string & name_t){ + if (JSONNode ** res = at(name_t)) { + JSONNode * result = *res; + Children.erase(res); + return result; + } + return 0; +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode * internalJSONNode::pop_back_nocase(const json_string & name_t){ + if (JSONNode ** res = at_nocase(name_t)) { + JSONNode * result = *res; + Children.erase(res); + return result; + } + return 0; + } +#endif + +JSONNode ** internalJSONNode::at(const json_string & name_t){ + Fetch(); + json_foreach(Children, myrunner){ + JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); + if ((*myrunner) -> name() == name_t) return myrunner; + } + return 0; +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + bool internalJSONNode::AreEqualNoCase(const json_char * ch_one, const json_char * ch_two){ + while (*ch_one){ //only need to check one, if the other one terminates early, the check will cause it to fail + const json_char c_one = *ch_one; + const json_char c_two = *ch_two; + if (c_one != c_two){ + if ((c_two > 64) && (c_two < 91)) { //A - Z + if (c_one != (json_char)(c_two + 32)) return false; + } else if ((c_two > 96) && (c_two < 123)) { //a - z + if (c_one != (json_char)(c_two - 32)) return false; + } else { //not a letter, so return false + return false; + } + } + ++ch_one; + ++ch_two; + + } + return *ch_two == '\0'; //this one has to be null terminated too, or else json_string two is longer, hence, not equal + } + + JSONNode ** internalJSONNode::at_nocase(const json_string & name_t){ + Fetch(); + json_foreach(Children, myrunner){ + JSON_ASSERT(*myrunner, JSON_TEXT("a null pointer within the children")); + if (AreEqualNoCase((*myrunner) -> name().c_str(), name_t.c_str())) return myrunner; + } + return 0; + } +#endif + +#ifndef JSON_PREPARSE + void internalJSONNode::preparse(void){ + Fetch(); + json_foreach(Children, myrunner){ + (*myrunner) -> preparse(); + } + } +#endif + +#ifdef JSON_VALIDATE + bool internalJSONNode::validate(void){ + json_foreach(Children, myrunner){ + if ((*myrunner) -> type() != JSON_NULL){ + #ifndef JSON_PREPARSE + (*myrunner) -> internal -> Fetch(); + #endif + if ((*myrunner) -> type() == JSON_NULL) return false; + } else if (!((*myrunner) -> internal -> isValid)) { + JSON_FAIL(_name + JSON_TEXT(" is null and not valid")); + return false; + } + } + json_foreach(Children, runner){ + if (!((*runner) -> internal -> validate())) return false; + } + return true; + } +#endif + +#ifdef JSON_DEBUG + #ifndef JSON_LIBRARY + JSONNode internalJSONNode::Dump(size_t & totalbytes) const { + JSONNode dumpage(JSON_NODE); + dumpage.set_name(JSON_TEXT("internalJSONNode")); + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("this"), (long)this))); + + size_t memory = sizeof(internalJSONNode); + memory += _name.capacity() * sizeof(json_char); + memory += _string.capacity() * sizeof(json_char); + memory += Children.capacity() * sizeof(JSONNode*); + #ifdef JSON_COMMENTS + memory += _comment.capacity() * sizeof(json_char); + #endif + totalbytes += memory; + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("bytes used"), memory))); + + #ifdef JSON_REF_COUNT + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("refcount"), refcount))); + #endif + #ifdef JSON_MUTEX_CALLBACKS + dumpage.push_back(JSON_NEW(DumpMutex())); + #endif + + #define DUMPCASE(ty)\ + case ty:\ + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT(#ty))));\ + break; + + switch(type()) { + DUMPCASE(JSON_NULL) + DUMPCASE(JSON_STRING) + DUMPCASE(JSON_NUMBER) + DUMPCASE(JSON_BOOL) + DUMPCASE(JSON_ARRAY) + DUMPCASE(JSON_NODE) + default: + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_type"), JSON_TEXT("Unknown")))); + } + + JSONNode str(JSON_NODE); + str.set_name(JSON_TEXT("_name")); + str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _name))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _name.length()))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _name.capacity()))); + + #ifdef JSON_LESS_MEMORY + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _type & 0x10))); + #else + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_name_encoded"), _name_encoded))); + #endif + dumpage.push_back(JSON_NEW(str)); + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("_string_encoded"), _string_encoded))); + str.clear(); + str.set_name(JSON_TEXT("_string")); + str.push_back(JSON_NEW(JSONNode(json_string(JSON_TEXT("value")), _string))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _string.length()))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _string.capacity()))); + dumpage.push_back(JSON_NEW(str)); + + JSONNode unio(JSON_NODE); + unio.set_name(JSON_TEXT("_value")); + unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_bool"), _value._bool))); + unio.push_back(JSON_NEW(JSONNode(JSON_TEXT("_number"), _value._number))); + dumpage.push_back(JSON_NEW(unio)); + + #ifndef JSON_PREPARSE + dumpage.push_back(JSON_NEW(JSONNode(JSON_TEXT("fetched"), fetched))); + #endif + + #ifdef JSON_COMMENTS + str.clear(); + str.set_name(JSON_TEXT("_comment")); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("value"), _comment))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("length"), _comment.length()))); + str.push_back(JSON_NEW(JSONNode(JSON_TEXT("capactiy"), _comment.capacity()))); + dumpage.push_back(JSON_NEW(str)); + #endif + + JSONNode arra(JSON_NODE); + arra.set_name(JSON_TEXT("Children")); + arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("size"), Children.size()))); + arra.push_back(JSON_NEW(JSONNode(JSON_TEXT("capacity"), Children.capacity()))); + JSONNode chil(JSON_ARRAY); + chil.set_name(JSON_TEXT("array")); + json_foreach(Children, it){ + chil.push_back(JSON_NEW((*it) -> dump(totalbytes))); + } + arra.push_back(JSON_NEW(chil)); + dumpage.push_back(JSON_NEW(arra)); + + return dumpage; + } + #endif +#endif diff --git a/src/mir_core/src/json/internalJSONNode.h b/src/mir_core/src/json/internalJSONNode.h new file mode 100644 index 0000000000..cf626ceae0 --- /dev/null +++ b/src/mir_core/src/json/internalJSONNode.h @@ -0,0 +1,452 @@ +#ifndef INTERNAL_JSONNODE_H +#define INTERNAL_JSONNODE_H + +#include "JSONDebug.h" +#include "JSONChildren.h" +#include "JSONMemory.h" +#ifdef JSON_DEBUG + #include //to check int value +#endif + +/* + This class is the work horse of libJSON, it handles all of the + functinality of JSONNode. This object is reference counted for + speed and memory reasons. + + If JSON_REF_COUNT is not on, this internal structure still has an important + purpose, as it can be passed around by JSONNoders that are flagged as temporary +*/ + +class JSONNode; //forward declaration + +#ifndef JSON_LIBRARY + #define DECL_SET_INTEGER(type) void Set(type); void Set(unsigned type); +#endif + +#ifdef JSON_MUTEX_CALLBACKS + #define initializeMutex(x) ,mylock(x) +#else + #define initializeMutex(x) +#endif + +#ifdef JSON_PREPARSE + #define SetFetched(b) (void)0 + #define Fetch() (void)0 +#define initializeFetch(x) +#else + #define initializeFetch(x) ,fetched(x) +#endif + +#ifdef JSON_REF_COUNT + #define initializeRefCount(x) ,refcount(x) +#else + #define initializeRefCount(x) +#endif + +#ifdef JSON_COMMENTS + #define initializeComment(x) ,_comment(x) +#else + #define initializeComment(x) +#endif + +#ifndef JSON_UNIT_TEST + #define incAllocCount() (void)0 + #define decAllocCount() (void)0 + #define incinternalAllocCount() (void)0 + #define decinternalAllocCount() (void)0 +#endif + +#ifdef JSON_VALIDATE + #define initializeValid(x) ,isValid(x) +#else + #define initializeValid(x) +#endif + +class internalJSONNode { +public: + internalJSONNode(char mytype = JSON_NULL); + internalJSONNode(const json_string & unparsed); + internalJSONNode(const json_string & name_t, const json_string & value_t); + internalJSONNode(const internalJSONNode & orig); + internalJSONNode & operator = (const internalJSONNode &); + ~internalJSONNode(void); + + static internalJSONNode * newInternal(char mytype = JSON_NULL); + static internalJSONNode * newInternal(const json_string & unparsed); + static internalJSONNode * newInternal(const json_string & name_t, const json_string & value_t); + static internalJSONNode * newInternal(const internalJSONNode & orig); //not copyable, only by this class + static void deleteInternal(internalJSONNode * ptr); + + json_index_t size(void) const; + bool empty(void) const; + unsigned char type(void) const; + + const json_char* name(void) const; + void setname(const json_string & newname); + #ifdef JSON_COMMENTS + void setcomment(const json_string & comment); + json_string getcomment(void) const; + #endif + json_string as_string(void) const; + long as_int(void) const; + json_number as_float(void) const; + bool as_bool(void) const; + + #ifndef JSON_PREPARSE + void preparse(void); + #endif + + #ifdef JSON_LIBRARY + void push_back(JSONNode *node); + #else + void push_back(const JSONNode & node); + #endif + void reserve(json_index_t size); + void push_front(const JSONNode & node); + JSONNode * pop_back(json_index_t pos); + JSONNode * pop_back(const json_string & name_t); + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode * pop_back_nocase(const json_string & name_t); + #endif + + JSONNode * at(json_index_t pos); + //These return ** because pop_back needs them + JSONNode ** at(const json_string & name_t); + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + JSONNode ** at_nocase(const json_string & name_t); + #endif + + void Set(const json_string & val); + #ifdef JSON_LIBRARY + void Set(json_number val); + void Set(long val); + #else + DECL_SET_INTEGER(char) + DECL_SET_INTEGER(short) + DECL_SET_INTEGER(int) + DECL_SET_INTEGER(long) + #ifndef JSON_ISO_STRICT + DECL_SET_INTEGER(long long) + #endif + + void Set(float val); + void Set(double val); + #endif + void Set(bool val); + + bool IsEqualTo(const json_string & val)const ; + bool IsEqualTo(bool val) const; + bool IsEqualTo(const internalJSONNode * val) const; + + template + bool IsEqualToNum(T val) const; + + internalJSONNode * incRef(void); + #ifdef JSON_REF_COUNT + void decRef(void); + bool hasNoReferences(void); + #endif + internalJSONNode * makeUnique(void); + + JSONNode ** begin(void) const; + JSONNode ** end(void) const; + #ifdef JSON_REF_COUNT + size_t refcount BITS(20); + #endif + bool Fetched(void) const; + #ifdef JSON_MUTEX_CALLBACKS + void * mylock; + void _set_mutex(void * mutex, bool unset = true); + void _unset_mutex(void); + #endif + #ifdef JSON_UNIT_TEST + static void incinternalAllocCount(void); + static void decinternalAllocCount(void); + #endif + + #ifdef JSON_WRITER + json_string WriteName(bool formatted, bool arrayChild) const; + json_string WriteChildren(unsigned int indent); + json_string WriteComment(unsigned int indent) const; + json_string Write(unsigned int indent, bool arrayChild); + #endif + #ifdef JSON_DEBUG + #ifndef JSON_LIBRARY + JSONNode Dump(size_t & totalmemory) const; + JSONNode DumpMutex(void) const; + #endif + #endif + + //json parts + mutable unsigned char _type BITS(3); + mutable bool _name_encoded BITS(1); //must be above name due to initialization list order + json_string _name; + + mutable json_string _string; //these are both mutable because the string can change when it's fetched + mutable bool _string_encoded BITS(1); + + //the value of the json + union value_union_t { + bool _bool; + json_number _number; + }; + mutable value_union_t _value; //internal structure changes depending on type + + jsonChildren Children; //container that holds all of my children + + #ifdef JSON_VALIDATE + mutable bool isValid BITS(1); //this does not need to be initialized, it's only used if it's null + void Nullify(bool validation = true) const; + bool validate(void); + #else + void Nullify(void) const; + #endif + + //Fetching and such + #ifndef JSON_PREPARSE + mutable bool fetched BITS(1); + void SetFetched(bool val) const; + void Fetch(void) const; //it's const because it doesn't change the VALUE of the function + #endif + + #ifdef JSON_COMMENTS + json_string _comment; + #endif + + void FetchString(void) const; + void FetchNode(void) const; + void FetchArray(void) const; + void FetchNumber(void) const; + #ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + static bool AreEqualNoCase(const json_char * ch_one, const json_char * ch_two); + #endif +}; + +inline internalJSONNode::internalJSONNode(char mytype) : _type(mytype), Children(), _name(), _name_encoded(), _string(), _string_encoded(), _value() + initializeMutex(0) + initializeRefCount(1) + initializeFetch(true) + initializeComment(0) + initializeValid(true){ + + incinternalAllocCount(); +} + +inline internalJSONNode * internalJSONNode::incRef(void){ + #ifdef JSON_REF_COUNT + ++refcount; + return this; + #else + return makeUnique(); + #endif +} + +inline json_index_t internalJSONNode::size(void) const { + Fetch(); + return Children.size(); +} + +inline bool internalJSONNode::empty(void) const { + if (type() != JSON_NODE && type() != JSON_ARRAY) return true; + Fetch(); + return Children.empty(); +} + +inline unsigned char internalJSONNode::type(void) const { + #ifdef JSON_LESS_MEMORY + return _type & 0xF; + #else + return _type; + #endif +} + +inline const json_char* internalJSONNode::name(void) const { + return _name.c_str(); +} + +inline void internalJSONNode::setname(const json_string & newname){ + _name = newname; + #ifdef JSON_LESS_MEMORY + _type |= 0x10; + #else + _name_encoded = true; + #endif +} + +#ifdef JSON_COMMENTS + inline void internalJSONNode::setcomment(const json_string & comment){ + _comment = comment; + } + + inline json_string internalJSONNode::getcomment(void) const { + return _comment; + } +#endif + +inline json_string internalJSONNode::as_string(void) const { + Fetch(); + return _string; +} + +inline long internalJSONNode::as_int(void) const { + Fetch(); + switch(type()) { + case JSON_NULL: + return 0; + case JSON_BOOL: + return _value._bool ? 1 : 0; + } + JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_int returning undefined results")); + JSON_ASSERT(_value._number > LONG_MIN, _string + JSON_TEXT(" is outside the lower range of long")); + JSON_ASSERT(_value._number < LONG_MAX, _string + JSON_TEXT(" is outside the upper range of long")); + JSON_ASSERT(_value._number == (json_number)((int)_value._number), json_string(JSON_TEXT("as_int will truncate ")) + _string); + return (int)_value._number; +} + +inline json_number internalJSONNode::as_float(void) const { + Fetch(); + switch(type()) { + case JSON_NULL: + return (json_number)0.0; + case JSON_BOOL: + return (json_number)(_value._bool ? 1.0 : 0.0); + } + JSON_ASSERT(type() == JSON_NUMBER, JSON_TEXT("as_float returning undefined results")); + return _value._number; +} + +inline bool internalJSONNode::as_bool(void) const { + Fetch(); + switch(type()) { + case JSON_NUMBER: + return _value._number != 0.0f; + case JSON_NULL: + return false; + } + JSON_ASSERT(type() == JSON_BOOL, JSON_TEXT("as_bool returning undefined results")); + return _value._bool; +} + +inline bool internalJSONNode::IsEqualTo(const json_string & val) const { + if (type() != JSON_STRING) return false; + Fetch(); + return val == _string; +} + +inline bool internalJSONNode::IsEqualTo(bool val) const { + if (type() != JSON_BOOL) return false; + Fetch(); + return val == _value._bool; +} + +template +inline bool internalJSONNode::IsEqualToNum(T val) const { + if (type() != JSON_NUMBER) return false; + Fetch(); + return (json_number)val == _value._number; +} + +#ifdef JSON_REF_COUNT + inline void internalJSONNode::decRef(void){ + JSON_ASSERT(refcount != 0, JSON_TEXT("decRef on a 0 refcount internal")); + --refcount; + } + + inline bool internalJSONNode::hasNoReferences(void){ + return refcount == 0; + } +#endif + +inline internalJSONNode * internalJSONNode::makeUnique(void){ + #ifdef JSON_REF_COUNT + if (refcount > 1){ + decRef(); + return newInternal(*this); + } + JSON_ASSERT(refcount == 1, JSON_TEXT("makeUnique on a 0 refcount internal")); + return this; + #else + return newInternal(*this); + #endif +} + +#ifndef JSON_PREPARSE + inline void internalJSONNode::SetFetched(bool val) const { + fetched = val; + } +#endif + +inline bool internalJSONNode::Fetched(void) const { + #ifndef JSON_PREPARSE + return fetched; + #else + return true; + #endif +} + +inline JSONNode ** internalJSONNode::begin(void) const { + Fetch(); + return Children.begin(); +} + +inline JSONNode ** internalJSONNode::end(void) const { + Fetch(); + return Children.end(); +} + +inline JSONNode * internalJSONNode::at(json_index_t pos){ + Fetch(); + return Children[pos]; +} + +inline void internalJSONNode::reserve(json_index_t size){ + Fetch(); + Children.reserve2(size); +} + +/* + These functions are to allow allocation to be completely controlled by the callbacks +*/ + +inline void internalJSONNode::deleteInternal(internalJSONNode * ptr){ + #ifdef JSON_MEMORY_CALLBACKS + ptr -> ~internalJSONNode(); + libjson_free(ptr); + #else + delete ptr; + #endif +} + +inline internalJSONNode * internalJSONNode::newInternal(char mytype){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) internalJSONNode(mytype); + #else + return new internalJSONNode(mytype); + #endif +} + +inline internalJSONNode * internalJSONNode::newInternal(const json_string & unparsed){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) internalJSONNode(unparsed); + #else + return new internalJSONNode(unparsed); + #endif +} + +inline internalJSONNode * internalJSONNode::newInternal(const json_string & name_t, const json_string & value_t){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) internalJSONNode(name_t, value_t); + #else + return new internalJSONNode(name_t, value_t); + #endif +} + +inline internalJSONNode * internalJSONNode::newInternal(const internalJSONNode & orig){ + #ifdef JSON_MEMORY_CALLBACKS + return new(json_malloc(1)) internalJSONNode(orig); + #else + return new internalJSONNode(orig); + #endif +} + +#endif diff --git a/src/mir_core/src/json/libJSON.cpp b/src/mir_core/src/json/libJSON.cpp new file mode 100644 index 0000000000..d55505c4eb --- /dev/null +++ b/src/mir_core/src/json/libJSON.cpp @@ -0,0 +1,457 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "..\commonheaders.h" + +#include + +/* + This is the implementation of the C interface to libJSON + This file may be included in any C++ application, but it will + be completely ignored if JSON_LIBRARY isn't defined. The + only reason JSON_LIBRARY should be defined is when compiling libJSON + as a library +*/ + +#include "JSONNode.h" +#include "JSONWorker.h" +#include //some methods throw exceptions +#ifdef JSON_MEMORY_MANAGE + auto_expand StringHandler; + auto_expand_node NodeHandler; + #define MANAGER_INSERT(x) NodeHandler.insert(x) +#else + #define MANAGER_INSERT(x) x +#endif + +#ifdef JSON_SAFE + static const json_char * EMPTY_CSTRING = JSON_TEXT(""); +#endif + +inline TCHAR* toCString(const json_string & str) +{ + return mir_utf8decodeT( str.c_str()); +} + +/* + stuff that's in namespace libJSON +*/ + +MIR_CORE_DLL(void) json_free(void *str){ + JSON_ASSERT_SAFE(str, JSON_TEXT("freeing null ptr"), return;); + #ifdef JSON_MEMORY_MANAGE + StringHandler.remove(str); + #endif + libjson_free(str); +} + +MIR_CORE_DLL(void) json_delete(JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("deleting null ptr"), return;); + #ifdef JSON_MEMORY_MANAGE + NodeHandler.remove(node); + #endif + JSONNode::deleteJSONNode((JSONNode *)node); +} + +#ifdef JSON_MEMORY_MANAGE + MIR_CORE_DLL(void) json_free_all(void){ + StringHandler.clear(); + } + + MIR_CORE_DLL(void) json_delete_all(void){ + NodeHandler.clear(); + } +#endif + +MIR_CORE_DLL(JSONNODE*) json_parse(const json_char *json){ + JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_parse"), return 0;); + try { + //use this constructor to simply copy reference instead of copying the temp + return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(JSONWorker::parse(json))); + } catch (std::invalid_argument){} + return 0; +} + +MIR_CORE_DLL(TCHAR*) json_strip_white_space(const json_char *json){ + JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_strip_white_space"), return 0;); + return toCString(JSONWorker::RemoveWhiteSpaceAndComments(json)); +} + +#ifdef JSON_VALIDATE + MIR_CORE_DLL(JSONNODE*) json_validate(const json_char *json){ + JSON_ASSERT_SAFE(json, JSON_TEXT("null ptr to json_validate"), return 0;); + try { + //use this constructor to simply copy reference instead of copying the temp + return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(JSONWorker::validate(json))); + } catch (std::invalid_argument){} + return 0; + } +#endif + +#if defined JSON_DEBUG && !defined JSON_STDERROR + //When libjson errors, a callback allows the user to know what went wrong + MIR_CORE_DLL(void) json_register_debug_callback(json_error_callback_t callback){ + JSONDebug::register_callback(callback); + } +#endif + +#ifdef JSON_MUTEX_CALLBACKS + #ifdef JSON_MUTEX_MANAGE + MIR_CORE_DLL(void) json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, json_mutex_callback_t destroy, void * manager_lock){ + JSONNode::register_mutex_callbacks(lock, unlock, manager_lock); + JSONNode::register_mutex_destructor(destroy); + } + + #else + MIR_CORE_DLL(void) json_register_mutex_callbacks(json_mutex_callback_t lock, json_mutex_callback_t unlock, void * manager_lock){ + JSONNode::register_mutex_callbacks(lock, unlock, manager_lock); + } + #endif + + MIR_CORE_DLL(void) json_set_global_mutex(void * mutex){ + JSONNode::set_global_mutex(mutex); + } + + MIR_CORE_DLL(void) json_set_mutex(JSONNODE *node, void * mutex){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_mutex"), return;); + ((JSONNode*)node) -> set_mutex(mutex); + } + + MIR_CORE_DLL(void) json_lock(JSONNODE *node, int threadid){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_lock"), return;); + ((JSONNode*)node) -> lock(threadid); + } + + MIR_CORE_DLL(void) json_unlock(JSONNODE *node, int threadid){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_unlock"), return;); + ((JSONNode*)node) -> unlock(threadid); + } +#endif + +/* +stuff that's in class JSONNode +*/ +//ctors +MIR_CORE_DLL(JSONNODE*) json_new_a(const json_char *name, const json_char *value){ + JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_a"), name = EMPTY_CSTRING;); + JSON_ASSERT_SAFE(value, JSON_TEXT("null value to json_new_a"), value = EMPTY_CSTRING;); + #ifdef JSON_MEMORY_CALLBACKS + return MANAGER_INSERT(new(json_malloc(1)) JSONNode(name, json_string(value))); + #else + return MANAGER_INSERT(new JSONNode(name, json_string(value))); + #endif +} + +MIR_CORE_DLL(JSONNODE*) json_new_i(const json_char *name, long value){ + JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_i"), name = EMPTY_CSTRING;); + #ifdef JSON_MEMORY_CALLBACKS + return MANAGER_INSERT(new(json_malloc(1)) JSONNode(name, value)); + #else + return MANAGER_INSERT(new JSONNode(name, value)); + #endif +} + +MIR_CORE_DLL(JSONNODE*) json_new_f(const json_char *name, double value){ + JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_f"), name = EMPTY_CSTRING;); + #ifdef JSON_MEMORY_CALLBACKS + return MANAGER_INSERT(new(json_malloc(1)) JSONNode(name, value)); + #else + return MANAGER_INSERT(new JSONNode(name, value)); + #endif +} + +MIR_CORE_DLL(JSONNODE*) json_new_b(const json_char *name, int value){ + JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_new_b"), name = EMPTY_CSTRING;); + #ifdef JSON_MEMORY_CALLBACKS + return MANAGER_INSERT(new(json_malloc(1)) JSONNode(name, value != 0 )); + #else + return MANAGER_INSERT(new JSONNode(name, value != 0)); + #endif +} + +MIR_CORE_DLL(JSONNODE*) json_new(char type){ + #ifdef JSON_MEMORY_CALLBACKS + return MANAGER_INSERT(new(json_malloc(1)) JSONNode(type)); + #else + return MANAGER_INSERT(new JSONNode(type)); + #endif +} + +MIR_CORE_DLL(JSONNODE*) json_copy(const JSONNODE *orig){ + JSON_ASSERT_SAFE(orig, JSON_TEXT("null orig to json_copy"), return 0;); + #ifdef JSON_MEMORY_CALLBACKS + return MANAGER_INSERT(new(json_malloc(1)) JSONNode(*((JSONNode*)orig))); + #else + return MANAGER_INSERT(new JSONNode(*((JSONNode*)orig))); + #endif +} + +MIR_CORE_DLL(JSONNODE*) json_duplicate(const JSONNODE *orig){ + JSON_ASSERT_SAFE(orig, JSON_TEXT("null orig to json_duplicate"), return 0;); + return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(((JSONNode*)orig) -> duplicate())); +} + +//assignment +MIR_CORE_DLL(void) json_set_a(JSONNODE *node, const json_char *value){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_a"), return;); + JSON_ASSERT_SAFE(value, JSON_TEXT("null value to json_set_a"), value = EMPTY_CSTRING;); + *((JSONNode*)node) = json_string(value); +} + +MIR_CORE_DLL(void) json_set_i(JSONNODE *node, long value){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_i"), return;); + *((JSONNode*)node) = value; +} + +MIR_CORE_DLL(void) json_set_f(JSONNODE *node, double value){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_f"), return;); + *((JSONNode*)node) = value; +} + +MIR_CORE_DLL(void) json_set_b(JSONNODE *node, int value){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_b"), return;); + *((JSONNode*)node) = value != 0; +} + +MIR_CORE_DLL(void) json_set_n(JSONNODE *node, const JSONNODE *orig){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_n"), return;); + JSON_ASSERT_SAFE(orig, JSON_TEXT("null node to json_set_n"), return;); + *((JSONNode*)node) = *((JSONNode*)orig); +} + +//inspectors +MIR_CORE_DLL(char) json_type(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_type"), return JSON_NULL;); + return ((JSONNode*)node) -> type(); +} + +MIR_CORE_DLL(json_index_t) json_size(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_size"), return 0;); + return ((JSONNode*)node) -> size(); +} + +MIR_CORE_DLL(int) json_empty(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_empty"), return true;); + return (int)(((JSONNode*)node) -> empty()); +} + +MIR_CORE_DLL(const json_char*) json_name(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_name"), return EMPTY_CSTRING;); + return ((JSONNode*)node) -> name(); +} + +#ifdef JSON_COMMENTS + MIR_CORE_DLL(json_char*) json_get_comment(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_get_comment"), return toCString(EMPTY_CSTRING);); + return toCString(((JSONNode*)node) -> get_comment()); + } +#endif + +MIR_CORE_DLL(TCHAR*) json_as_string(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_string"), return toCString(EMPTY_CSTRING);); + return toCString(((JSONNode*)node) -> as_string()); +} + +MIR_C_CORE_DLL(std::string) json_as_pstring(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_string"), return EMPTY_CSTRING;); + return ((JSONNode*)node) -> as_string(); +} + +MIR_CORE_DLL(long) json_as_int(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_int"), return 0;); + return ((JSONNode*)node) -> as_int(); +} + +MIR_CORE_DLL(double) json_as_float(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_float"), return 0.0;); + return ((JSONNode*)node) -> as_float(); +} + +MIR_CORE_DLL(int) json_as_bool(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_bool"), return false;); + return (int)(((JSONNode*)node) -> as_bool()); +} + +MIR_CORE_DLL(JSONNODE*) json_as_node(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_node"), return 0;); + return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(((JSONNode*)node) -> as_node())); +} + +MIR_CORE_DLL(JSONNODE*) json_as_array(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_array"), return 0;); + return MANAGER_INSERT(JSONNode::newJSONNode_Shallow(((JSONNode*)node) -> as_array())); +} + +#ifdef JSON_BINARY + void * json_as_binary(const JSONNODE *node, unsigned long * size){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_as_binary"), if (size){*size = 0;} return 0;); + const std::string result = ((JSONNode*)node) -> as_binary(); + const size_t len = result.length(); + if (size) *size = len; + #ifdef JSON_SAFE + if (result.empty()) return 0; + #endif + #ifdef JSON_MEMORY_MANAGE + return StringHandler.insert(memcpy(json_malloc(len), result.data(), len)); + #else + return memcpy(json_malloc(len), result.data(), len); + #endif + } +#endif + +#ifdef JSON_WRITER + MIR_CORE_DLL(TCHAR*) json_write(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_write"), return toCString(EMPTY_CSTRING);); + return toCString(((JSONNode*)node) -> write()); + } + + MIR_CORE_DLL(TCHAR*) json_write_formatted(const JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_write_formatted"), return toCString(EMPTY_CSTRING);); + return toCString(((JSONNode*)node) -> write_formatted()); + } +#endif + +//modifiers +MIR_CORE_DLL(void) json_set_name(JSONNODE *node, const json_char *name){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_name"), return;); + JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_set_name"), name = EMPTY_CSTRING;); + ((JSONNode*)node) -> set_name(name); +} + +#ifdef JSON_COMMENTS + MIR_CORE_DLL(void) json_set_comment(JSONNODE *node, const json_char * comment){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_set_comment"), return;); + JSON_ASSERT_SAFE(comment, JSON_TEXT("null name to json_set_comment"), comment = EMPTY_CSTRING;); + ((JSONNode*)node) -> set_comment(comment); + } +#endif + +MIR_CORE_DLL(void) json_clear(JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_clear"), return;); + ((JSONNode*)node) -> clear(); +} + +MIR_CORE_DLL(void) json_nullify(JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_nullify"), return;); + ((JSONNode*)node) -> nullify(); +} + +MIR_CORE_DLL(void) json_swap(JSONNODE *node, JSONNODE *node2){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_swap"), return;); + JSON_ASSERT_SAFE(node2, JSON_TEXT("null node to json_swap"), return;); + ((JSONNode*)node) -> swap(*(JSONNode*)node2); +} + +MIR_CORE_DLL(void) json_merge(JSONNODE *node, JSONNODE *node2){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_merge"), return;); + JSON_ASSERT_SAFE(node2, JSON_TEXT("null node to json_merge"), return;); + ((JSONNode*)node) -> merge(*(JSONNode*)node2); +} + +#ifndef JSON_PREPARSE + MIR_CORE_DLL(void) json_preparse(JSONNODE *node){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_preparse"), return;); + ((JSONNode*)node) -> preparse(); + } +#endif + +#ifdef JSON_BINARY + MIR_CORE_DLL(void) json_set_binary(JSONNODE *node, const void * data, unsigned long length){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_swap"), return;); + JSON_ASSERT_SAFE(data, JSON_TEXT("null data to json_set_binary"), *((JSONNode*)node) = EMPTY_CSTRING; return;); + ((JSONNode*)node) -> set_binary((unsigned char *)data, length); + } +#endif + +MIR_CORE_DLL(void) json_cast(JSONNODE *node, char type){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_cast"), return;); + ((JSONNode*)node) -> cast(type); +} + +//children access +MIR_CORE_DLL(void) json_reserve(JSONNODE *node, json_index_t siz){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_reserve"), return;); + ((JSONNode*)node) -> reserve(siz); +} + +MIR_CORE_DLL(JSONNODE*) json_at(JSONNODE *node, json_index_t pos){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_at"), return 0;); + try { + return &((JSONNode*)node) -> at(pos); + } catch (std::out_of_range){} + return 0; +} + +MIR_CORE_DLL(JSONNODE*) json_get(JSONNODE *node, const json_char *name){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_get"), return 0;); + JSON_ASSERT_SAFE(name, JSON_TEXT("null node to json_get. Did you mean to use json_at?"), return 0;); + try { + return &((JSONNode*)node) -> at(name); + } catch (std::out_of_range){} + return 0; +} + +#ifdef JSON_CASE_INSENSITIVE_FUNCTIONS + MIR_CORE_DLL(JSONNODE*) json_get_nocase(JSONNODE *node, const json_char *name){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_at_nocase"), return 0;); + JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_at_nocase"), return 0;); + try { + return &((JSONNode*)node) -> at_nocase(name); + } catch (std::out_of_range){} + return 0; + } + + MIR_CORE_DLL(JSONNODE*) json_pop_back_nocase(JSONNODE *node, const json_char *name){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_pop_back_nocase"), return 0;); + JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_pop_back_nocase"), return 0;); + return MANAGER_INSERT(((JSONNode*)node) -> pop_back_nocase(name)); + } +#endif + +MIR_CORE_DLL(void) json_push_back(JSONNODE *node, JSONNODE *node2){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_push_back"), return;); + JSON_ASSERT_SAFE(node2, JSON_TEXT("null node2 to json_push_back"), return;); + #ifdef JSON_MEMORY_MANAGE + NodeHandler.remove(node2); + #endif + ((JSONNode*)node) -> push_back((JSONNode*)node2); +} + +MIR_CORE_DLL(JSONNODE*) json_pop_back_at(JSONNODE *node, json_index_t pos){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_pop_back_i"), return 0;); + return MANAGER_INSERT(((JSONNode*)node) -> pop_back(pos)); +} + +MIR_CORE_DLL(JSONNODE*) json_pop_back(JSONNODE *node, const json_char *name){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_pop_back"), return 0;); + JSON_ASSERT_SAFE(name, JSON_TEXT("null name to json_pop_back. Did you mean to use json_pop_back_at?"), return 0;); + return MANAGER_INSERT(((JSONNode*)node) -> pop_back(name)); +} + +//comparison +MIR_CORE_DLL(int) json_equal(JSONNODE *node, JSONNODE *node2){ + JSON_ASSERT_SAFE(node, JSON_TEXT("null node to json_equal"), return false;); + JSON_ASSERT_SAFE(node2, JSON_TEXT("null node2 to json_equal"), return false;); + return (int)(*((JSONNode*)node) == *((JSONNode*)node2)); +} diff --git a/src/mir_core/src/langpack.cpp b/src/mir_core/src/langpack.cpp new file mode 100644 index 0000000000..0c2cf130ea --- /dev/null +++ b/src/mir_core/src/langpack.cpp @@ -0,0 +1,734 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" +#include "../../modules/langpack/langpack.h" + +#define LANGPACK_BUF_SIZE 4000 + +static int CompareMuuids(const MUUID *p1, const MUUID *p2) +{ + return memcmp(p1, p2, sizeof(MUUID)); +} + +static LIST lMuuids(10, CompareMuuids); +static MUUID *pCurrentMuuid = NULL; +static HANDLE hevChanged = 0; + +static BOOL bModuleInitialized = FALSE; + +struct LangPackEntry +{ + DWORD englishHash; + char *szLocal; + wchar_t *wszLocal; + MUUID *pMuuid; + LangPackEntry* pNext; // for langpack items with the same hash value +}; + +static LANGPACK_INFO langPack; +static TCHAR g_tszRoot[MAX_PATH]; + +static LangPackEntry *g_pEntries; +static int g_entryCount, g_entriesAlloced; + +static int IsEmpty(const char *str) +{ + for (int i = 0; str[i]; i++) + if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') + return 0; + + return 1; +} + +static int ConvertBackslashes(char *str, UINT fileCp) +{ + int shift = 0; + char *pstr; + for (pstr = str; *pstr; pstr = CharNextExA(fileCp, pstr, 0)) { + if (*pstr == '\\') { + shift++; + switch (pstr[1]) { + case 'n': *pstr = '\n'; break; + case 't': *pstr = '\t'; break; + case 'r': *pstr = '\r'; break; + case 's': *pstr = ' '; break; + default: *pstr = pstr[1]; break; + } + memmove(pstr + 1, pstr + 2, strlen(pstr + 2) + 1); + } + } + return shift; +} + +#ifdef _DEBUG +//#pragma optimize("gt", on) +#endif + +// MurmurHash2 +MIR_CORE_DLL(unsigned int) mir_hash(const void * key, unsigned int len) +{ + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + const unsigned int m = 0x5bd1e995; + const int r = 24; + + // Initialize the hash to a 'random' value + unsigned int h = len; + + // Mix 4 bytes at a time into the hash + const unsigned char *data = (const unsigned char*)key; + + while (len >= 4) { + unsigned int k = *(unsigned int*)data; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + // Handle the last few bytes of the input array + switch (len) { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + } + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +static unsigned int __fastcall hashstrW(const char *key) +{ + if (key == NULL) return 0; + const unsigned int len = (unsigned int)wcslen((const wchar_t*)key); + char *buf = (char*)alloca(len + 1); + for (unsigned i = 0; i <= len; ++i) + buf[i] = key[i << 1]; + return mir_hash(buf, len); +} + +static int SortLangPackHashesProc(LangPackEntry *arg1, LangPackEntry *arg2) +{ + if (arg1->englishHash < arg2->englishHash) return -1; + if (arg1->englishHash > arg2->englishHash) return 1; + + return (arg1->pMuuid < arg2->pMuuid) ? -1 : 1; +} + +static void swapBytes(void *p, size_t iSize) +{ + char *head = (char*)p; // here + char *tail = head + iSize - 1; + + for (; tail > head; --tail, ++head) { + char temp = *head; + *head = *tail; + *tail = temp; + } +} + +static bool EnterMuuid(const char *p, MUUID &result) +{ + if (*p++ != '{') + return false; + + BYTE *d = (BYTE*)&result; + + for (int nBytes = 0; *p && nBytes < 24; p++) { + if (*p == '-') + continue; + + if (*p == '}') + break; + + if (!isxdigit(*p)) + return false; + + if (!isxdigit(p[1])) + return false; + + int c = 0; + if (sscanf(p, "%2x", &c) != 1) + return false; + + *d++ = (BYTE)c; + nBytes++; + p++; + } + + if (*p != '}') + return false; + + swapBytes(&result.a, sizeof(result.a)); + swapBytes(&result.b, sizeof(result.b)); + swapBytes(&result.c, sizeof(result.c)); + return true; +} + +static void LoadLangPackFile(FILE *fp, char *line) +{ + while (!feof(fp)) { + if (fgets(line, LANGPACK_BUF_SIZE, fp) == NULL) + break; + + if (IsEmpty(line) || line[0] == ';' || line[0] == 0) + continue; + + rtrim(line); + + if (line[0] == '#') { + strlwr(line); + + if (!memcmp(line + 1, "include", 7)) { + TCHAR tszFileName[MAX_PATH]; + TCHAR *p = _tcsrchr(langPack.tszFullPath, '\\'); + if (p) + *p = 0; + mir_sntprintf(tszFileName, SIZEOF(tszFileName), _T("%s\\%S"), langPack.tszFullPath, ltrim(line + 9)); + if (p) + *p = '\\'; + + FILE *fp = _tfopen(tszFileName, _T("r")); + if (fp) { + line[0] = 0; + fgets(line, LANGPACK_BUF_SIZE, fp); + + if (strlen(line) >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf') + fseek(fp, 3, SEEK_SET); + else + fseek(fp, 0, SEEK_SET); + + LoadLangPackFile(fp, line); + fclose(fp); + } + } + else if (!memcmp(line + 1, "muuid", 5)) { + MUUID t; + if (!EnterMuuid(line + 7, t)) + continue; + + MUUID *pNew = (MUUID*)mir_alloc(sizeof(MUUID)); + memcpy(pNew, &t, sizeof(t)); + lMuuids.insert(pNew); + pCurrentMuuid = pNew; + } + + continue; + } + + char cFirst = line[0]; + + ConvertBackslashes(line, CP_UTF8); + + size_t cbLen = strlen(line) - 1; + if (cFirst == '[' && line[cbLen] == ']') { + if (g_entryCount && g_pEntries[g_entryCount-1].wszLocal == NULL) + g_entryCount--; + + char *pszLine = line + 1; + line[cbLen] = '\0'; + if (++g_entryCount > g_entriesAlloced) { + g_entriesAlloced += 128; + g_pEntries = (LangPackEntry*)mir_realloc(g_pEntries, sizeof(LangPackEntry)*g_entriesAlloced); + } + + LangPackEntry *E = &g_pEntries[g_entryCount - 1]; + E->englishHash = mir_hashstr(pszLine); + E->szLocal = NULL; + E->wszLocal = NULL; + E->pMuuid = pCurrentMuuid; + E->pNext = NULL; + continue; + } + + if (!g_entryCount) + continue; + + LangPackEntry *E = &g_pEntries[g_entryCount - 1]; + int iNeeded = MultiByteToWideChar(CP_UTF8, 0, line, -1, 0, 0), iOldLen; + if (E->wszLocal == NULL) { + iOldLen = 0; + E->wszLocal = (wchar_t *)mir_alloc((iNeeded + 1) * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, line, -1, E->wszLocal, iNeeded); + } + else { + iOldLen = (int)wcslen(E->wszLocal); + E->wszLocal = (wchar_t*)mir_realloc(E->wszLocal, (sizeof(wchar_t)* (iOldLen + iNeeded + 2))); + E->wszLocal[iOldLen++] = '\n'; + } + MultiByteToWideChar(CP_UTF8, 0, line, -1, E->wszLocal + iOldLen, iNeeded); + } +} + +static int LoadLangDescr(LANGPACK_INFO &lpinfo, FILE *fp, char *line, int &startOfLine) +{ + char szLanguage[64]; szLanguage[0] = 0; + CMStringA szAuthors; + + lpinfo.codepage = CP_ACP; + lpinfo.flags = 0; + + fgets(line, LANGPACK_BUF_SIZE, fp); + size_t lineLen = strlen(line); + if (lineLen >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf') + memmove(line, line + 3, lineLen - 2); + + lrtrim(line); + if (mir_strcmp(line, "Miranda Language Pack Version 1")) + return 2; + + // headers + while (!feof(fp)) { + startOfLine = ftell(fp); + if (fgets(line, LANGPACK_BUF_SIZE, fp) == NULL) + break; + + lrtrim(line); + if (IsEmpty(line) || line[0] == ';' || line[0] == 0) + continue; + + if (line[0] == '[' || line[0] == '#') + break; + + char *pszColon = strchr(line, ':'); + if (pszColon == NULL) + return 3; + + *pszColon++ = 0; + if (!mir_strcmp(line, "Language")) { + strncpy_s(szLanguage, pszColon, _TRUNCATE); + lrtrim(szLanguage); + } + else if (!mir_strcmp(line, "Last-Modified-Using")) { + lpinfo.szLastModifiedUsing = pszColon; + lpinfo.szLastModifiedUsing.Trim(); + } + else if (!mir_strcmp(line, "Authors")) { + if (!szAuthors.IsEmpty()) + szAuthors.AppendChar(' '); + szAuthors.Append(lrtrim(pszColon)); + } + else if (!mir_strcmp(line, "Author-email")) { + lpinfo.szAuthorEmail = pszColon; + lpinfo.szAuthorEmail.Trim(); + } + else if (!mir_strcmp(line, "Locale")) { + char szBuf[20], *stopped; + + lrtrim(pszColon + 1); + USHORT langID = (USHORT)strtol(pszColon, &stopped, 16); + lpinfo.Locale = MAKELCID(langID, 0); + GetLocaleInfoA(lpinfo.Locale, LOCALE_IDEFAULTANSICODEPAGE, szBuf, 10); + szBuf[5] = 0; // codepages have max. 5 digits + lpinfo.codepage = atoi(szBuf); + } + } + + lpinfo.szAuthors = szAuthors; + + MultiByteToWideChar(lpinfo.codepage, 0, szLanguage, -1, lpinfo.tszLanguage, SIZEOF(lpinfo.tszLanguage)); + + if (!lpinfo.tszLanguage[0] && (lpinfo.Locale == 0) || !GetLocaleInfo(lpinfo.Locale, LOCALE_SENGLANGUAGE, lpinfo.tszLanguage, sizeof(lpinfo.tszLanguage))) { + TCHAR *p = _tcschr(lpinfo.tszFileName, '_'); + _tcsncpy_s(lpinfo.tszLanguage, ((p != NULL) ? (p + 1) : lpinfo.tszFileName), _TRUNCATE); + p = _tcsrchr(lpinfo.tszLanguage, _T('.')); + if (p != NULL) *p = '\0'; + } + return 0; +} + +MIR_CORE_DLL(int) LoadLangPack(const TCHAR *ptszLangPack) +{ + if (ptszLangPack == NULL || !mir_tstrcmpi(ptszLangPack, _T(""))) + return 1; + + // ensure that a lang's name is a full file name + TCHAR tszFullPath[MAX_PATH]; + if (!PathIsAbsoluteT(ptszLangPack)) + mir_sntprintf(tszFullPath, SIZEOF(tszFullPath), _T("%s\\%s"), g_tszRoot, ptszLangPack); + else + _tcsncpy_s(tszFullPath, ptszLangPack, _TRUNCATE); + + // this lang is already loaded? nothing to do then + if (!mir_tstrcmp(tszFullPath, langPack.tszFullPath)) + return 0; + + // ok... loading a new langpack. remove the old one if needed + if (g_entryCount) + UnloadLangPackModule(); + + // exists & not a directory? + DWORD dwAttrib = GetFileAttributes(tszFullPath); + if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) + return 3; + + // copy the full file name and extract a file name from it + _tcsncpy_s(langPack.tszFullPath, tszFullPath, _TRUNCATE); + TCHAR *p = _tcsrchr(langPack.tszFullPath, '\\'); + _tcsncpy_s(langPack.tszFileName, (p == NULL) ? tszFullPath : p + 1, _TRUNCATE); + CharLower(langPack.tszFileName); + + FILE *fp = _tfopen(tszFullPath, _T("rt")); + if (fp == NULL) + return 1; + + char line[LANGPACK_BUF_SIZE] = ""; + int startOfLine = 0; + if (LoadLangDescr(langPack, fp, line, startOfLine)) { + fclose(fp); + return 1; + } + + // body + fseek(fp, startOfLine, SEEK_SET); + + LoadLangPackFile(fp, line); + fclose(fp); + pCurrentMuuid = NULL; + + qsort(g_pEntries, g_entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc); + return 0; +} + +MIR_CORE_DLL(int) LoadLangPackDescr(const TCHAR *ptszLangPack, LANGPACK_INFO *lpInfo) +{ + if (lpInfo == NULL) + return 1; + + _tcsncpy_s(lpInfo->tszFullPath, ptszLangPack, _TRUNCATE); + TCHAR *p = _tcsrchr(lpInfo->tszFullPath, '\\'); + _tcsncpy_s(lpInfo->tszFileName, (p == NULL) ? ptszLangPack : p+1, _TRUNCATE); + CharLower(lpInfo->tszFileName); + + FILE *fp = _tfopen(ptszLangPack, _T("rt")); + if (fp == NULL) + return 1; + + char line[LANGPACK_BUF_SIZE] = ""; + int startOfLine = 0; + int res = LoadLangDescr(*lpInfo, fp, line, startOfLine); + fclose(fp); + return res; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int SortLangPackHashesProc2(LangPackEntry *arg1, LangPackEntry *arg2) +{ + if (arg1->englishHash < arg2->englishHash) return -1; + if (arg1->englishHash > arg2->englishHash) return 1; + return 0; +} + +static char *LangPackTranslateString(MUUID *pUuid, const char *szEnglish, const int W) +{ + if (g_entryCount == 0 || szEnglish == NULL) + return (char*)szEnglish; + + LangPackEntry key, *entry; + key.englishHash = W ? hashstrW(szEnglish) : mir_hashstr(szEnglish); + entry = (LangPackEntry*)bsearch(&key, g_pEntries, g_entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc2); + if (entry == NULL) + return (char*)szEnglish; + + // try to find the exact match, otherwise the first entry will be returned + if (pUuid) { + for (LangPackEntry *p = entry->pNext; p != NULL; p = p->pNext) { + if (p->pMuuid == pUuid) { + entry = p; + break; + } + } + } + + if (W) + return (char*)entry->wszLocal; + + if (entry->szLocal == NULL && entry->wszLocal != NULL) + entry->szLocal = mir_u2a_cp(entry->wszLocal, langPack.codepage); + return entry->szLocal; +} + +MIR_CORE_DLL(int) Langpack_GetDefaultCodePage() +{ + return langPack.codepage; +} + +MIR_CORE_DLL(int) Langpack_GetDefaultLocale() +{ + return (langPack.Locale == 0) ? LOCALE_USER_DEFAULT : langPack.Locale; +} + +MIR_CORE_DLL(TCHAR*) Langpack_PcharToTchar(const char *pszStr) +{ + if (pszStr == NULL) + return NULL; + + int len = (int)strlen(pszStr); + TCHAR *result = (TCHAR*)alloca((len + 1)*sizeof(TCHAR)); + MultiByteToWideChar(Langpack_GetDefaultCodePage(), 0, pszStr, -1, result, len); + result[len] = 0; + return mir_wstrdup(TranslateW(result)); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(char*) TranslateA_LP(const char *str, int hLangpack) +{ + return (char*)LangPackTranslateString(Langpack_LookupUuid(hLangpack), str, FALSE); +} + +MIR_CORE_DLL(WCHAR*) TranslateW_LP(const WCHAR *str, int hLangpack) +{ + return (WCHAR*)LangPackTranslateString(Langpack_LookupUuid(hLangpack), (LPCSTR)str, TRUE); +} + +MIR_CORE_DLL(void) TranslateMenu_LP(HMENU hMenu, int hLangpack) +{ + MUUID *uuid = Langpack_LookupUuid(hLangpack); + + MENUITEMINFO mii = { sizeof(mii) }; + for (int i = GetMenuItemCount(hMenu) - 1; i >= 0; i--) { + TCHAR str[256]; + mii.fMask = MIIM_TYPE | MIIM_SUBMENU; + mii.dwTypeData = (TCHAR*)str; + mii.cch = SIZEOF(str); + GetMenuItemInfo(hMenu, i, TRUE, &mii); + + if (mii.cch && mii.dwTypeData) { + TCHAR *result = (TCHAR*)LangPackTranslateString(uuid, (const char*)mii.dwTypeData, TRUE); + if (result != mii.dwTypeData) { + mii.dwTypeData = result; + mii.fMask = MIIM_TYPE; + SetMenuItemInfo(hMenu, i, TRUE, &mii); + } + } + + if (mii.hSubMenu != NULL) + TranslateMenu_LP(mii.hSubMenu, hLangpack); + } +} + +static void TranslateWindow(MUUID *pUuid, HWND hwnd) +{ + TCHAR title[2048]; + GetWindowText(hwnd, title, SIZEOF(title)); + + TCHAR *result = (TCHAR*)LangPackTranslateString(pUuid, (const char*)title, TRUE); + if (result != title) + SetWindowText(hwnd, result); +} + +struct LANGPACKTRANSLATEDIALOG +{ + HWND hwndDlg; + int hLangpack; +}; + +static BOOL CALLBACK TranslateDialogEnumProc(HWND hwnd, LPARAM lParam) +{ + int hLangpack = (int)lParam; + TCHAR szClass[32]; + int id = GetDlgCtrlID(hwnd); + + MUUID *uuid = Langpack_LookupUuid(hLangpack); + + GetClassName(hwnd, szClass, SIZEOF(szClass)); + if (!mir_tstrcmpi(szClass, _T("static")) || !mir_tstrcmpi(szClass, _T("hyperlink")) || !mir_tstrcmpi(szClass, _T("button")) || !mir_tstrcmpi(szClass, _T("MButtonClass")) || !mir_tstrcmpi(szClass, _T("MHeaderbarCtrl"))) + TranslateWindow(uuid, hwnd); + else if (!mir_tstrcmpi(szClass, _T("edit"))) { + if (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY) + TranslateWindow(uuid, hwnd); + } + return TRUE; +} + +MIR_CORE_DLL(void) TranslateDialog_LP(HWND hDlg, int hLangpack) +{ + TranslateWindow(Langpack_LookupUuid(hLangpack), hDlg); + EnumChildWindows(hDlg, TranslateDialogEnumProc, hLangpack); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(MUUID*) Langpack_LookupUuid(WPARAM wParam) +{ + int idx = (wParam >> 16) & 0xFFFF; + return (idx > 0 && idx <= lMuuids.getCount()) ? lMuuids[idx - 1] : NULL; +} + +MIR_CORE_DLL(int) Langpack_MarkPluginLoaded(PLUGININFOEX *pInfo) +{ + int idx = lMuuids.getIndex(&pInfo->uuid); + if (idx == -1) + return 0; + + return (idx + 1) << 16; +} + +MIR_CORE_DLL(void) Langpack_SortDuplicates(void) +{ + if (g_entryCount == 0) + return; + + LangPackEntry *s = g_pEntries + 1, *d = s, *pLast = g_pEntries; + DWORD dwSavedHash = g_pEntries->englishHash; + bool bSortNeeded = false; + + for (int i = 1; i < g_entryCount; i++, s++) { + if (s->englishHash != dwSavedHash) { + pLast = d; + if (s != d) + *d++ = *s; + else + d++; + dwSavedHash = s->englishHash; + } + else { + bSortNeeded = true; + LangPackEntry *p = (LangPackEntry*)mir_alloc(sizeof(LangPackEntry)); + *p = *s; + pLast->pNext = p; pLast = p; + } + } + + if (bSortNeeded) { + g_entryCount = (int)(d - g_pEntries); + qsort(g_pEntries, g_entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +TCHAR tszDefaultLang[100]; + +void GetDefaultLang() +{ + // calculate the langpacks' root + PathToAbsoluteT(_T("\\Languages"), g_tszRoot); + if (_taccess(g_tszRoot, 0) != 0) // directory Languages exists + PathToAbsoluteT(_T("."), g_tszRoot); + + // look into mirandaboot.ini + TCHAR tszPath[MAX_PATH]; + PathToAbsoluteT(_T("\\mirandaboot.ini"), tszPath); + GetPrivateProfileString(_T("Language"), _T("DefaultLanguage"), _T(""), tszDefaultLang, SIZEOF(tszDefaultLang), tszPath); + + if (!mir_tstrcmpi(tszDefaultLang, _T("default"))) { + db_set_ts(NULL, "Langpack", "Current", _T("default")); + return; + } + else if (!LoadLangPack(tszDefaultLang)) { + db_set_ts(NULL, "Langpack", "Current", tszDefaultLang); + return; + } + + // finally try to load first file + mir_sntprintf(tszPath, SIZEOF(tszPath), _T("%s\\langpack_*.txt"), g_tszRoot); + + WIN32_FIND_DATA fd; + HANDLE hFind = FindFirstFile(tszPath, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + /* search first langpack that could be loaded */ + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + if (!LoadLangPack(fd.cFileName)) { + db_set_ts(NULL, "Langpack", "Current", fd.cFileName); + break; + } + } while (FindNextFile(hFind, &fd)); + FindClose(hFind); + } else + db_set_ts(NULL, "Langpack", "Current", _T("default")); +} + +MIR_CORE_DLL(int) LoadLangPackModule(void) +{ + bModuleInitialized = TRUE; + hevChanged = CreateHookableEvent(ME_LANGPACK_CHANGED); + GetDefaultLang(); + return 0; +} + +void UnloadLangPackModule() +{ + if (!bModuleInitialized) return; + + int i; + for (i = 0; i < lMuuids.getCount(); i++) + mir_free(lMuuids[i]); + lMuuids.destroy(); + + LangPackEntry *p = g_pEntries; + for (i = 0; i < g_entryCount; i++, p++) { + if (p->pNext != NULL) { + for (LangPackEntry *p1 = p->pNext; p1 != NULL;) { + LangPackEntry *p2 = p1; p1 = p1->pNext; + mir_free(p2->szLocal); + mir_free(p2->wszLocal); + mir_free(p2); + } + } + + mir_free(p->szLocal); + mir_free(p->wszLocal); + } + + if (g_entryCount) { + mir_free(g_pEntries); + g_pEntries = 0; + g_entryCount = g_entriesAlloced = 0; + } + + langPack.tszFileName[0] = langPack.tszFullPath[0] = 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(void) ReloadLangpack(TCHAR *pszStr) +{ + if (pszStr == NULL) + pszStr = NEWTSTR_ALLOCA(langPack.tszFileName); + + UnloadLangPackModule(); + LoadLangPack(pszStr); + Langpack_SortDuplicates(); + + NotifyEventHooks(hevChanged, 0, 0); +} diff --git a/src/mir_core/src/lists.cpp b/src/mir_core/src/lists.cpp new file mode 100644 index 0000000000..f981927cd8 --- /dev/null +++ b/src/mir_core/src/lists.cpp @@ -0,0 +1,247 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +/* a simple sorted list implementation */ + +MIR_CORE_DLL(SortedList*) List_Create(int p_limit, int p_increment) +{ + SortedList* result = (SortedList*)mir_calloc(sizeof(SortedList)); + if (result == NULL) + return(NULL); + + result->increment = p_increment; + result->limit = p_limit; + return result; +} + +MIR_CORE_DLL(void) List_Destroy(SortedList* p_list) +{ + if (p_list == NULL) + return; + + if (p_list->items != NULL) { + mir_free(p_list->items); + p_list->items = NULL; + } + + p_list->realCount = p_list->limit = 0; +} + +MIR_CORE_DLL(void*) List_Find(SortedList* p_list, void* p_value) +{ + int idx; + if (!List_GetIndex(p_list, p_value, &idx)) + return NULL; + + return p_list->items[idx]; +} + +#ifdef _DEBUG +#pragma optimize("gt", on) +#endif + +MIR_CORE_DLL(int) List_GetIndex(SortedList* p_list, void* p_value, int* p_index) +{ + if (p_value == NULL || p_list->sortFunc == NULL) { + *p_index = -1; + return 0; + } + + int low = 0; + int high = p_list->realCount - 1; + + switch ((INT_PTR)p_list->sortFunc) { + case HandleKeySort: + #ifdef _WIN64 + { + const unsigned __int64 val = *(unsigned __int64 *)p_value; + + while (low <= high) { + int i = (low + high) / 2; + unsigned __int64 vali = *(unsigned __int64 *)p_list->items[i]; + if (vali == val) { + *p_index = i; + return 1; + } + + if (vali < val) + low = i + 1; + else + high = i - 1; + } + } + break; + #endif + + case NumericKeySort: + { + const unsigned val = *(unsigned *)p_value; + + while (low <= high) { + int i = (low + high) / 2; + unsigned vali = *(unsigned *)p_list->items[i]; + if (vali == val) { + *p_index = i; + return 1; + } + + if (vali < val) + low = i + 1; + else + high = i - 1; + } + } + break; + + case PtrKeySort: + while (low <= high) { + int i = (low + high) / 2; + const void* vali = p_list->items[i]; + if (vali == p_value) { + *p_index = i; + return 1; + } + + if (vali < p_value) + low = i + 1; + else + high = i - 1; + } + break; + + default: + while (low <= high) { + int i = (low + high) / 2; + int result = p_list->sortFunc(p_list->items[i], p_value); + if (result == 0) { + *p_index = i; + return 1; + } + + if (result < 0) + low = i + 1; + else + high = i - 1; + } + break; + } + + *p_index = low; + return 0; +} + +MIR_CORE_DLL(int) List_IndexOf(SortedList* p_list, void* p_value) +{ + if (p_value == NULL) + return -1; + + for (int i = 0; i < p_list->realCount; i++) + if (p_list->items[i] == p_value) + return i; + + return -1; +} + +#ifdef _DEBUG +#pragma optimize("", on) +#endif + +MIR_CORE_DLL(int) List_Insert(SortedList* p_list, void* p_value, int p_index) +{ + if (p_value == NULL || p_index > p_list->realCount) + return 0; + + if (p_list->realCount == p_list->limit) { + p_list->items = (void**)mir_realloc(p_list->items, sizeof(void*)*(p_list->realCount + p_list->increment)); + p_list->limit += p_list->increment; + } + + if (p_index < p_list->realCount) + memmove(p_list->items + p_index + 1, p_list->items + p_index, sizeof(void*)*(p_list->realCount - p_index)); + + p_list->realCount++; + + p_list->items[p_index] = p_value; + return 1; +} + +MIR_CORE_DLL(int) List_InsertPtr(SortedList* list, void* p) +{ + if (p == NULL) + return -1; + + int idx; + if (list->sortFunc == 0) + idx = list->realCount; + else + List_GetIndex(list, p, &idx); + return List_Insert(list, p, idx); +} + +MIR_CORE_DLL(int) List_Remove(SortedList* p_list, int index) +{ + if (index < 0 || index > p_list->realCount) + return 0; + + p_list->realCount--; + if (p_list->realCount > index) { + memmove(p_list->items + index, p_list->items + index + 1, sizeof(void*)*(p_list->realCount - index)); + p_list->items[p_list->realCount] = NULL; + } + + return 1; +} + +MIR_CORE_DLL(int) List_RemovePtr(SortedList* list, void* p) +{ + int idx; + if (!List_GetIndex(list, p, &idx)) + return -1; + + List_Remove(list, idx); + return idx; +} + +MIR_CORE_DLL(void) List_Copy(SortedList* s, SortedList* d, size_t itemSize) +{ + d->increment = s->increment; + d->limit = s->limit; + d->realCount = s->realCount; + d->items = (void**)mir_alloc(sizeof(void*) * d->realCount); + memcpy(d->items, s->items, sizeof(void*) * d->realCount); +} + +MIR_CORE_DLL(void) List_ObjCopy(SortedList* s, SortedList* d, size_t itemSize) +{ + d->increment = s->increment; + d->sortFunc = s->sortFunc; + + for (int i = 0; i < s->realCount; i++) { + void* item = new char[itemSize]; + memcpy(item, s->items[i], itemSize); + List_Insert(d, item, i); + } +} diff --git a/src/mir_core/src/logger.cpp b/src/mir_core/src/logger.cpp new file mode 100644 index 0000000000..e129f48765 --- /dev/null +++ b/src/mir_core/src/logger.cpp @@ -0,0 +1,228 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +#define SECRET_SIGNATURE 0x87654321 + +struct Logger +{ + Logger(const char* pszName, const TCHAR *ptszDescr, const TCHAR *ptszFilename, unsigned options) : + m_name(mir_strdup(pszName)), + m_descr(mir_tstrdup(ptszDescr)), + m_fileName(mir_tstrdup(ptszFilename)), + m_options(options), + m_signature(SECRET_SIGNATURE), + m_out(NULL), + m_lastwrite(0) + { + InitializeCriticalSection(&m_cs); + } + + ~Logger() + { + if (m_out) + fclose(m_out); + + DeleteCriticalSection(&m_cs); + } + + int m_signature; + ptrA m_name; + ptrT m_fileName, m_descr; + FILE *m_out; + __int64 m_lastwrite; + unsigned m_options; + + CRITICAL_SECTION m_cs; +}; + +static int CompareLoggers(const Logger *p1, const Logger *p2) +{ return strcmp(p1->m_name, p2->m_name); +} + +static OBJLIST arLoggers(1, CompareLoggers); + +static __int64 llIdlePeriod; + +void InitLogs() +{ + LARGE_INTEGER li; + QueryPerformanceFrequency(&li); + llIdlePeriod = li.QuadPart; +} + +void UninitLogs() +{ + arLoggers.destroy(); +} + +void CheckLogs() +{ + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + + for (int i=0; i < arLoggers.getCount(); i++) { + Logger &p = arLoggers[i]; + + mir_cslock lck(p.m_cs); + if (p.m_out && li.QuadPart - p.m_lastwrite > llIdlePeriod) { + fclose(p.m_out); + p.m_out = NULL; + } + else fflush(p.m_out); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(HANDLE) mir_createLog(const char* pszName, const TCHAR *ptszDescr, const TCHAR *ptszFile, unsigned options) +{ + if (ptszFile == NULL) + return NULL; + + Logger *result = new Logger(pszName, ptszDescr, ptszFile, options); + if (result == NULL) + return NULL; + + int idx = arLoggers.getIndex(result); + if (idx != -1) { + delete result; + return &arLoggers[idx]; + } + + FILE *fp = _tfopen(ptszFile, _T("ab")); + if (fp == NULL) { + TCHAR tszPath[MAX_PATH]; + _tcsncpy_s(tszPath, ptszFile, _TRUNCATE); + CreatePathToFileT(tszPath); + } + else fclose(fp); + + DeleteFile(ptszFile); + arLoggers.insert(result); + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +static Logger* prepareLogger(HANDLE hLogger) +{ + if (hLogger == NULL) + return NULL; + + Logger *p = (Logger*)hLogger; + return (p->m_signature == SECRET_SIGNATURE) ? p : NULL; +} + +MIR_CORE_DLL(void) mir_closeLog(HANDLE hLogger) +{ + Logger *p = prepareLogger(hLogger); + if (p != NULL) + arLoggers.remove(p); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +MIR_C_CORE_DLL(int) mir_writeLogA(HANDLE hLogger, const char *format, ...) +{ + Logger *p = prepareLogger(hLogger); + if (p == NULL) + return 1; + + mir_cslock lck(p->m_cs); + if (p->m_out == NULL) + if ((p->m_out = _tfopen(p->m_fileName, _T("ab"))) == NULL) + return 2; + + va_list args; + va_start(args, format); + vfprintf(p->m_out, format, args); + + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + p->m_lastwrite = li.QuadPart; + return 0; +} + +MIR_C_CORE_DLL(int) mir_writeLogW(HANDLE hLogger, const WCHAR *format, ...) +{ + Logger *p = prepareLogger(hLogger); + if (p == NULL) + return 1; + + mir_cslock lck(p->m_cs); + if (p->m_out == NULL) + if ((p->m_out = _tfopen(p->m_fileName, _T("ab"))) == NULL) + return 2; + + va_list args; + va_start(args, format); + vfwprintf(p->m_out, format, args); + + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + p->m_lastwrite = li.QuadPart; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(int) mir_writeLogVA(HANDLE hLogger, const char *format, va_list args) +{ + Logger *p = prepareLogger(hLogger); + if (p == NULL) + return 1; + + mir_cslock lck(p->m_cs); + if (p->m_out == NULL) + if ((p->m_out = _tfopen(p->m_fileName, _T("ab"))) == NULL) + return 2; + + vfprintf(p->m_out, format, args); + + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + p->m_lastwrite = li.QuadPart; + return 0; +} + +MIR_CORE_DLL(int) mir_writeLogVW(HANDLE hLogger, const WCHAR *format, va_list args) +{ + Logger *p = prepareLogger(hLogger); + if (p == NULL) + return 1; + + mir_cslock lck(p->m_cs); + if (p->m_out == NULL) + if ((p->m_out = _tfopen(p->m_fileName, _T("ab"))) == NULL) + return 2; + + vfwprintf(p->m_out, format, args); + + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + p->m_lastwrite = li.QuadPart; + return 0; +} diff --git a/src/mir_core/src/mc.cpp b/src/mir_core/src/mc.cpp new file mode 100644 index 0000000000..189e4a3ed0 --- /dev/null +++ b/src/mir_core/src/mc.cpp @@ -0,0 +1,188 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +static HANDLE hEventDefaultChanged, hEventEnabled; +static bool g_bEnabled; + +void InitMetaContacts() +{ + hEventDefaultChanged = CreateHookableEvent(ME_MC_DEFAULTTCHANGED); + hEventEnabled = CreateHookableEvent(ME_MC_ENABLED); +} + +DBCachedContact* CheckMeta(MCONTACT hMeta) +{ + if (!g_bEnabled) + return NULL; + + DBCachedContact *cc = currDb->m_cache->GetCachedContact(hMeta); + return (cc == NULL || cc->nSubs == -1) ? NULL : cc; +} + +int Meta_GetContactNumber(DBCachedContact *cc, MCONTACT hContact) +{ + if (g_bEnabled) + for (int i = 0; i < cc->nSubs; i++) + if (cc->pSubs[i] == hContact) + return i; + + return -1; +} + +MCONTACT Meta_GetContactHandle(DBCachedContact *cc, int contact_number) +{ + if (contact_number >= cc->nSubs || contact_number < 0 || !g_bEnabled) + return 0; + + return cc->pSubs[contact_number]; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// metacontacts + +MIR_CORE_DLL(BOOL) db_mc_isEnabled(void) +{ + return g_bEnabled; +} + +MIR_CORE_DLL(void) db_mc_enable(BOOL bEnabled) +{ + g_bEnabled = bEnabled != 0; + + NotifyEventHooks(hEventEnabled, g_bEnabled, 0); +} + +MIR_CORE_DLL(BOOL) db_mc_isMeta(MCONTACT hContact) +{ + if (currDb == NULL || !g_bEnabled) return FALSE; + + DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); + return (cc == NULL) ? FALSE : cc->nSubs != -1; +} + +MIR_CORE_DLL(BOOL) db_mc_isSub(MCONTACT hContact) +{ + if (currDb == NULL || !g_bEnabled) return FALSE; + + DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); + return (cc == NULL) ? FALSE : cc->parentID != 0; +} + +//returns a handle to the default contact, or null on failure +MIR_CORE_DLL(MCONTACT) db_mc_getDefault(MCONTACT hMetaContact) +{ + DBCachedContact *cc = CheckMeta(hMetaContact); + if (cc == NULL) + return 0; + + return (cc->nDefault != -1) ? Meta_GetContactHandle(cc, cc->nDefault) : 0; +} + +//returns the default contact number, or -1 on failure +MIR_CORE_DLL(int) db_mc_getDefaultNum(MCONTACT hMetaContact) +{ + DBCachedContact *cc = CheckMeta(hMetaContact); + return (cc == NULL) ? -1 : cc->nDefault; +} + +//returns the number of subcontacts, or -1 on failure +MIR_CORE_DLL(int) db_mc_getSubCount(MCONTACT hMetaContact) +{ + DBCachedContact *cc = CheckMeta(hMetaContact); + return (cc == NULL) ? -1 : cc->nSubs; +} + +// returns parent hContact for a subcontact or NULL if it's not a sub +MIR_CORE_DLL(MCONTACT) db_mc_getMeta(MCONTACT hSubContact) +{ + if (currDb == NULL) return NULL; + + DBCachedContact *cc = currDb->m_cache->GetCachedContact(hSubContact); + return (cc == NULL) ? NULL : cc->parentID; +} + +// returns parent hContact for a subcontact or hContact itself if it's not a sub +MIR_CORE_DLL(MCONTACT) db_mc_tryMeta(MCONTACT hContact) +{ + if (currDb == NULL) return hContact; + + DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); + if (cc == NULL) return hContact; + + return (cc->IsSub()) ? cc->parentID : hContact; +} + +// returns a subcontact with the given index +MIR_CORE_DLL(MCONTACT) db_mc_getSub(MCONTACT hMetaContact, int iNum) +{ + DBCachedContact *cc = CheckMeta(hMetaContact); + return (cc == NULL) ? 0 : Meta_GetContactHandle(cc, iNum); +} + +//sets the default contact, using the subcontact's handle +MIR_CORE_DLL(int) db_mc_setDefault(MCONTACT hMetaContact, MCONTACT hSub, BOOL bWriteDb) +{ + DBCachedContact *cc = CheckMeta(hMetaContact); + if (cc == NULL) + return 1; + + int contact_number = Meta_GetContactNumber(cc, hSub); + if (contact_number == -1) + return 1; + + if (cc->nDefault != contact_number) { + cc->nDefault = contact_number; + if (bWriteDb) + currDb->MetaSetDefault(cc); + + NotifyEventHooks(hEventDefaultChanged, hMetaContact, hSub); + } + return 0; +} + +//sets the default contact, using the subcontact's number +MIR_CORE_DLL(int) db_mc_setDefaultNum(MCONTACT hMetaContact, int iNum, BOOL bWriteDb) +{ + DBCachedContact *cc = CheckMeta(hMetaContact); + if (cc == NULL) + return 1; + if (iNum >= cc->nSubs || iNum < 0) + return 1; + + if (cc->nDefault != iNum) { + cc->nDefault = iNum; + if (bWriteDb) + currDb->MetaSetDefault(cc); + + NotifyEventHooks(hEventDefaultChanged, hMetaContact, Meta_GetContactHandle(cc, iNum)); + } + return 0; +} + +extern "C" MIR_CORE_DLL(void) db_mc_notifyDefChange(WPARAM wParam, LPARAM lParam) +{ + NotifyEventHooks(hEventDefaultChanged, wParam, lParam); +} diff --git a/src/mir_core/src/md5.cpp b/src/mir_core/src/md5.cpp new file mode 100644 index 0000000000..216abfedba --- /dev/null +++ b/src/mir_core/src/md5.cpp @@ -0,0 +1,358 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c 2874 2006-05-16 21:38:00Z ghazan $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +// (C) 2005 Joe @ Whale - changed to compile with Miranda + +#include "commonheaders.h" + +#define T_MASK ((UINT32)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +//gfd* +static void md5_process(mir_md5_state_t *pms, const BYTE *data /*[64]*/) +{ + UINT32 + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + UINT32 t; + /* Define storage for little-endian or both types of CPUs. */ + UINT32 xbuf[16]; + const UINT32 *X; + + { + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const BYTE *)&w)) /* dynamic little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if ( !((data - (const BYTE *)0) & 3)) { + /* data are properly aligned */ + X = (const UINT32 *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } + else /* dynamic big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const BYTE *xp = data; + int i; + + X = xbuf; /* (dynamic only) */ + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b, c, d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET1(a, b, c, d, k, s, Ti)\ + t = a + F(b, c, d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET1(a, b, c, d, 0, 7, T1); + SET1(d, a, b, c, 1, 12, T2); + SET1(c, d, a, b, 2, 17, T3); + SET1(b, c, d, a, 3, 22, T4); + SET1(a, b, c, d, 4, 7, T5); + SET1(d, a, b, c, 5, 12, T6); + SET1(c, d, a, b, 6, 17, T7); + SET1(b, c, d, a, 7, 22, T8); + SET1(a, b, c, d, 8, 7, T9); + SET1(d, a, b, c, 9, 12, T10); + SET1(c, d, a, b, 10, 17, T11); + SET1(b, c, d, a, 11, 22, T12); + SET1(a, b, c, d, 12, 7, T13); + SET1(d, a, b, c, 13, 12, T14); + SET1(c, d, a, b, 14, 17, T15); + SET1(b, c, d, a, 15, 22, T16); + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b, c, d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET2(a, b, c, d, k, s, Ti)\ + t = a + G(b, c, d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET2(a, b, c, d, 1, 5, T17); + SET2(d, a, b, c, 6, 9, T18); + SET2(c, d, a, b, 11, 14, T19); + SET2(b, c, d, a, 0, 20, T20); + SET2(a, b, c, d, 5, 5, T21); + SET2(d, a, b, c, 10, 9, T22); + SET2(c, d, a, b, 15, 14, T23); + SET2(b, c, d, a, 4, 20, T24); + SET2(a, b, c, d, 9, 5, T25); + SET2(d, a, b, c, 14, 9, T26); + SET2(c, d, a, b, 3, 14, T27); + SET2(b, c, d, a, 8, 20, T28); + SET2(a, b, c, d, 13, 5, T29); + SET2(d, a, b, c, 2, 9, T30); + SET2(c, d, a, b, 7, 14, T31); + SET2(b, c, d, a, 12, 20, T32); + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b, c, d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET3(a, b, c, d, k, s, Ti)\ + t = a + H(b, c, d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET3(a, b, c, d, 5, 4, T33); + SET3(d, a, b, c, 8, 11, T34); + SET3(c, d, a, b, 11, 16, T35); + SET3(b, c, d, a, 14, 23, T36); + SET3(a, b, c, d, 1, 4, T37); + SET3(d, a, b, c, 4, 11, T38); + SET3(c, d, a, b, 7, 16, T39); + SET3(b, c, d, a, 10, 23, T40); + SET3(a, b, c, d, 13, 4, T41); + SET3(d, a, b, c, 0, 11, T42); + SET3(c, d, a, b, 3, 16, T43); + SET3(b, c, d, a, 6, 23, T44); + SET3(a, b, c, d, 9, 4, T45); + SET3(d, a, b, c, 12, 11, T46); + SET3(c, d, a, b, 15, 16, T47); + SET3(b, c, d, a, 2, 23, T48); + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b, c, d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET4(a, b, c, d, k, s, Ti)\ + t = a + I(b, c, d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET4(a, b, c, d, 0, 6, T49); + SET4(d, a, b, c, 7, 10, T50); + SET4(c, d, a, b, 14, 15, T51); + SET4(b, c, d, a, 5, 21, T52); + SET4(a, b, c, d, 12, 6, T53); + SET4(d, a, b, c, 3, 10, T54); + SET4(c, d, a, b, 10, 15, T55); + SET4(b, c, d, a, 1, 21, T56); + SET4(a, b, c, d, 8, 6, T57); + SET4(d, a, b, c, 15, 10, T58); + SET4(c, d, a, b, 6, 15, T59); + SET4(b, c, d, a, 13, 21, T60); + SET4(a, b, c, d, 4, 6, T61); + SET4(d, a, b, c, 11, 10, T62); + SET4(c, d, a, b, 2, 15, T63); + SET4(b, c, d, a, 9, 21, T64); + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +MIR_CORE_DLL(void) mir_md5_init(mir_md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +MIR_CORE_DLL(void) mir_md5_append(mir_md5_state_t *pms, const BYTE *data, int nbytes) +{ + const BYTE *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + UINT32 nbits = (UINT32)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +MIR_CORE_DLL(void) mir_md5_finish(mir_md5_state_t *pms, BYTE digest[16]) +{ + static const BYTE pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + BYTE data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (BYTE)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + mir_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + mir_md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (BYTE)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + +MIR_CORE_DLL(void) mir_md5_hash(const BYTE *data, int len, BYTE digest[16]) +{ + mir_md5_state_t state; + mir_md5_init(&state); + mir_md5_append(&state, data, len); + mir_md5_finish(&state, digest); +} diff --git a/src/mir_core/src/memory.cpp b/src/mir_core/src/memory.cpp new file mode 100644 index 0000000000..9c1c2afbf6 --- /dev/null +++ b/src/mir_core/src/memory.cpp @@ -0,0 +1,285 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +#define BLOCK_ALLOCED 0xABBABABA +#define BLOCK_FREED 0xDEADBEEF + +static int CheckBlock(void* blk) +{ + int result = FALSE; + char* p = (char*)blk - sizeof(DWORD)*2; + DWORD size, *b, *e; + + __try + { + size = *(DWORD*)p; + b = (DWORD*)&p[ sizeof(DWORD) ]; + e = (DWORD*)&p[ sizeof(DWORD)*2 + size ]; + + if (*b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED) + { + if (*b == BLOCK_FREED && *e == BLOCK_FREED) + OutputDebugStringA("memory block is already deleted\n"); + else + OutputDebugStringA("memory block is corrupted\n"); + #if defined(_DEBUG) + DebugBreak(); + #endif + } + else result = TRUE; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + OutputDebugStringA("access violation during checking memory block\n"); + #if defined(_DEBUG) + DebugBreak(); + #endif + } + + return result; +} + +/******************************************************************************/ + +MIR_C_CORE_DLL(void*) mir_alloc(size_t size) +{ + if (size == 0) + return NULL; + + char *p = (char*)malloc(size + sizeof(DWORD)* 3); + if (p == NULL) { + OutputDebugStringA("memory overflow\n"); + #if defined(_DEBUG) + DebugBreak(); + #endif + return NULL; + } + + *(DWORD*)p = (DWORD)size; + *(DWORD*)&p[sizeof(DWORD)] = BLOCK_ALLOCED; + *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_ALLOCED; + return p + sizeof(DWORD)* 2; +} + +/******************************************************************************/ + +MIR_C_CORE_DLL(void*) mir_calloc(size_t size) +{ + void* p = mir_alloc(size); + if (p != NULL) + memset(p, 0, size); + return p; +} + +/******************************************************************************/ + +MIR_C_CORE_DLL(void*) mir_realloc(void* ptr, size_t size) +{ + char *p; + + if (ptr != NULL) { + if (!CheckBlock(ptr)) + return NULL; + p = (char*)ptr - sizeof(DWORD)*2; + } + else p = NULL; + + p = (char*)realloc(p, size + sizeof(DWORD)*3); + if (p == NULL) { + OutputDebugStringA("memory overflow\n"); + #if defined(_DEBUG) + DebugBreak(); + #endif + return NULL; + } + + *(DWORD*)p = (DWORD)size; + *(DWORD*)&p[sizeof(DWORD)] = BLOCK_ALLOCED; + *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_ALLOCED; + return p + sizeof(DWORD)*2; +} + +/******************************************************************************/ + +MIR_C_CORE_DLL(void) mir_free(void* ptr) +{ + char* p; + DWORD size; + + if (ptr == NULL) + return; + if (!CheckBlock(ptr)) + return; + + p = (char*)ptr - sizeof(DWORD)*2; + size = *(DWORD*)p; + + *(DWORD*)&p[sizeof(DWORD)] = BLOCK_FREED; + *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_FREED; + free(p); +} + +/******************************************************************************/ + +MIR_CORE_DLL(char*) mir_strdup(const char *str) +{ + if (str == NULL) + return NULL; + + char *p = (char*)mir_alloc(strlen(str)+1); + if (p) + strcpy(p, str); + return p; +} + +MIR_CORE_DLL(WCHAR*) mir_wstrdup(const WCHAR *str) +{ + if (str == NULL) + return NULL; + + WCHAR *p = (WCHAR*)mir_alloc(sizeof(WCHAR)*(wcslen(str)+1)); + if (p) + wcscpy(p, str); + return p; +} + +/******************************************************************************/ + +MIR_CORE_DLL(char*) mir_strndup(const char *str, size_t len) +{ + if (str == NULL || len == 0) + return NULL; + + char *p = (char*)mir_alloc(len+1); + if (p) { + memcpy(p, str, len); + p[len] = 0; + } + return p; +} + +MIR_CORE_DLL(WCHAR*) mir_wstrndup(const WCHAR *str, size_t len) +{ + if (str == NULL || len == 0) + return NULL; + + WCHAR *p = (WCHAR*)mir_alloc(sizeof(WCHAR)*(len+1)); + if (p) { + memcpy(p, str, sizeof(WCHAR)*len); + p[len] = 0; + } + return p; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_snprintf(char *buffer, size_t count, const char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + int len = _vsnprintf(buffer, count-1, fmt, va); + va_end(va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_snwprintf(WCHAR *buffer, size_t count, const WCHAR* fmt, ...) +{ + va_list va; + va_start(va, fmt); + int len = _vsntprintf(buffer, count-1, fmt, va); + va_end(va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va) +{ + int len = _vsnprintf(buffer, count-1, fmt, va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_vsnwprintf(WCHAR *buffer, size_t count, const WCHAR* fmt, va_list va) +{ + int len = _vsntprintf(buffer, count-1, fmt, va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +MIR_CORE_DLL(wchar_t*) mir_a2u_cp(const char* src, int codepage) +{ + if (src == NULL) + return NULL; + + int cbLen = MultiByteToWideChar(codepage, 0, src, -1, NULL, 0); + wchar_t* result = (wchar_t*)mir_alloc(sizeof(wchar_t)*(cbLen+1)); + if (result == NULL) + return NULL; + + MultiByteToWideChar(codepage, 0, src, -1, result, cbLen); + result[cbLen] = 0; + return result; +} + +/******************************************************************************/ + +MIR_CORE_DLL(wchar_t*) mir_a2u(const char* src) +{ + return mir_a2u_cp(src, Langpack_GetDefaultCodePage()); +} + +/******************************************************************************/ + +MIR_CORE_DLL(char*) mir_u2a_cp(const wchar_t* src, int codepage) +{ + if (src == NULL) + return NULL; + + int cbLen = WideCharToMultiByte(codepage, 0, src, -1, NULL, 0, NULL, NULL); + char* result = (char*)mir_alloc(cbLen+1); + if (result == NULL) + return NULL; + + WideCharToMultiByte(codepage, 0, src, -1, result, cbLen, NULL, NULL); + result[cbLen] = 0; + return result; +} + +/******************************************************************************/ + +MIR_CORE_DLL(char*) mir_u2a(const wchar_t* src) +{ + return mir_u2a_cp(src, Langpack_GetDefaultCodePage()); +} diff --git a/src/mir_core/src/mir_core.def b/src/mir_core/src/mir_core.def new file mode 100644 index 0000000000..312540f081 --- /dev/null +++ b/src/mir_core/src/mir_core.def @@ -0,0 +1,282 @@ +LIBRARY mir_core + +EXPORTS +CallContactService @1 +CallProtoService @2 +Langpack_LookupUuid @3 +Langpack_MarkPluginLoaded @4 +CallFunctionAsync @5 +CallPluginEventHook @7 +CallService @8 +CallServiceSync @9 +CreateDirectoryTree @10 +CreateDirectoryTreeW @11 +CreateHookableEvent @12 +CreatePathToFile @13 +CreatePathToFileW @14 +CreateServiceFunction @15 +CreateServiceFunctionObj @16 +CreateServiceFunctionObjParam @17 +CreateServiceFunctionParam @18 +DestroyHookableEvent @19 +DestroyServiceFunction @20 +GetExceptionFilter @21 +GetInstByAddress @22 +HookEvent @23 +HookEventMessage @24 +HookEventObj @25 +HookEventObjParam @26 +HookEventParam @27 +KillModuleEventHooks @28 +KillModuleServices @29 +KillObjectEventHooks @30 +KillObjectServices @31 +KillObjectThreads @32 +Langpack_SortDuplicates @33 +Langpack_GetDefaultCodePage @34 +Langpack_GetDefaultLocale @35 +Langpack_PcharToTchar @36 +List_Copy @37 +List_Create @38 +List_Destroy @39 +List_Find @40 +List_GetIndex @41 +List_IndexOf @42 +List_Insert @43 +List_InsertPtr @44 +List_ObjCopy @45 +List_Remove @46 +List_RemovePtr @47 +LoadLangPack @48 +LoadLangPackModule @49 +NotifyEventHooks @50 +PathToAbsolute @51 +PathToAbsoluteW @52 +PathToRelative @53 +PathToRelativeW @54 +RegisterModule @55 +ReloadLangpack @56 +ServiceExists @57 +SetExceptionFilter @58 +SetHookDefaultForHookableEvent @59 +Thread_Pop @60 +Thread_Push @61 +Thread_Wait @62 +TranslateA_LP @63 +TranslateDialog_LP @64 +TranslateMenu_LP @65 +TranslateW_LP @66 +Ucs2toUtf8Len @67 +UnhookEvent @68 +UnregisterModule @69 +Utf8Decode @70 +Utf8DecodeCP @71 +Utf8DecodeW @72 +Utf8Encode @73 +Utf8EncodeCP @74 +Utf8EncodeW @75 +forkthread @76 +forkthreadex @77 +ltrim @78 +ltrimp @79 +mir_a2u @80 +mir_a2u_cp @81 +mir_alloc @82 +mir_calloc @83 +mir_free @84 +mir_hash @85 +mir_md5_append @86 +mir_md5_finish @87 +mir_md5_hash @88 +mir_md5_init @89 +mir_realloc @90 +mir_sha1_append @91 +mir_sha1_finish @92 +mir_sha1_hash @93 +mir_sha1_init @94 +mir_strdup @95 +mir_strndup @96 +mir_u2a @97 +mir_u2a_cp @98 +mir_vsnprintf @99 +mir_vsnwprintf @100 +mir_wstrdup @101 +rtrim @102 +wildcmp @103 +rtrimw @104 +mir_snprintf @105 +mir_snwprintf @106 +db_unset @107 +db_free @108 +db_get @109 +db_get_b @110 +db_get_dw @111 +db_get_s @112 +db_get_sa @113 +db_get_w @114 +db_get_wsa @115 +db_set_b @116 +db_set_blob @117 +db_set_dw @118 +db_set_s @119 +db_set_utf @120 +db_set_w @121 +db_set_ws @122 +UnloadCoreModule @123 +Thread_SetName @124 +replaceStr @125 +replaceStrW @126 +db_setCurrent @127 +CmdLine_GetOption @128 +CmdLine_Parse @129 +Utf8CheckString @130 +GetSubscribersCount @131 +NotifyFastHook @132 +db_find_first @133 +db_find_next @134 +Icon_Register @135 +Icon_RegisterT @136 +mir_subclassWindow @137 +mir_callNextSubclass @138 +KillModuleSubclassing @139 +mir_wstrndup @140 +mir_unsubclassWindow @141 +mir_urlEncode @142 +db_event_add @143 +db_event_count @144 +db_event_delete @145 +db_event_first @146 +db_event_firstUnread @147 +db_event_get @148 +db_event_getBlobSize @149 +db_event_getContact @150 +db_event_last @151 +db_event_markRead @152 +db_event_next @153 +db_event_prev @154 +ltrimw @155 +ltrimpw @156 +wildcmpw @157 +wildcmpi @158 +wildcmpiw @159 +mir_base64_encode @160 +mir_base64_decode @161 +ProtoServiceExists @162 +ProtoBroadcastAck @163 +ProtoCallService @164 +db_set_resident @165 +db_set @166 +ProtoConstructor @167 +ProtoDestructor @168 +ProtoCreateService @169 +ProtoCreateServiceParam @170 +ProtoHookEvent @171 +ProtoCreateHookableEvent @172 +ProtoForkThread @173 +ProtoForkThreadEx @174 +json_as_array @175 +json_as_bool @176 +json_as_float @177 +json_as_int @178 +json_as_node @179 +json_as_string @180 +json_as_pstring @181 +json_at @182 +json_cast @183 +json_clear @184 +json_copy @185 +json_delete @186 +json_duplicate @187 +json_empty @188 +json_equal @189 +json_free @190 +json_get @191 +json_merge @192 +json_name @193 +json_new @194 +json_new_a @195 +json_new_b @196 +json_new_f @197 +json_new_i @198 +json_nullify @199 +json_parse @200 +json_pop_back @201 +json_pop_back_at @202 +json_preparse @203 +json_push_back @204 +json_reserve @205 +json_set_a @206 +json_set_b @207 +json_set_f @208 +json_set_i @209 +json_set_n @210 +json_set_name @211 +json_size @212 +json_strip_white_space @213 +json_swap @214 +json_type @215 +json_write @216 +json_write_formatted @217 +mir_subclassWindowFull @218 +ProtoGetAvatarFormat @219 +ProtoGetAvatarExtension @220 +ProtoGetBufferFormat @221 +ProtoGetAvatarFileFormat @222 +mir_createLog @223 +mir_writeLogA @224 +mir_writeLogW @225 +mir_writeLogVA @226 +mir_writeLogVW @227 +bin2hex @228 +bin2hexW @229 +mir_hmac_sha1 @230 +mir_base64_encodebuf @231 +mirstr_allocate @232 +mirstr_free @233 +mirstr_realloc @234 +mirstr_getNil @235 +mirstr_lock @236 +mirstr_release @237 +mirstr_unlock @238 +IsWinVerVistaPlus @239 +IsWinVer7Plus @240 +IsFullScreen @241 +IsWorkstationLocked @242 +IsScreenSaverRunning @243 +ProtoLogA @244 +ProtoLogW @245 +db_get_static @246 +db_get_wstatic @247 +db_get_static_utf @248 +db_mc_isMeta @249 +db_mc_isSub @250 +db_mc_getMeta @251 +db_get_contact @252 +db_mc_getDefault @253 +db_mc_getDefaultNum @254 +db_mc_getSubCount @255 +db_mc_getSub @256 +db_mc_setDefault @257 +db_mc_setDefaultNum @258 +mir_closeLog @259 +db_mc_enable @260 +db_mc_isEnabled @261 +LoadLangPackDescr @262 +PathIsAbsolute @263 +PathIsAbsoluteW @264 +db_mc_notifyDefChange @265 +db_mc_tryMeta @266 +mir_strlen @267 +mir_wstrlen @268 +mir_strcpy @269 +mir_wstrcpy @270 +mir_strncpy @271 +mir_wstrncpy @272 +mir_strcat @273 +mir_wstrcat @274 +mir_strncat @275 +mir_wstrncat @276 +mir_strcmp @277 +mir_strcmpi @278 +mir_wstrcmp @279 +mir_wstrcmpi @280 diff --git a/src/mir_core/src/miranda.cpp b/src/mir_core/src/miranda.cpp new file mode 100644 index 0000000000..ebf4b59956 --- /dev/null +++ b/src/mir_core/src/miranda.cpp @@ -0,0 +1,128 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "commonheaders.h" + +HWND hAPCWindow = NULL; + +int InitPathUtils(void); +void (*RecalculateTime)(void); + +void CheckLogs(); +void InitLogs(); +void UninitLogs(); + +void InitWinver(); +void InitMetaContacts(); + +int hLangpack = 0; +HINSTANCE hInst = 0; + +HANDLE hStackMutex, hThreadQueueEmpty; +DWORD mir_tls = 0; + +///////////////////////////////////////////////////////////////////////////////////////// +// module init + +static LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_USER+1) { + PAPCFUNC pFunc = (PAPCFUNC)wParam; + pFunc((ULONG_PTR)lParam); + return 0; + } + + if (msg == WM_TIMER) + CheckLogs(); + + if (msg == WM_TIMECHANGE && RecalculateTime) + RecalculateTime(); + + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +static void LoadCoreModule(void) +{ + INITCOMMONCONTROLSEX icce = {0}; + icce.dwSize = sizeof(icce); + icce.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES; + InitCommonControlsEx(&icce); + + hAPCWindow = CreateWindowEx(0, _T("ComboLBox"), NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + SetClassLongPtr(hAPCWindow, GCL_STYLE, GetClassLongPtr(hAPCWindow, GCL_STYLE) | CS_DROPSHADOW); + DestroyWindow(hAPCWindow); + hAPCWindow = NULL; + + hAPCWindow = CreateWindowEx(0, _T("STATIC"), NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + SetWindowLongPtr(hAPCWindow, GWLP_WNDPROC, (LONG_PTR)APCWndProc); + SetTimer(hAPCWindow, 1, 1000, NULL); + hStackMutex = CreateMutex(NULL, FALSE, NULL); + hThreadQueueEmpty = CreateEvent(NULL, TRUE, TRUE, NULL); + + #ifdef _WIN64 + HMODULE mirInst = GetModuleHandleA("miranda64.exe"); + #else + HMODULE mirInst = GetModuleHandleA("miranda32.exe"); + #endif + RecalculateTime = (void (*)()) GetProcAddress(mirInst, "RecalculateTime"); + + InitWinver(); + InitPathUtils(); + InitLogs(); + InitialiseModularEngine(); + InitProtocols(); + InitMetaContacts(); +} + +MIR_CORE_DLL(void) UnloadCoreModule(void) +{ + DestroyWindow(hAPCWindow); + CloseHandle(hStackMutex); + CloseHandle(hThreadQueueEmpty); + TlsFree(mir_tls); + + UninitProtocols(); + DestroyModularEngine(); + UninitLogs(); + UnloadLangPackModule(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// entry point + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) { + hInst = hinstDLL; + mir_tls = TlsAlloc(); + LoadCoreModule(); + } + else if (fdwReason == DLL_THREAD_DETACH) { + HANDLE hEvent = TlsGetValue(mir_tls); + if (hEvent) + CloseHandle(hEvent); + } + return TRUE; +} diff --git a/src/mir_core/src/miranda.h b/src/mir_core/src/miranda.h new file mode 100644 index 0000000000..6b85fc2b67 --- /dev/null +++ b/src/mir_core/src/miranda.h @@ -0,0 +1,138 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +extern "C" +{ + MIR_CORE_DLL(int) Langpack_MarkPluginLoaded(PLUGININFOEX* pInfo); + MIR_CORE_DLL(MUUID*) Langpack_LookupUuid(WPARAM wParam); +}; + +void UnloadLangPackModule(void); + +int InitialiseModularEngine(void); +void DestroyModularEngine(void); + +int InitPathUtils(void); + +void InitProtocols(); +void UninitProtocols(); + +extern HINSTANCE hInst; +extern HWND hAPCWindow; +extern HANDLE hStackMutex, hThreadQueueEmpty; +extern MIDatabase *currDb; + +/**** modules.cpp **********************************************************************/ + +struct THookSubscriber +{ + HINSTANCE hOwner; + int type; + union { + struct { + union { + MIRANDAHOOK pfnHook; + MIRANDAHOOKPARAM pfnHookParam; + MIRANDAHOOKOBJ pfnHookObj; + MIRANDAHOOKOBJPARAM pfnHookObjParam; + }; + void* object; + LPARAM lParam; + }; + struct { + HWND hwnd; + UINT message; + }; + }; +}; + +#define HOOK_SECRET_SIGNATURE 0xDEADBABA + +struct THook +{ + char name[ MAXMODULELABELLENGTH ]; + int id; + int subscriberCount; + THookSubscriber* subscriber; + MIRANDAHOOK pfnHook; + DWORD secretSignature; + CRITICAL_SECTION csHook; +}; + +extern LIST pluginListAddr; + +/**** langpack.cpp *********************************************************************/ + +char* LangPackTranslateString(MUUID* pUuid, const char *szEnglish, const int W); +TCHAR* LangPackTranslateStringT(int hLangpack, const TCHAR* tszEnglish); + +/**** options.cpp **********************************************************************/ + +HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR *name); + +/**** subclass.cpp *********************************************************************/ + +/**** threads.cpp **********************************************************************/ + +extern DWORD mir_tls; + +/**** utils.cpp ************************************************************************/ + +void HotkeyToName(TCHAR *buf, int size, BYTE shift, BYTE key); +WORD GetHotkeyValue(INT_PTR idHotkey); + +HBITMAP ConvertIconToBitmap(HICON hIcon, HIMAGELIST hIml, int iconId); + +class StrConvUT +{ +private: + wchar_t* m_body; + +public: + StrConvUT(const char* pSrc) : + m_body(mir_a2u(pSrc)) {} + + ~StrConvUT() { mir_free(m_body); } + operator const wchar_t* () const { return m_body; } +}; + +class StrConvAT +{ +private: + char* m_body; + +public: + StrConvAT(const wchar_t* pSrc) : + m_body(mir_u2a(pSrc)) {} + + ~StrConvAT() { mir_free(m_body); } + operator const char* () const { return m_body; } + operator const wchar_t* () const { return (wchar_t*)m_body; } // type cast to fake the interface definition + operator const LPARAM () const { return (LPARAM)m_body; } +}; + +#define StrConvT(x) StrConvUT(x) +#define StrConvTu(x) x +#define StrConvA(x) StrConvAT(x) +#define StrConvU(x) x diff --git a/src/mir_core/src/modules.cpp b/src/mir_core/src/modules.cpp new file mode 100644 index 0000000000..8b819b17a4 --- /dev/null +++ b/src/mir_core/src/modules.cpp @@ -0,0 +1,662 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +// list of hooks + +static int compareHooks(const THook* p1, const THook* p2) +{ + return strcmp(p1->name, p2->name); +} + +static LIST hooks(50, compareHooks); + +struct THookToMainThreadItem +{ + THook* hook; + HANDLE hDoneEvent; + WPARAM wParam; + LPARAM lParam; + int result; +}; + +// list of services + +struct TService +{ + DWORD nameHash; + HINSTANCE hOwner; + union { + MIRANDASERVICE pfnService; + MIRANDASERVICEPARAM pfnServiceParam; + MIRANDASERVICEOBJ pfnServiceObj; + MIRANDASERVICEOBJPARAM pfnServiceObjParam; + }; + int flags; + LPARAM lParam; + void* object; + char name[1]; +}; + +LIST services(100, NumericKeySortT); + +typedef struct +{ + HANDLE hDoneEvent; + WPARAM wParam; + LPARAM lParam; + int result; + const char *name; +} + TServiceToMainThreadItem; + +// other static variables +static BOOL bServiceMode = FALSE; +static CRITICAL_SECTION csHooks, csServices; +static DWORD mainThreadId; +static int hookId = 1; + +///////////////////////////////////////////////////////////////////////////////////////// + +__forceinline HANDLE getThreadEvent() +{ + HANDLE pData = (HANDLE)TlsGetValue(mir_tls); + if (pData == NULL) { + pData = CreateEvent(NULL, FALSE, FALSE, NULL); + TlsSetValue(mir_tls, pData); + } + return pData; +} + +static int QueueMainThread(PAPCFUNC pFunc, void* pParam, HANDLE hDoneEvent) +{ + int result = PostMessage(hAPCWindow, WM_USER+1, (WPARAM)pFunc, (LPARAM)pParam); // let this get processed in its own time + if (hDoneEvent) + WaitForSingleObject(hDoneEvent, INFINITE); + + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +// HOOKS + +MIR_CORE_DLL(HANDLE) CreateHookableEvent(const char *name) +{ + if (name == NULL) + return NULL; + + mir_cslock lck(csHooks); + + int idx; + if ((idx = hooks.getIndex((THook*)name)) != -1) + return hooks[idx]; + + THook* newItem = (THook*)mir_alloc(sizeof(THook)); + strncpy(newItem->name, name, sizeof(newItem->name)); newItem->name[ MAXMODULELABELLENGTH-1 ] = 0; + newItem->id = hookId++; + newItem->subscriberCount = 0; + newItem->subscriber = NULL; + newItem->pfnHook = NULL; + newItem->secretSignature = HOOK_SECRET_SIGNATURE; + InitializeCriticalSection(&newItem->csHook); + hooks.insert(newItem); + return (HANDLE)newItem; +} + +MIR_CORE_DLL(int) DestroyHookableEvent(HANDLE hEvent) +{ + if (hEvent == NULL) + return 1; + + mir_cslock lck(csHooks); + + int idx; + if ((idx = hooks.getIndex((THook*)hEvent)) == -1) + return 1; + + THook* p = hooks[idx]; + p->secretSignature = 0; + if (p->subscriberCount) { + mir_free(p->subscriber); + p->subscriber = NULL; + p->subscriberCount = 0; + } + hooks.remove(idx); + DeleteCriticalSection(&p->csHook); + mir_free(p); + return 0; +} + +MIR_CORE_DLL(int) SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook) +{ + THook* p = (THook*)hEvent; + + mir_cslock lck(csHooks); + if (hooks.getIndex(p) != -1) + p->pfnHook = pfnHook; + return 0; +} + +MIR_CORE_DLL(int) CallPluginEventHook(HINSTANCE hInst, HANDLE hEvent, WPARAM wParam, LPARAM lParam) +{ + THook* p = (THook*)hEvent; + if (p == NULL || hInst == NULL) + return -1; + + mir_cslock lck(p->csHook); + for (int i = 0; i < p->subscriberCount; i++) { + THookSubscriber* s = &p->subscriber[i]; + if (s->hOwner != hInst) + continue; + + int returnVal; + switch (s->type) { + case 1: returnVal = s->pfnHook(wParam, lParam); break; + case 2: returnVal = s->pfnHookParam(wParam, lParam, s->lParam); break; + case 3: returnVal = s->pfnHookObj(s->object, wParam, lParam); break; + case 4: returnVal = s->pfnHookObjParam(s->object, wParam, lParam, s->lParam); break; + case 5: returnVal = SendMessage(s->hwnd, s->message, wParam, lParam); break; + default: continue; + } + if (returnVal) + return returnVal; + } + + if (p->subscriberCount == 0 && p->pfnHook != 0) + return p->pfnHook(wParam, lParam); + + return 0; +} + +static int CallHookSubscribers(THook* p, WPARAM wParam, LPARAM lParam) +{ + if (p == NULL) + return -1; + + mir_cslock lck(p->csHook); + + // NOTE: We've got the critical section while all this lot are called. That's mostly safe, though. + for (int i = 0; i < p->subscriberCount; i++) { + THookSubscriber* s = &p->subscriber[i]; + + int returnVal; + switch (s->type) { + case 1: returnVal = s->pfnHook(wParam, lParam); break; + case 2: returnVal = s->pfnHookParam(wParam, lParam, s->lParam); break; + case 3: returnVal = s->pfnHookObj(s->object, wParam, lParam); break; + case 4: returnVal = s->pfnHookObjParam(s->object, wParam, lParam, s->lParam); break; + case 5: returnVal = SendMessage(s->hwnd, s->message, wParam, lParam); break; + default: continue; + } + if (returnVal) + return returnVal; + } + + // call the default hook if any + if (p->pfnHook != 0) + return p->pfnHook(wParam, lParam); + + return 0; +} + +enum { hookOk, hookEmpty, hookInvalid }; + +__forceinline int checkHook(THook* p) +{ + if (p == NULL) + return hookInvalid; + + int ret; + __try + { + if (p->secretSignature != HOOK_SECRET_SIGNATURE) + ret = hookInvalid; + else if (p->subscriberCount == 0 && p->pfnHook == NULL) + ret = hookEmpty; + else + ret = hookOk; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + ret = hookInvalid; + } + + return ret; +} + +static void CALLBACK HookToMainAPCFunc(ULONG_PTR dwParam) +{ + THookToMainThreadItem* item = (THookToMainThreadItem*)dwParam; + item->result = CallHookSubscribers(item->hook, item->wParam, item->lParam); + SetEvent(item->hDoneEvent); +} + +MIR_CORE_DLL(int) NotifyEventHooks(HANDLE hEvent, WPARAM wParam, LPARAM lParam) +{ + switch ( checkHook((THook*)hEvent)) { + case hookInvalid: return -1; + case hookEmpty: return 0; + } + + if ( GetCurrentThreadId() == mainThreadId) + return CallHookSubscribers((THook*)hEvent, wParam, lParam); + + THookToMainThreadItem item; + item.hDoneEvent = getThreadEvent(); + item.hook = (THook*)hEvent; + item.wParam = wParam; + item.lParam = lParam; + QueueMainThread(HookToMainAPCFunc, &item, item.hDoneEvent); + return item.result; +} + +MIR_CORE_DLL(int) NotifyFastHook(HANDLE hEvent, WPARAM wParam, LPARAM lParam) +{ + switch ( checkHook((THook*)hEvent)) { + case hookInvalid: return -1; + case hookEmpty: return 0; + } + + return CallHookSubscribers((THook*)hEvent, wParam, lParam); +} + +extern "C" MIR_CORE_DLL(int) GetSubscribersCount(THook* pHook) +{ + switch ( checkHook(pHook)) { + case hookInvalid: + case hookEmpty: return 0; + } + return pHook->subscriberCount; +} + +static HANDLE HookEventInt(int type, const char *name, MIRANDAHOOK hookProc, void* object, LPARAM lParam) +{ + mir_cslock lck(csHooks); + + int idx; + if ((idx = hooks.getIndex((THook*)name)) == -1) + return NULL; + + THook* p = hooks[ idx ]; + p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1)); + p->subscriber[ p->subscriberCount ].type = type; + p->subscriber[ p->subscriberCount ].pfnHook = hookProc; + p->subscriber[ p->subscriberCount ].object = object; + p->subscriber[ p->subscriberCount ].lParam = lParam; + p->subscriber[ p->subscriberCount ].hOwner = GetInstByAddress(hookProc); + p->subscriberCount++; + + return (HANDLE)((p->id << 16) | p->subscriberCount); +} + +MIR_CORE_DLL(HANDLE) HookEvent(const char *name, MIRANDAHOOK hookProc) +{ + return HookEventInt(1, name, hookProc, 0, 0); +} + +MIR_CORE_DLL(HANDLE) HookEventParam(const char *name, MIRANDAHOOKPARAM hookProc, LPARAM lParam) +{ + return HookEventInt(2, name, (MIRANDAHOOK)hookProc, 0, lParam); +} + +MIR_CORE_DLL(HANDLE) HookEventObj(const char *name, MIRANDAHOOKOBJ hookProc, void* object) +{ + return HookEventInt(3, name, (MIRANDAHOOK)hookProc, object, 0); +} + +MIR_CORE_DLL(HANDLE) HookEventObjParam(const char *name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam) +{ + return HookEventInt(4, name, (MIRANDAHOOK)hookProc, object, lParam); +} + +MIR_CORE_DLL(HANDLE) HookEventMessage(const char *name, HWND hwnd, UINT message) +{ + mir_cslock lck(csHooks); + + int idx; + if ((idx = hooks.getIndex((THook*)name)) == -1) + return NULL; + + THook* p = hooks[ idx ]; + p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1)); + p->subscriber[ p->subscriberCount ].type = 5; + p->subscriber[ p->subscriberCount ].hwnd = hwnd; + p->subscriber[ p->subscriberCount ].message = message; + p->subscriberCount++; + return (HANDLE)((p->id << 16) | p->subscriberCount); +} + +MIR_CORE_DLL(int) UnhookEvent(HANDLE hHook) +{ + if (hHook == NULL) + return 0; + + int hookId = (int)hHook >> 16; + int subscriberId = ((int)hHook & 0xFFFF) - 1; + + mir_cslock lck(csHooks); + + THook* p = NULL; + for (int i = 0; i < hooks.getCount(); i++) + if (hooks[i]->id == hookId) { + p = hooks[i]; + break; + } + + if (p == NULL) + return 1; + + if (subscriberId >= p->subscriberCount || subscriberId < 0) + return 1; + + p->subscriber[subscriberId].type = 0; + p->subscriber[subscriberId].pfnHook = NULL; + p->subscriber[subscriberId].hOwner = NULL; + while (p->subscriberCount && p->subscriber[p->subscriberCount-1].type == 0) + p->subscriberCount--; + if (p->subscriberCount == 0) { + mir_free(p->subscriber); + p->subscriber = NULL; + } + return 0; +} + +MIR_CORE_DLL(void) KillModuleEventHooks(HINSTANCE hInst) +{ + mir_cslock lck(csHooks); + + for (int i = hooks.getCount()-1; i >= 0; i--) { + if (hooks[i]->subscriberCount == 0) + continue; + + for (int j = hooks[i]->subscriberCount-1; j >= 0; j--) { + if (hooks[i]->subscriber[j].hOwner != hInst) + continue; + + char szModuleName[ MAX_PATH ]; + GetModuleFileNameA(hooks[i]->subscriber[j].hOwner, szModuleName, sizeof(szModuleName)); + UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1)); + if (hooks[i]->subscriberCount == 0) + break; + } + } +} + +MIR_CORE_DLL(void) KillObjectEventHooks(void* pObject) +{ + mir_cslock lck(csHooks); + + for (int i = hooks.getCount()-1; i >= 0; i--) { + if (hooks[i]->subscriberCount == 0) + continue; + + for (int j = hooks[i]->subscriberCount-1; j >= 0; j--) { + if (hooks[i]->subscriber[j].object == pObject) { + UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1)); + if (hooks[i]->subscriberCount == 0) + break; + } + } + } +} + +static void DestroyHooks() +{ + mir_cslock lck(csHooks); + + for (int i=0; i < hooks.getCount(); i++) { + THook* p = hooks[i]; + if (p->subscriberCount) + mir_free(p->subscriber); + DeleteCriticalSection(&p->csHook); + mir_free(p); + } +} + +/////////////////////SERVICES + +static __inline TService* FindServiceByName(const char *name) +{ + unsigned hash = mir_hashstr(name); + return services.find((TService*)&hash); +} + +static HANDLE CreateServiceInt(int type, const char *name, MIRANDASERVICE serviceProc, void* object, LPARAM lParam) +{ + if (name == NULL) + return NULL; + + TService tmp; + tmp.nameHash = mir_hashstr(name); + + mir_cslock lck(csServices); + + if (services.getIndex(&tmp) != -1) + return NULL; + + TService* p = (TService*)mir_alloc(sizeof(*p) + strlen(name)); + strcpy(p->name, name); + p->nameHash = tmp.nameHash; + p->pfnService = serviceProc; + p->hOwner = GetInstByAddress(serviceProc); + p->flags = type; + p->lParam = lParam; + p->object = object; + services.insert(p); + + return (HANDLE)tmp.nameHash; +} + +MIR_CORE_DLL(HANDLE) CreateServiceFunction(const char *name, MIRANDASERVICE serviceProc) +{ + return CreateServiceInt(0, name, serviceProc, 0, 0); +} + +MIR_CORE_DLL(HANDLE) CreateServiceFunctionParam(const char *name, MIRANDASERVICEPARAM serviceProc, LPARAM lParam) +{ + return CreateServiceInt(1, name, (MIRANDASERVICE)serviceProc, 0, lParam); +} + +MIR_CORE_DLL(HANDLE) CreateServiceFunctionObj(const char *name, MIRANDASERVICEOBJ serviceProc, void* object) +{ + return CreateServiceInt(2, name, (MIRANDASERVICE)serviceProc, object, 0); +} + +MIR_CORE_DLL(HANDLE) CreateServiceFunctionObjParam(const char *name, MIRANDASERVICEOBJPARAM serviceProc, void* object, LPARAM lParam) +{ + return CreateServiceInt(3, name, (MIRANDASERVICE)serviceProc, object, lParam); +} + +MIR_CORE_DLL(int) DestroyServiceFunction(HANDLE hService) +{ + mir_cslock lck(csServices); + + int idx; + if ((idx = services.getIndex((TService*)&hService)) != -1) { + mir_free(services[idx]); + services.remove(idx); + } + + return 0; +} + +MIR_CORE_DLL(int) ServiceExists(const char *name) +{ + if (name == NULL) + return FALSE; + + mir_cslock lck(csServices); + return FindServiceByName(name) != NULL; +} + +MIR_CORE_DLL(INT_PTR) CallService(const char *name, WPARAM wParam, LPARAM lParam) +{ + if (name == NULL) + return CALLSERVICE_NOTFOUND; + + TService *pService; + { + mir_cslock lck(csServices); + if ((pService = FindServiceByName(name)) == NULL) + return CALLSERVICE_NOTFOUND; + } + + MIRANDASERVICE pfnService = pService->pfnService; + int flags = pService->flags; + LPARAM fnParam = pService->lParam; + void* object = pService->object; + switch(flags) { + case 1: return ((MIRANDASERVICEPARAM)pfnService)(wParam, lParam, fnParam); + case 2: return ((MIRANDASERVICEOBJ)pfnService)(object, wParam, lParam); + case 3: return ((MIRANDASERVICEOBJPARAM)pfnService)(object, wParam, lParam, fnParam); + default: return pfnService(wParam, lParam); +} } + +static void CALLBACK CallServiceToMainAPCFunc(ULONG_PTR dwParam) +{ + TServiceToMainThreadItem *item = (TServiceToMainThreadItem*) dwParam; + item->result = CallService(item->name, item->wParam, item->lParam); + SetEvent(item->hDoneEvent); +} + +MIR_CORE_DLL(INT_PTR) CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam) +{ + if (name == NULL) + return CALLSERVICE_NOTFOUND; + + // the service is looked up within the main thread, since the time it takes + // for the APC queue to clear the service being called maybe removed. + // even thou it may exists before the call, the critsec can't be locked between calls. + if (GetCurrentThreadId() == mainThreadId) + return CallService(name, wParam, lParam); + + TServiceToMainThreadItem item; + item.wParam = wParam; + item.lParam = lParam; + item.name = name; + item.hDoneEvent = getThreadEvent(); + QueueMainThread(CallServiceToMainAPCFunc, &item, item.hDoneEvent); + return item.result; +} + +MIR_CORE_DLL(int) CallFunctionAsync(void (__stdcall *func)(void *), void *arg) +{ + if (GetCurrentThreadId() == mainThreadId) + func(arg); + else + QueueMainThread((PAPCFUNC)func, arg, 0); + return 0; +} + +MIR_CORE_DLL(void) KillModuleServices(HINSTANCE hInst) +{ + mir_cslock lck(csServices); + + for (int i = services.getCount()-1; i >= 0; i--) { + if (services[i]->hOwner == hInst) { + char szModuleName[ MAX_PATH ]; + GetModuleFileNameA(services[i]->hOwner, szModuleName, sizeof(szModuleName)); + DestroyServiceFunction((HANDLE)services[i]->nameHash); + } + } +} + +MIR_CORE_DLL(void) KillObjectServices(void* pObject) +{ + mir_cslock lck(csServices); + + for (int i = services.getCount()-1; i >= 0; i--) + if (services[i]->object == pObject) + DestroyServiceFunction((HANDLE)services[i]->nameHash); +} + +static void DestroyServices() +{ + mir_cslock lck(csServices); + + for (int j=0; j < services.getCount(); j++) + mir_free(services[j]); +} + +/////////////////////////////////////////////////////////////////////////////// + +static int sttComparePlugins(const HINSTANCE__* p1, const HINSTANCE__* p2) +{ + if (p1 == p2) + return 0; + + return (p1 < p2) ? -1 : 1; +} + +LIST pluginListAddr(10, sttComparePlugins); + +MIR_CORE_DLL(void) RegisterModule(HINSTANCE hInst) +{ + pluginListAddr.insert(hInst); +} + +MIR_CORE_DLL(void) UnregisterModule(HINSTANCE hInst) +{ + pluginListAddr.remove(hInst); +} + +MIR_CORE_DLL(HINSTANCE) GetInstByAddress(void* codePtr) +{ + if (pluginListAddr.getCount() == 0) + return NULL; + + int idx; + List_GetIndex((SortedList*)&pluginListAddr, codePtr, &idx); + if (idx > 0) + idx--; + + HINSTANCE result = pluginListAddr[idx]; + if (result < hInst && codePtr > hInst) + result = hInst; + else if (idx == 0 && codePtr < (void*)result) + result = NULL; + + return result; +} + +/////////////////////////////////////////////////////////////////////////////// + +int InitialiseModularEngine(void) +{ + InitializeCriticalSection(&csHooks); + InitializeCriticalSection(&csServices); + + mainThreadId = GetCurrentThreadId(); + return 0; +} + +void DestroyModularEngine(void) +{ + DestroyHooks(); + DeleteCriticalSection(&csHooks); + + DestroyServices(); + DeleteCriticalSection(&csServices); +} diff --git a/src/mir_core/src/mstring.cpp b/src/mir_core/src/mstring.cpp new file mode 100644 index 0000000000..8d071b61c1 --- /dev/null +++ b/src/mir_core/src/mstring.cpp @@ -0,0 +1,118 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// CMBaseString + +class CNilMStringData : public CMStringData +{ +public: + CNilMStringData(); + +public: + wchar_t achNil[2]; +}; + +CNilMStringData::CNilMStringData() +{ + nRefs = 2; // Never gets freed + nDataLength = 0; + nAllocLength = 0; + achNil[0] = 0; + achNil[1] = 0; +} + +static CNilMStringData m_nil; + +///////////////////////////////////////////////////////////////////////////////////////// +// CMBaseString + +MIR_CORE_DLL(CMStringData*) mirstr_allocate(int nChars, int nCharSize) +{ + nChars++; // nil char + size_t nDataBytes = nCharSize * nChars; + size_t nTotalSize = nDataBytes + sizeof(CMStringData); + + CMStringData *pData = static_cast(malloc(nTotalSize)); + if (pData == NULL) + return NULL; + + pData->nRefs = 1; + pData->nAllocLength = nChars - 1; + pData->nDataLength = 0; + return pData; +} + +MIR_CORE_DLL(void) mirstr_free(CMStringData *pData) +{ + free(pData); +} + +MIR_CORE_DLL(CMStringData*) mirstr_realloc(CMStringData* pData, int nChars, int nCharSize) +{ + nChars++; // nil char + ULONG nDataBytes = nCharSize * nChars; + ULONG nTotalSize = nDataBytes + sizeof(CMStringData); + + CMStringData *pNewData = static_cast(realloc(pData, nTotalSize)); + if (pNewData == NULL) + return NULL; + + pNewData->nAllocLength = nChars - 1; + return pNewData; +} + +MIR_CORE_DLL(CMStringData*) mirstr_getNil() +{ + m_nil.AddRef(); + return &m_nil; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CMStringData + +MIR_CORE_DLL(void) mirstr_lock(CMStringData* pThis) +{ + pThis->nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary + if (pThis->nRefs == 0) + pThis->nRefs = -1; +} + +MIR_CORE_DLL(void) mirstr_release(CMStringData* pThis) +{ + if (InterlockedDecrement(&pThis->nRefs) <= 0) + mirstr_free(pThis); +} + +MIR_CORE_DLL(void) mirstr_unlock(CMStringData* pThis) +{ + if (pThis->IsLocked()) + { + pThis->nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary + if (pThis->nRefs == 0) + pThis->nRefs = 1; + } +} diff --git a/src/mir_core/src/path.cpp b/src/mir_core/src/path.cpp new file mode 100644 index 0000000000..ab0ee26b14 --- /dev/null +++ b/src/mir_core/src/path.cpp @@ -0,0 +1,210 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +static char szMirandaPath[MAX_PATH]; +static WCHAR szMirandaPathW[MAX_PATH]; + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(int) PathIsAbsolute(const char *path) +{ + if (path && strlen(path) > 2) + if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) + return 1; + return 0; +} + +MIR_CORE_DLL(int) PathToRelative(const char *pSrc, char *pOut, const char *pBase) +{ + if (!pSrc || !pSrc[0] || strlen(pSrc) > MAX_PATH) + return 0; + + if (!PathIsAbsolute(pSrc)) + strncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); + else { + if (pBase == NULL) + pBase = szMirandaPath; + + size_t cbBaseLen = strlen(pBase); + if (!strnicmp(pSrc, pBase, cbBaseLen)) + strncpy_s(pOut, MAX_PATH, pSrc + cbBaseLen, _TRUNCATE); + else + strncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); + } + + return (int)strlen(pOut); +} + +MIR_CORE_DLL(int) PathToAbsolute(const char *pSrc, char *pOut, const char *base) +{ + if (!pSrc || !pSrc[0] || strlen(pSrc) > MAX_PATH) { + *pOut = 0; + return 0; + } + + char buf[MAX_PATH]; + if (pSrc[0] < ' ') + strncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); + + if (PathIsAbsolute(pSrc)) + return GetFullPathNameA(pSrc, MAX_PATH, pOut, NULL); + + if (base == NULL) + base = szMirandaPath; + + if (pSrc[0] == '\\') + pSrc++; + mir_snprintf(buf, SIZEOF(buf), "%s%s", base, pSrc); + return GetFullPathNameA(buf, SIZEOF(buf), pOut, NULL); +} + +MIR_CORE_DLL(void) CreatePathToFile(char *szFilePath) +{ + char *pszLastBackslash = strrchr(szFilePath, '\\'); + if (pszLastBackslash == NULL) + return; + + *pszLastBackslash = '\0'; + CreateDirectoryTree(szFilePath); + *pszLastBackslash = '\\'; +} + +MIR_CORE_DLL(int) CreateDirectoryTree(const char *szDir) +{ + char szTestDir[MAX_PATH]; + mir_strncpy(szTestDir, szDir, SIZEOF(szTestDir)); + + DWORD dwAttributes = GetFileAttributesA(szTestDir); + if (dwAttributes != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) + return 0; + + char *pszLastBackslash = strrchr(szTestDir, '\\'); + if (pszLastBackslash == NULL) + return 0; + + *pszLastBackslash = '\0'; + CreateDirectoryTree(szTestDir); + *pszLastBackslash = '\\'; + return (CreateDirectoryA(szTestDir, NULL) == 0) ? GetLastError() : 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(int) PathIsAbsoluteW(const WCHAR *path) +{ + if (path && wcslen(path) > 2) + if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) + return 1; + return 0; +} + +MIR_CORE_DLL(int) PathToRelativeW(const WCHAR *pSrc, WCHAR *pOut, const WCHAR *pBase) +{ + if (!pSrc || !pSrc[0] || wcslen(pSrc) > MAX_PATH) + return 0; + + if (!PathIsAbsoluteW(pSrc)) + wcsncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); + else { + if (pBase == NULL) + pBase = szMirandaPathW; + + size_t cbBaseLen = wcslen(pBase); + if (!wcsnicmp(pSrc, pBase, cbBaseLen)) + wcsncpy_s(pOut, MAX_PATH, pSrc + cbBaseLen, _TRUNCATE); + else + wcsncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); + } + return (int)wcslen(pOut); +} + +MIR_CORE_DLL(int) PathToAbsoluteW(const WCHAR *pSrc, WCHAR *pOut, const WCHAR *base) +{ + if (!pSrc || !pSrc[0] || wcslen(pSrc) > MAX_PATH) { + *pOut = 0; + return 0; + } + + WCHAR buf[MAX_PATH]; + if (pSrc[0] < ' ') + return mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + + if (PathIsAbsoluteW(pSrc)) + return GetFullPathName(pSrc, MAX_PATH, pOut, NULL); + + if (base == NULL) + base = szMirandaPathW; + + if (pSrc[0] == '\\') + pSrc++; + + mir_sntprintf(buf, MAX_PATH, _T("%s%s"), base, pSrc); + return GetFullPathName(buf, MAX_PATH, pOut, NULL); +} + +MIR_CORE_DLL(void) CreatePathToFileW(WCHAR *wszFilePath) +{ + WCHAR *pszLastBackslash = wcsrchr(wszFilePath, '\\'); + if (pszLastBackslash == NULL) + return; + + *pszLastBackslash = '\0'; + CreateDirectoryTreeW(wszFilePath); + *pszLastBackslash = '\\'; +} + +MIR_CORE_DLL(int) CreateDirectoryTreeW(const WCHAR *szDir) +{ + WCHAR szTestDir[MAX_PATH]; + mir_wstrncpy(szTestDir, szDir, SIZEOF(szTestDir)); + + DWORD dwAttributes = GetFileAttributesW(szTestDir); + if (dwAttributes != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) + return 0; + + WCHAR *pszLastBackslash = wcsrchr(szTestDir, '\\'); + if (pszLastBackslash == NULL) + return 0; + + *pszLastBackslash = '\0'; + CreateDirectoryTreeW(szTestDir); + *pszLastBackslash = '\\'; + return (CreateDirectoryW(szTestDir, NULL) == 0) ? GetLastError() : 0; +} + +int InitPathUtils(void) +{ + GetModuleFileNameA(hInst, szMirandaPath, SIZEOF(szMirandaPath)); + char *p = strrchr(szMirandaPath, '\\'); + if (p) + p[1] = 0; + + GetModuleFileNameW(hInst, szMirandaPathW, SIZEOF(szMirandaPathW)); + WCHAR *tp = wcsrchr(szMirandaPathW, '\\'); + if (tp) + tp[1] = 0; + return 0; +} diff --git a/src/mir_core/src/protos.cpp b/src/mir_core/src/protos.cpp new file mode 100644 index 0000000000..7015647bc3 --- /dev/null +++ b/src/mir_core/src/protos.cpp @@ -0,0 +1,264 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-14 Miranda NG project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +#include +#include +#include +#include + +static HANDLE hAckEvent; + +void InitProtocols() +{ + hAckEvent = CreateHookableEvent(ME_PROTO_ACK); +} + +void UninitProtocols() +{ + if (hAckEvent) { + DestroyHookableEvent(hAckEvent); + hAckEvent = NULL; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(void) ProtoLogA(struct PROTO_INTERFACE *pThis, LPCSTR szFormat, va_list args) +{ + char buf[4096]; + int res = _vsnprintf(buf, sizeof(buf), szFormat, args); + CallService(MS_NETLIB_LOG, (WPARAM)pThis->m_hNetlibUser, (LPARAM)((res != -1) ? buf : CMStringA().FormatV(szFormat, args))); +} + +MIR_CORE_DLL(void) ProtoLogW(struct PROTO_INTERFACE *pThis, LPCWSTR wszFormat, va_list args) +{ + WCHAR buf[4096]; + int res = _vsnwprintf(buf, SIZEOF(buf), wszFormat, args); + CallService(MS_NETLIB_LOGW, (WPARAM)pThis->m_hNetlibUser, (LPARAM)((res != -1) ? buf : CMStringW().FormatV(wszFormat, args))); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(INT_PTR) ProtoBroadcastAck(const char *szModule, MCONTACT hContact, int type, int result, HANDLE hProcess, LPARAM lParam) +{ + if (type == ACKTYPE_AVATAR && hProcess) { + PROTO_AVATAR_INFORMATION* ai = (PROTO_AVATAR_INFORMATION*)hProcess; + if (ai->cbSize == sizeof(PROTO_AVATAR_INFORMATION)) { + PROTO_AVATAR_INFORMATIONW aiw = { sizeof(aiw), ai->hContact, ai->format }; + MultiByteToWideChar(CP_ACP, 0, ai->filename, -1, aiw.filename, SIZEOF(aiw.filename)); + + hProcess = &aiw; + ACKDATA ack = { sizeof(ACKDATA), szModule, hContact, type, result, hProcess, lParam }; + return NotifyEventHooks(hAckEvent, 0, (LPARAM)&ack); + } + } + + ACKDATA ack = { sizeof(ACKDATA), szModule, hContact, type, result, hProcess, lParam }; + return NotifyEventHooks(hAckEvent, 0, (LPARAM)&ack); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(INT_PTR) ProtoCallService(const char *szModule, const char *szService, WPARAM wParam, LPARAM lParam) +{ + if (szModule == NULL || szService == NULL) + return false; + + char str[MAXMODULELABELLENGTH * 2]; + strncpy_s(str, szModule, _TRUNCATE); + strncat_s(str, szService, _TRUNCATE); + return CallService(str, wParam, lParam); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(int) ProtoServiceExists(const char *szModule, const char *szService) +{ + if (szModule == NULL || szService == NULL) + return false; + + char str[MAXMODULELABELLENGTH * 2]; + strncpy_s(str, szModule, _TRUNCATE); + strncat_s(str, szService, _TRUNCATE); + return ServiceExists(str); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(void) ProtoConstructor(PROTO_INTERFACE *pThis, LPCSTR pszModuleName, LPCTSTR ptszUserName) +{ + pThis->m_iVersion = 2; + pThis->m_iStatus = pThis->m_iDesiredStatus = ID_STATUS_OFFLINE; + pThis->m_szModuleName = mir_strdup(pszModuleName); + pThis->m_hProtoIcon = (HANDLE)CallService("Skin2/Icons/IsManaged", (WPARAM)LoadSkinnedProtoIcon(pszModuleName, ID_STATUS_ONLINE), 0); + pThis->m_tszUserName = mir_tstrdup(ptszUserName); +} + +MIR_CORE_DLL(void) ProtoDestructor(PROTO_INTERFACE *pThis) +{ + mir_free(pThis->m_szModuleName); + mir_free(pThis->m_tszUserName); +} + +MIR_CORE_DLL(void) ProtoCreateService(PROTO_INTERFACE *pThis, const char* szService, ProtoServiceFunc serviceProc) +{ + char str[MAXMODULELABELLENGTH * 2]; + strncpy_s(str, pThis->m_szModuleName, _TRUNCATE); + strncat_s(str, szService, _TRUNCATE); + ::CreateServiceFunctionObj(str, (MIRANDASERVICEOBJ)*(void**)&serviceProc, pThis); +} + +MIR_CORE_DLL(void) ProtoCreateServiceParam(PROTO_INTERFACE *pThis, const char* szService, ProtoServiceFuncParam serviceProc, LPARAM lParam) +{ + char str[MAXMODULELABELLENGTH * 2]; + strncpy_s(str, pThis->m_szModuleName, _TRUNCATE); + strncat_s(str, szService, _TRUNCATE); + ::CreateServiceFunctionObjParam(str, (MIRANDASERVICEOBJPARAM)*(void**)&serviceProc, pThis, lParam); +} + +MIR_CORE_DLL(void) ProtoHookEvent(PROTO_INTERFACE *pThis, const char* szEvent, ProtoEventFunc handler) +{ + ::HookEventObj(szEvent, (MIRANDAHOOKOBJ)*(void**)&handler, pThis); +} + +MIR_CORE_DLL(HANDLE) ProtoCreateHookableEvent(PROTO_INTERFACE *pThis, const char* szName) +{ + char str[MAXMODULELABELLENGTH * 2]; + strncpy_s(str, pThis->m_szModuleName, _TRUNCATE); + strncat_s(str, szName, _TRUNCATE); + return CreateHookableEvent(str); +} + +MIR_CORE_DLL(void) ProtoForkThread(PROTO_INTERFACE *pThis, ProtoThreadFunc pFunc, void *param) +{ + UINT threadID; + CloseHandle((HANDLE)::mir_forkthreadowner((pThreadFuncOwner)*(void**)&pFunc, pThis, param, &threadID)); +} + +MIR_CORE_DLL(HANDLE) ProtoForkThreadEx(PROTO_INTERFACE *pThis, ProtoThreadFunc pFunc, void *param, UINT* threadID) +{ + UINT lthreadID; + return (HANDLE)::mir_forkthreadowner((pThreadFuncOwner)*(void**)&pFunc, pThis, param, threadID ? threadID : <hreadID); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(LPCTSTR) ProtoGetAvatarExtension(int format) +{ + if (format == PA_FORMAT_PNG) + return _T(".png"); + if (format == PA_FORMAT_JPEG) + return _T(".jpg"); + if (format == PA_FORMAT_ICON) + return _T(".ico"); + if (format == PA_FORMAT_BMP) + return _T(".bmp"); + if (format == PA_FORMAT_GIF) + return _T(".gif"); + if (format == PA_FORMAT_SWF) + return _T(".swf"); + if (format == PA_FORMAT_XML) + return _T(".xml"); + + return _T(""); +} + +MIR_CORE_DLL(int) ProtoGetAvatarFormat(const TCHAR *ptszFileName) +{ + if (ptszFileName == NULL) + return PA_FORMAT_UNKNOWN; + + const TCHAR *ptszExt = _tcsrchr(ptszFileName, '.'); + if (ptszExt == NULL) + return PA_FORMAT_UNKNOWN; + + if (!_tcsicmp(ptszExt, _T(".png"))) + return PA_FORMAT_PNG; + + if (!_tcsicmp(ptszExt, _T(".jpg")) || !_tcsicmp(ptszExt, _T(".jpeg"))) + return PA_FORMAT_JPEG; + + if (!_tcsicmp(ptszExt, _T(".ico"))) + return PA_FORMAT_ICON; + + if (!_tcsicmp(ptszExt, _T(".bmp")) || !_tcsicmp(ptszExt, _T(".rle"))) + return PA_FORMAT_BMP; + + if (!_tcsicmp(ptszExt, _T(".gif"))) + return PA_FORMAT_GIF; + + if (!_tcsicmp(ptszExt, _T(".swf"))) + return PA_FORMAT_SWF; + + if (!_tcsicmp(ptszExt, _T(".xml"))) + return PA_FORMAT_XML; + + return PA_FORMAT_UNKNOWN; +} + +MIR_CORE_DLL(int) ProtoGetBufferFormat(const void *pBuffer, const TCHAR **ptszExtension) +{ + if (!memcmp(pBuffer, "%PNG", 4)) { + if (ptszExtension) *ptszExtension = _T(".png"); + return PA_FORMAT_PNG; + } + + if (!memcmp(pBuffer, "GIF8", 4)) { + if (ptszExtension) *ptszExtension = _T(".gif"); + return PA_FORMAT_GIF; + } + + if (!memicmp(pBuffer, "> (32-(n)))) + +static void shaHashBlock(mir_sha1_ctx *ctx) +{ + int t; + unsigned long A, B, C, D, E, TEMP; + + for (t = 16; t <= 79; t++) + ctx->W[t] = + SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); + + A = ctx->H[0]; + B = ctx->H[1]; + C = ctx->H[2]; + D = ctx->H[3]; + E = ctx->H[4]; + + for (t = 0; t <= 19; t++) { + TEMP = SHA_ROTL(A, 5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 20; t <= 39; t++) { + TEMP = SHA_ROTL(A, 5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 40; t <= 59; t++) { + TEMP = SHA_ROTL(A, 5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 60; t <= 79; t++) { + TEMP = SHA_ROTL(A, 5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + + ctx->H[0] += A; + ctx->H[1] += B; + ctx->H[2] += C; + ctx->H[3] += D; + ctx->H[4] += E; +} + +MIR_CORE_DLL(void) mir_sha1_init(mir_sha1_ctx *ctx) +{ + ctx->lenW = 0; + ctx->sizeHi = ctx->sizeLo = 0; + + /* Initialize H with the magic constants (see FIPS180 for constants) + */ + ctx->H[0] = 0x67452301L; + ctx->H[1] = 0xefcdab89L; + ctx->H[2] = 0x98badcfeL; + ctx->H[3] = 0x10325476L; + ctx->H[4] = 0xc3d2e1f0L; + + for (int i = 0; i < 80; i++) + ctx->W[i] = 0; +} + +MIR_CORE_DLL(void) mir_sha1_append(mir_sha1_ctx *ctx, const BYTE *dataIn, int len) +{ + /* Read the data into W and process blocks as they get full + */ + for (int i = 0; i < len; i++) { + ctx->W[ctx->lenW / 4] <<= 8; + ctx->W[ctx->lenW / 4] |= (unsigned long)dataIn[i]; + if ((++ctx->lenW) % 64 == 0) { + shaHashBlock(ctx); + ctx->lenW = 0; + } + ctx->sizeLo += 8; + ctx->sizeHi += (ctx->sizeLo < 8); + } +} + +MIR_CORE_DLL(void) mir_sha1_finish(mir_sha1_ctx *ctx, BYTE hashout[20]) +{ + unsigned char pad0x80 = 0x80; + unsigned char pad0x00 = 0x00; + unsigned char padlen[8]; + int i; + + /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length + */ + padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); + padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); + padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); + padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); + padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); + padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); + padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); + padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); + mir_sha1_append(ctx, &pad0x80, 1); + while (ctx->lenW != 56) + mir_sha1_append(ctx, &pad0x00, 1); + mir_sha1_append(ctx, padlen, 8); + + /* Output hash + */ + for (i = 0; i < 20; i++) { + hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); + ctx->H[i / 4] <<= 8; + } + + /* + * Re-initialize the context (also zeroizes contents) + */ + mir_sha1_init(ctx); +} + +MIR_CORE_DLL(void) mir_sha1_hash(BYTE *dataIn, int len, BYTE hashout[20]) +{ + mir_sha1_ctx ctx; + + mir_sha1_init(&ctx); + mir_sha1_append(&ctx, dataIn, len); + mir_sha1_finish(&ctx, hashout); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(void) mir_hmac_sha1(BYTE hashout[MIR_SHA1_HASH_SIZE], const BYTE *key, size_t keylen, const BYTE *text, size_t textlen) +{ + const unsigned SHA_BLOCKSIZE = 64; + + BYTE mdkey[MIR_SHA1_HASH_SIZE], k_ipad[SHA_BLOCKSIZE], k_opad[SHA_BLOCKSIZE]; + mir_sha1_ctx ctx; + + if (keylen > SHA_BLOCKSIZE) { + mir_sha1_init(&ctx); + mir_sha1_append(&ctx, key, (int)keylen); + mir_sha1_finish(&ctx, mdkey); + keylen = 20; + key = mdkey; + } + + memcpy(k_ipad, key, keylen); + memcpy(k_opad, key, keylen); + memset(k_ipad+keylen, 0x36, SHA_BLOCKSIZE - keylen); + memset(k_opad+keylen, 0x5c, SHA_BLOCKSIZE - keylen); + + for (unsigned i = 0; i < keylen; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + mir_sha1_init(&ctx); + mir_sha1_append(&ctx, k_ipad, SHA_BLOCKSIZE); + mir_sha1_append(&ctx, text, (int)textlen); + mir_sha1_finish(&ctx, hashout); + + mir_sha1_init(&ctx); + mir_sha1_append(&ctx, k_opad, SHA_BLOCKSIZE); + mir_sha1_append(&ctx, hashout, MIR_SHA1_HASH_SIZE); + mir_sha1_finish(&ctx, hashout); +} diff --git a/src/mir_core/src/stdafx.cpp b/src/mir_core/src/stdafx.cpp new file mode 100644 index 0000000000..9c953189b2 --- /dev/null +++ b/src/mir_core/src/stdafx.cpp @@ -0,0 +1,18 @@ +/* +Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "commonheaders.h" \ No newline at end of file diff --git a/src/mir_core/src/subclass.cpp b/src/mir_core/src/subclass.cpp new file mode 100644 index 0000000000..ca5dc88d2b --- /dev/null +++ b/src/mir_core/src/subclass.cpp @@ -0,0 +1,178 @@ +/* +Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "commonheaders.h" + +struct MSubclassData +{ + HWND m_hWnd; + + int m_iHooks; + WNDPROC *m_hooks; + WNDPROC m_origWndProc; + + ~MSubclassData() + { + free(m_hooks); + } +}; + +static LIST arSubclass(10, LIST::FTSortFunc(HandleKeySortT)); + +///////////////////////////////////////////////////////////////////////////////////////// + +static LRESULT CALLBACK MSubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + MSubclassData *p = arSubclass.find((MSubclassData*)&hwnd); + if (p != NULL) { + if (p->m_iHooks) + return p->m_hooks[p->m_iHooks-1](hwnd, uMsg, wParam, lParam); + + return p->m_origWndProc(hwnd, uMsg, wParam, lParam); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +MIR_CORE_DLL(void) mir_subclassWindow(HWND hWnd, WNDPROC wndProc) +{ + MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); + if (p == NULL) { + p = new MSubclassData; + p->m_hWnd = hWnd; + p->m_origWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MSubclassWndProc); + p->m_iHooks = 0; + p->m_hooks = (WNDPROC*)malloc( sizeof(WNDPROC)); + arSubclass.insert(p); + } + else { + for (int i=0; i < p->m_iHooks; i++) + if (p->m_hooks[i] == wndProc) + return; + + p->m_hooks = (WNDPROC*)realloc(p->m_hooks, (p->m_iHooks+1)*sizeof(WNDPROC)); + } + + p->m_hooks[p->m_iHooks++] = wndProc; +} + +MIR_CORE_DLL(void) mir_subclassWindowFull(HWND hWnd, WNDPROC wndProc, WNDPROC oldWndProc) +{ + MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); + if (p == NULL) { + p = new MSubclassData; + p->m_hWnd = hWnd; + p->m_origWndProc = oldWndProc; + p->m_iHooks = 0; + p->m_hooks = (WNDPROC*)malloc( sizeof(WNDPROC)); + arSubclass.insert(p); + + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MSubclassWndProc); + } + else { + for (int i=0; i < p->m_iHooks; i++) + if (p->m_hooks[i] == wndProc) + return; + + p->m_hooks = (WNDPROC*)realloc(p->m_hooks, (p->m_iHooks+1)*sizeof(WNDPROC)); + } + + p->m_hooks[p->m_iHooks++] = wndProc; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static void removeHook(MSubclassData *p, int idx) +{ + WNDPROC saveProc = p->m_hooks[idx]; + + // untie hook from a window to prevent calling mir_callNextSubclass from saveProc + for (int i=idx+1; i < p->m_iHooks; i++) + p->m_hooks[i-1] = p->m_hooks[i]; + p->m_iHooks--; +} + +MIR_CORE_DLL(void) mir_unsubclassWindow(HWND hWnd, WNDPROC wndProc) +{ + MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); + if (p == NULL) + return; + + for (int i=0; i < p->m_iHooks; i++) { + if (p->m_hooks[i] == wndProc) { + removeHook(p, i); + i--; + } + } + + if (p->m_iHooks == 0) { + arSubclass.remove(p); + delete p; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(LRESULT) mir_callNextSubclass(HWND hWnd, WNDPROC wndProc, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); + if (p == NULL) + return DefWindowProc(hWnd, uMsg, wParam, lParam); + + for (int i=p->m_iHooks-1; i >= 0; i--) { + if (p->m_hooks[i] != wndProc) + continue; + + // next hook exists, call it + if (i != 0) + return p->m_hooks[i-1](hWnd, uMsg, wParam, lParam); + + // last hook called, ping the default window procedure + if (uMsg != WM_DESTROY) + return p->m_origWndProc(hWnd, uMsg, wParam, lParam); + + WNDPROC saveProc = p->m_origWndProc; + arSubclass.remove(p); + delete p; + + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)saveProc); + return saveProc(hWnd, uMsg, wParam, lParam); + } + + // invalid / closed hook + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(void) KillModuleSubclassing(HMODULE hInst) +{ + for (int i=arSubclass.getCount()-1; i >= 0; i--) { + MSubclassData *p = arSubclass[i]; + for (int j=0; j < p->m_iHooks; j++) { + if ( GetInstByAddress(p->m_hooks[j]) == hInst) { + removeHook(p, j); + j--; + } + } + + if (p->m_iHooks == 0) { + arSubclass.remove(p); + delete p; + } + } +} diff --git a/src/mir_core/src/threads.cpp b/src/mir_core/src/threads.cpp new file mode 100644 index 0000000000..b1d6a23ebd --- /dev/null +++ b/src/mir_core/src/threads.cpp @@ -0,0 +1,364 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "commonheaders.h" + +#include + +///////////////////////////////////////////////////////////////////////////////////////// +// APC and mutex functions + +static void __stdcall DummyAPCFunc(ULONG_PTR) +{ + /* called in the context of thread that cleared it's APC queue */ + return; +} + +static int MirandaWaitForMutex(HANDLE hEvent) +{ + for (;;) { + // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result + DWORD rc = MsgWaitForMultipleObjectsEx(1, &hEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE); + if (rc == WAIT_OBJECT_0 + 1) { + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (IsDialogMessage(msg.hwnd, &msg)) continue; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + else if (rc == WAIT_OBJECT_0) { // got object + return 1; + } + else if (rc == WAIT_ABANDONED_0 || rc == WAIT_FAILED) + return 0; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// exception handling + +static DWORD __cdecl sttDefaultFilter(DWORD, EXCEPTION_POINTERS*) +{ + return EXCEPTION_EXECUTE_HANDLER; +} + +pfnExceptionFilter pMirandaExceptFilter = sttDefaultFilter; + +MIR_CORE_DLL(pfnExceptionFilter) GetExceptionFilter() +{ + return pMirandaExceptFilter; +} + +MIR_CORE_DLL(pfnExceptionFilter) SetExceptionFilter(pfnExceptionFilter pMirandaExceptFilter) +{ + pfnExceptionFilter oldOne = pMirandaExceptFilter; + if (pMirandaExceptFilter != 0) + pMirandaExceptFilter = pMirandaExceptFilter; + return oldOne; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// thread support functions + +struct THREAD_WAIT_ENTRY +{ + DWORD dwThreadId; // valid if hThread isn't signalled + HANDLE hThread; + HINSTANCE hOwner; + void *pObject, *pEntryPoint; +}; + +static LIST threads(10, NumericKeySortT); + +struct FORK_ARG +{ + HANDLE hEvent; + union + { + pThreadFunc threadcode; + pThreadFuncEx threadcodeex; + }; + void *arg, *owner; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// forkthread - starts a new thread + +void __cdecl forkthread_r(void *arg) +{ + FORK_ARG *fa = (FORK_ARG*)arg; + pThreadFunc callercode = fa->threadcode; + void *cookie = fa->arg; + Thread_Push((HINSTANCE)callercode); + SetEvent(fa->hEvent); + + callercode(cookie); + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + Thread_Pop(); +} + +MIR_CORE_DLL(UINT_PTR) forkthread(void(__cdecl *threadcode)(void*), unsigned long stacksize, void *arg) +{ + FORK_ARG fa; + fa.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + fa.threadcode = threadcode; + fa.arg = arg; + UINT_PTR rc = _beginthread(forkthread_r, stacksize, &fa); + if ((UINT_PTR)-1L != rc) + WaitForSingleObject(fa.hEvent, INFINITE); + + CloseHandle(fa.hEvent); + return rc; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// forkthreadex - starts a new thread with the extended info and returns the thread id + +unsigned __stdcall forkthreadex_r(void * arg) +{ + struct FORK_ARG *fa = (struct FORK_ARG *)arg; + pThreadFuncEx threadcode = fa->threadcodeex; + pThreadFuncOwner threadcodeex = (pThreadFuncOwner)fa->threadcodeex; + void *cookie = fa->arg; + void *owner = fa->owner; + unsigned long rc = 0; + + Thread_Push((HINSTANCE)threadcode, fa->owner); + SetEvent(fa->hEvent); + if (owner) + rc = threadcodeex(owner, cookie); + else + rc = threadcode(cookie); + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + Thread_Pop(); + return rc; +} + +MIR_CORE_DLL(UINT_PTR) forkthreadex( + void *sec, + unsigned stacksize, + unsigned(__stdcall *threadcode)(void*), + void *owner, + void *arg, + unsigned *thraddr) +{ + struct FORK_ARG fa = { 0 }; + fa.threadcodeex = threadcode; + fa.arg = arg; + fa.owner = owner; + fa.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + UINT_PTR rc = _beginthreadex(sec, stacksize, forkthreadex_r, (void *)&fa, 0, thraddr); + if (rc) + WaitForSingleObject(fa.hEvent, INFINITE); + + CloseHandle(fa.hEvent); + return rc; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(void) KillObjectThreads(void* owner) +{ + if (owner == NULL) + return; + + WaitForSingleObject(hStackMutex, INFINITE); + + HANDLE *threadPool = (HANDLE*)alloca(threads.getCount()*sizeof(HANDLE)); + int threadCount = 0; + + for (int j = threads.getCount(); j--;) { + THREAD_WAIT_ENTRY *p = threads[j]; + if (p->pObject == owner) + threadPool[threadCount++] = p->hThread; + } + ReleaseMutex(hStackMutex); + + // is there anything to kill? + if (threadCount > 0) { + if (WaitForMultipleObjects(threadCount, threadPool, TRUE, 5000) == WAIT_TIMEOUT) { + // forcibly kill all remaining threads after 5 secs + WaitForSingleObject(hStackMutex, INFINITE); + for (int j = threads.getCount() - 1; j >= 0; j--) { + THREAD_WAIT_ENTRY* p = threads[j]; + if (p->pObject == owner) { + char szModuleName[MAX_PATH]; + GetModuleFileNameA(p->hOwner, szModuleName, sizeof(szModuleName)); + Netlib_Logf(0, "Killing objec thread %s:%p", szModuleName, p->dwThreadId); + TerminateThread(p->hThread, 9999); + CloseHandle(p->hThread); + threads.remove(j); + mir_free(p); + } + } + ReleaseMutex(hStackMutex); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static void CALLBACK KillAllThreads(HWND, UINT, UINT_PTR, DWORD) +{ + if (MirandaWaitForMutex(hStackMutex)) { + for (int j = 0; j < threads.getCount(); j++) { + THREAD_WAIT_ENTRY *p = threads[j]; + char szModuleName[MAX_PATH]; + GetModuleFileNameA(p->hOwner, szModuleName, sizeof(szModuleName)); + Netlib_Logf(0, "Killing thread %s:%p (%p)", szModuleName, p->dwThreadId, p->pEntryPoint); + TerminateThread(p->hThread, 9999); + CloseHandle(p->hThread); + mir_free(p); + } + + threads.destroy(); + + ReleaseMutex(hStackMutex); + SetEvent(hThreadQueueEmpty); + } +} + +MIR_CORE_DLL(void) Thread_Wait(void) +{ + // acquire the list and wake up any alertable threads + if (MirandaWaitForMutex(hStackMutex)) { + for (int j = 0; j < threads.getCount(); j++) + QueueUserAPC(DummyAPCFunc, threads[j]->hThread, 0); + ReleaseMutex(hStackMutex); + } + + // give all unclosed threads 5 seconds to close + SetTimer(NULL, 0, 5000, KillAllThreads); + + // wait til the thread list is empty + MirandaWaitForMutex(hThreadQueueEmpty); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG); +#define ThreadQuerySetWin32StartAddress 9 + +static void* GetCurrentThreadEntryPoint() +{ + pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread"); + if (NtQueryInformationThread == NULL) return 0; + + HANDLE hDupHandle, hCurrentProcess = GetCurrentProcess(); + if (!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)) { + SetLastError(ERROR_ACCESS_DENIED); + return NULL; + } + + DWORD_PTR dwStartAddress; + LONG ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL); + CloseHandle(hDupHandle); + + return (ntStatus != ERROR_SUCCESS) ? NULL : (void*)dwStartAddress; +} + +MIR_CORE_DLL(INT_PTR) Thread_Push(HINSTANCE hInst, void* pOwner) +{ + ResetEvent(hThreadQueueEmpty); // thread list is not empty + if (WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) { + THREAD_WAIT_ENTRY* p = (THREAD_WAIT_ENTRY*)mir_calloc(sizeof(THREAD_WAIT_ENTRY)); + + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &p->hThread, 0, FALSE, DUPLICATE_SAME_ACCESS); + p->dwThreadId = GetCurrentThreadId(); + p->pObject = pOwner; + if (pluginListAddr.getIndex(hInst) != -1) + p->hOwner = hInst; + else + p->hOwner = GetInstByAddress((hInst != NULL) ? (PVOID)hInst : GetCurrentThreadEntryPoint()); + p->pEntryPoint = hInst; + + threads.insert(p); + + ReleaseMutex(hStackMutex); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(INT_PTR) Thread_Pop() +{ + if (WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) { + DWORD dwThreadId = GetCurrentThreadId(); + for (int j = 0; j < threads.getCount(); j++) { + THREAD_WAIT_ENTRY *p = threads[j]; + if (p->dwThreadId == dwThreadId) { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + CloseHandle(p->hThread); + threads.remove(j); + mir_free(p); + + if (!threads.getCount()) { + threads.destroy(); + ReleaseMutex(hStackMutex); + SetEvent(hThreadQueueEmpty); // thread list is empty now + return 0; + } + + ReleaseMutex(hStackMutex); + return 0; + } + } + ReleaseMutex(hStackMutex); + } + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +const DWORD MS_VC_EXCEPTION=0x406D1388; + +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +MIR_CORE_DLL(void) Thread_SetName(const char *szThreadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = GetCurrentThreadId(); + info.dwFlags = 0; + + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER) + {} +} diff --git a/src/mir_core/src/utf.cpp b/src/mir_core/src/utf.cpp new file mode 100644 index 0000000000..1e30cdecf5 --- /dev/null +++ b/src/mir_core/src/utf.cpp @@ -0,0 +1,452 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + + Copyright 2000 Alexandre Julliard of Wine project + (UTF-8 conversion routines) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */ +static const char utf8_length[128] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xaf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0-0xbf */ + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xc0-0xcf */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xd0-0xdf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xe0-0xef */ + 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0-0xff */ +}; + +/* first byte mask depending on UTF-8 sequence length */ +static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 }; + +/* minimum Unicode value depending on UTF-8 sequence length */ +static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 }; + +/* get the next char value taking surrogates into account */ +static unsigned int getSurrogateValue(const wchar_t *src, unsigned int srclen) +{ + if (src[0] >= 0xd800 && src[0] <= 0xdfff) { /* surrogate pair */ + if (src[0] > 0xdbff || /* invalid high surrogate */ + srclen <= 1 || /* missing low surrogate */ + src[1] < 0xdc00 || src[1] > 0xdfff) /* invalid low surrogate */ + return 0; + return 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff); + } + return src[0]; +} + +/* query necessary dst length for src string */ +static int Ucs2toUtf8Len(const wchar_t *src, unsigned int srclen) +{ + int len; + unsigned int val; + + for (len = 0; srclen; srclen--, src++) { + if (*src < 0x80) { /* 0x00-0x7f: 1 byte */ + len++; + continue; + } + if (*src < 0x800) { /* 0x80-0x7ff: 2 bytes */ + len += 2; + continue; + } + if ( !(val = getSurrogateValue(src, srclen))) + return -2; + + if (val < 0x10000) /* 0x800-0xffff: 3 bytes */ + len += 3; + else { /* 0x10000-0x10ffff: 4 bytes */ + len += 4; + src++; + srclen--; + } + } + return len; +} + +MIR_CORE_DLL(int) Ucs2toUtf8Len(const wchar_t *src) +{ + if (src == 0) + return 0; + + return Ucs2toUtf8Len(src, (int)wcslen(src)); +} + +/* wide char to UTF-8 string conversion */ +/* return -1 on dst buffer overflow, -2 on invalid input char */ +int Ucs2toUtf8(const wchar_t *src, int srclen, char *dst, int dstlen) +{ + int len; + + for (len = dstlen; srclen; srclen--, src++) + { + WCHAR ch = *src; + unsigned int val; + + if (ch < 0x80) /* 0x00-0x7f: 1 byte */ + { + if ( !len--) return -1; /* overflow */ + *dst++ = ch; + continue; + } + + if (ch < 0x800) /* 0x80-0x7ff: 2 bytes */ + { + if ((len -= 2) < 0) return -1; /* overflow */ + dst[1] = 0x80 | (ch & 0x3f); + ch >>= 6; + dst[0] = 0xc0 | ch; + dst += 2; + continue; + } + + if ( !(val = getSurrogateValue(src, srclen))) + { + return -2; + } + + if (val < 0x10000) /* 0x800-0xffff: 3 bytes */ + { + if ((len -= 3) < 0) return -1; /* overflow */ + dst[2] = 0x80 | (val & 0x3f); + val >>= 6; + dst[1] = 0x80 | (val & 0x3f); + val >>= 6; + dst[0] = 0xe0 | val; + dst += 3; + } + else /* 0x10000-0x10ffff: 4 bytes */ + { + if ((len -= 4) < 0) return -1; /* overflow */ + dst[3] = 0x80 | (val & 0x3f); + val >>= 6; + dst[2] = 0x80 | (val & 0x3f); + val >>= 6; + dst[1] = 0x80 | (val & 0x3f); + val >>= 6; + dst[0] = 0xf0 | val; + dst += 4; + src++; + srclen--; + } + } + return dstlen - len; +} + +/* helper for the various utf8 mbstowcs functions */ +static unsigned int decodeUtf8Char(unsigned char ch, const char **str, const char *strend) +{ + unsigned int len = utf8_length[ch-0x80]; + unsigned int res = ch & utf8_mask[len]; + const char *end = *str + len; + + if (end > strend) return ~0; + switch(len) + { + case 3: + if ((ch = end[-3] ^ 0x80) >= 0x40) break; + res = (res << 6) | ch; + (*str)++; + case 2: + if ((ch = end[-2] ^ 0x80) >= 0x40) break; + res = (res << 6) | ch; + (*str)++; + case 1: + if ((ch = end[-1] ^ 0x80) >= 0x40) break; + res = (res << 6) | ch; + (*str)++; + if (res < utf8_minval[len]) break; + return res; + } + return ~0; +} + +/* query necessary dst length for src string */ +static inline int Utf8toUcs2Len(const char *src, int srclen) +{ + int ret = 0; + unsigned int res; + const char *srcend = src + srclen; + + while (src < srcend) + { + unsigned char ch = *src++; + if (ch < 0x80) /* special fast case for 7-bit ASCII */ + { + ret++; + continue; + } + if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0x10ffff) + { + if (res > 0xffff) ret++; + ret++; + } + else return -2; /* bad char */ + /* otherwise ignore it */ + } + return ret; +} + +/* UTF-8 to wide char string conversion */ +/* return -1 on dst buffer overflow, -2 on invalid input char */ +int Utf8toUcs2(const char *src, int srclen, wchar_t *dst, int dstlen) +{ + unsigned int res; + const char *srcend = src + srclen; + wchar_t *dstend = dst + dstlen; + + while ((dst < dstend) && (src < srcend)) + { + unsigned char ch = *src++; + if (ch < 0x80) /* special fast case for 7-bit ASCII */ + { + *dst++ = ch; + continue; + } + if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0xffff) + { + *dst++ = res; + } + else if (res <= 0x10ffff) /* we need surrogates */ + { + if (dst == dstend - 1) return -1; /* overflow */ + res -= 0x10000; + *dst++ = 0xd800 | (res >> 10); + *dst++ = 0xdc00 | (res & 0x3ff); + } + else return -2; /* bad char */ + /* otherwise ignore it */ + } + if (src < srcend) return -1; /* overflow */ + return dstlen - (dstend - dst); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format + +MIR_CORE_DLL(char*) Utf8DecodeCP(char *str, int codepage, wchar_t **ucs2) +{ + int len; + bool needs_free = false; + wchar_t* tempBuf = NULL; + if (ucs2) + *ucs2 = NULL; + + if (str == NULL) + return NULL; + + len = (int)strlen(str); + + if (len < 2) { + if (ucs2 != NULL) { + *ucs2 = tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); + MultiByteToWideChar(codepage, 0, str, len, tempBuf, len); + tempBuf[len] = 0; + } + return str; + } + + int destlen = Utf8toUcs2Len(str, len); + if (destlen < 0) + return NULL; + + if (ucs2 == NULL) { + __try + { + tempBuf = (wchar_t*)alloca((destlen + 1) * sizeof(wchar_t)); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + tempBuf = NULL; + needs_free = true; + } + } + + if (tempBuf == NULL) { + tempBuf = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t)); + if (tempBuf == NULL) + return NULL; + } + + Utf8toUcs2(str, len, tempBuf, destlen); + tempBuf[destlen] = 0; + WideCharToMultiByte(codepage, 0, tempBuf, -1, str, len + 1, "?", NULL); + + if (ucs2) + *ucs2 = tempBuf; + else if (needs_free) + mir_free(tempBuf); + + return str; +} + +MIR_CORE_DLL(char*) Utf8Decode(char *str, wchar_t **ucs2) +{ + return Utf8DecodeCP(str, Langpack_GetDefaultCodePage(), ucs2); +} + +MIR_CORE_DLL(wchar_t*) Utf8DecodeW(const char *str) +{ + if (str == NULL) + return NULL; + + int len = (int)strlen(str); + + int destlen = Utf8toUcs2Len(str, len); + if (destlen < 0) return NULL; + + wchar_t* ucs2 = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t)); + if (ucs2 == NULL) return NULL; + + if (Utf8toUcs2(str, len, ucs2, destlen) >= 0) + { + ucs2[destlen] = 0; + return ucs2; + } + + mir_free(ucs2); + + return NULL; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Utf8Encode - converts MBCS string to the UTF8-encoded format + +MIR_CORE_DLL(char*) Utf8EncodeCP(const char* src, int codepage) +{ + int len; + bool needs_free = false; + char* result = NULL; + wchar_t* tempBuf; + + if (src == NULL) + return NULL; + + len = (int)strlen(src); + + __try + { + tempBuf = (wchar_t*)alloca((len + 1) * sizeof(wchar_t)); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); + if (tempBuf == NULL) return NULL; + needs_free = true; + } + + len = MultiByteToWideChar(codepage, 0, src, -1, tempBuf, len + 1); + + int destlen = Ucs2toUtf8Len(tempBuf, len); + if (destlen >= 0) + { + result = (char*)mir_alloc(destlen + 1); + if (result) + { + Ucs2toUtf8(tempBuf, len, result, destlen); + result[destlen] = 0; + } + } + + if (needs_free) + mir_free(tempBuf); + + return result; +} + +MIR_CORE_DLL(char*) Utf8Encode(const char* src) +{ + return Utf8EncodeCP(src, Langpack_GetDefaultCodePage()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Utf8Encode - converts UCS2 string to the UTF8-encoded format + +MIR_CORE_DLL(char*) Utf8EncodeW(const wchar_t* src) +{ + if (src == NULL) + return NULL; + + int len = (int)wcslen(src); + + int destlen = Ucs2toUtf8Len(src, len); + if (destlen < 0) return NULL; + + char* result = (char*)mir_alloc(destlen + 1); + if (result == NULL) + return NULL; + + Ucs2toUtf8(src, len, result, destlen); + result[destlen] = 0; + + return result; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Utf8Encode - converts UCS2 string to the UTF8-encoded format + +MIR_CORE_DLL(BOOL) Utf8CheckString(const char *str) +{ + int expect_bytes = 0, utf_found = 0; + + if (!str) return 0; + + while (*str) { + if ((*str & 0x80) == 0) { + /* Looks like an ASCII character */ + if (expect_bytes) + /* byte of UTF-8 character expected */ + return 0; + } + else { + /* Looks like byte of an UTF-8 character */ + if (expect_bytes) { + /* expect_bytes already set: first byte of UTF-8 char already seen */ + if ((*str & 0xC0) != 0x80) { + /* again first byte ?!?! */ + return 0; + } + } + else { + /* First byte of the UTF-8 character */ + /* count initial one bits and set expect_bytes to 1 less */ + char ch = *str; + while (ch & 0x80) { + expect_bytes++; + ch = (ch & 0x7f) << 1; + } + } + /* OK, next byte of UTF-8 character */ + /* Decrement number of expected bytes */ + if (--expect_bytes == 0) + utf_found = 1; + } + str++; + } + + return (utf_found && expect_bytes == 0); +} diff --git a/src/mir_core/src/utils.cpp b/src/mir_core/src/utils.cpp new file mode 100644 index 0000000000..bf05b84b6e --- /dev/null +++ b/src/mir_core/src/utils.cpp @@ -0,0 +1,411 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "commonheaders.h" + +MIR_CORE_DLL(char*) replaceStr(char* &dest, const char *src) +{ + if (dest != NULL) + mir_free(dest); + + return dest = (src != NULL) ? mir_strdup(src) : NULL; +} + +MIR_CORE_DLL(WCHAR*) replaceStrW(WCHAR* &dest, const WCHAR *src) +{ + if (dest != NULL) + mir_free(dest); + + return dest = (src != NULL) ? mir_wstrdup(src) : NULL; +} + +MIR_CORE_DLL(char*) rtrim(char *str) +{ + if (str == NULL) + return NULL; + + char* p = strchr(str, 0); + while (--p >= str) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + *p = 0; break; + default: + return str; + } + } + return str; +} + +MIR_CORE_DLL(WCHAR*) rtrimw(WCHAR *str) +{ + if (str == NULL) + return NULL; + + WCHAR *p = _tcschr(str, 0); + while (--p >= str) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + *p = 0; break; + default: + return str; + } + } + return str; +} + +MIR_CORE_DLL(char*) ltrim(char *str) +{ + if (str == NULL) + return NULL; + + char* p = str; + for (;;) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + ++p; break; + default: + memmove(str, p, strlen(p) + 1); + return str; + } + } +} + +MIR_CORE_DLL(WCHAR*) ltrimw(WCHAR *str) +{ + if (str == NULL) + return NULL; + + WCHAR *p = str; + for (;;) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + ++p; break; + default: + memmove(str, p, sizeof(WCHAR)*(wcslen(p) + 1)); + return str; + } + } +} + +MIR_CORE_DLL(char*) ltrimp(char *str) +{ + if (str == NULL) + return NULL; + + char *p = str; + for (;;) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + ++p; break; + default: + return p; + } + } +} + +MIR_CORE_DLL(WCHAR*) ltrimpw(WCHAR *str) +{ + if (str == NULL) + return NULL; + + WCHAR *p = str; + for (;;) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + ++p; break; + default: + return p; + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(int) wildcmp(const char *name, const char *mask) +{ + if (name == NULL || mask == NULL) + return false; + + const char *last = '\0'; + for (;; mask++, name++) { + if (*mask != '?' && *mask != *name) break; + if (*name == '\0') return ((BOOL)!*mask); + } + if (*mask != '*') return FALSE; + for (;; mask++, name++) { + while (*mask == '*') { + last = mask++; + if (*mask == '\0') return ((BOOL)!*mask); /* true */ + } + if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ + if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last; + } +} + +MIR_CORE_DLL(int) wildcmpw(const WCHAR *name, const WCHAR *mask) +{ + if (name == NULL || mask == NULL) + return false; + + const WCHAR* last = '\0'; + for (;; mask++, name++) { + if (*mask != '?' && *mask != *name) break; + if (*name == '\0') return ((BOOL)!*mask); + } + if (*mask != '*') return FALSE; + for (;; mask++, name++) { + while (*mask == '*') { + last = mask++; + if (*mask == '\0') return ((BOOL)!*mask); /* true */ + } + if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ + if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last; + } +} + +#define _qtoupper(_c) (((_c) >= 'a' && (_c) <= 'z')?((_c)-'a'+'A'):(_c)) + +MIR_CORE_DLL(int) wildcmpi(const char *name, const char *mask) +{ + if (name == NULL || mask == NULL) + return false; + + const char *last = NULL; + for (;; mask++, name++) { + if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) break; + if (*name == '\0') return ((BOOL)!*mask); + } + if (*mask != '*') return FALSE; + for (;; mask++, name++) { + while (*mask == '*') { + last = mask++; + if (*mask == '\0') return ((BOOL)!*mask); /* true */ + } + if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ + if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) name -= (size_t)(mask - last) - 1, mask = last; + } +} + +MIR_CORE_DLL(int) wildcmpiw(const WCHAR *name, const WCHAR *mask) +{ + if (name == NULL || mask == NULL) + return false; + + const WCHAR* last = NULL; + for (;; mask++, name++) { + if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) break; + if (*name == '\0') return ((BOOL)!*mask); + } + if (*mask != '*') return FALSE; + for (;; mask++, name++) { + while (*mask == '*') { + last = mask++; + if (*mask == '\0') return ((BOOL)!*mask); /* true */ + } + if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ + if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) name -= (size_t)(mask - last) - 1, mask = last; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static char szHexTable[] = "0123456789abcdef"; + +MIR_CORE_DLL(char*) bin2hex(const void *pData, size_t len, char *dest) +{ + const BYTE *p = (const BYTE*)pData; + char *d = dest; + + for (size_t i = 0; i < len; i++, p++) { + *d++ = szHexTable[*p >> 4]; + *d++ = szHexTable[*p & 0x0F]; + } + *d = 0; + + return dest; +} + +MIR_CORE_DLL(WCHAR*) bin2hexW(const void *pData, size_t len, WCHAR *dest) +{ + const BYTE *p = (const BYTE*)pData; + WCHAR *d = dest; + + for (size_t i = 0; i < len; i++, p++) { + *d++ = szHexTable[*p >> 4]; + *d++ = szHexTable[*p & 0x0F]; + } + *d = 0; + + return dest; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#pragma intrinsic(strlen, strcpy, strcat, strcmp, wcslen, wcscpy, wcscat, wcscmp) + +MIR_CORE_DLL(size_t) mir_strlen(const char *p) +{ + return (p) ? strlen(p) : 0; +} + +MIR_CORE_DLL(size_t) mir_wstrlen(const wchar_t *p) +{ + return (p) ? wcslen(p) : 0; +} + +MIR_CORE_DLL(char*) mir_strcpy(char *dest, const char *src) +{ + if (dest == NULL) + return NULL; + + if (src == NULL) { + *dest = 0; + return dest; + } + + return strcpy(dest, src); +} + +MIR_CORE_DLL(wchar_t*) mir_wstrcpy(wchar_t *dest, const wchar_t *src) +{ + if (dest == NULL) + return NULL; + + if (src == NULL) { + *dest = 0; + return dest; + } + + return wcscpy(dest, src); +} + +MIR_CORE_DLL(char*) mir_strncpy(char *dest, const char *src, size_t len) +{ + if (dest == NULL) + return NULL; + + if (src == NULL) + *dest = 0; + else + strncpy_s(dest, len, src, _TRUNCATE); + return dest; +} + +MIR_CORE_DLL(wchar_t*) mir_wstrncpy(wchar_t *dest, const wchar_t *src, size_t len) +{ + if (dest == NULL) + return NULL; + + if (src == NULL) + *dest = 0; + else + wcsncpy_s(dest, len, src, _TRUNCATE); + return dest; +} + +MIR_CORE_DLL(char*) mir_strcat(char *dest, const char *src) +{ + if (dest == NULL) + return NULL; + + if (src == NULL) { + *dest = 0; + return dest; + } + + return strcat(dest, src); +} + +MIR_CORE_DLL(wchar_t*) mir_wstrcat(wchar_t *dest, const wchar_t *src) +{ + if (dest == NULL) + return NULL; + + if (src == NULL) { + *dest = 0; + return dest; + } + + return wcscat(dest, src); +} + +MIR_CORE_DLL(char*) mir_strncat(char *dest, const char *src, size_t len) +{ + if (dest == NULL) + return NULL; + + if (src == NULL) + *dest = 0; + else + strncat_s(dest, len, src, _TRUNCATE); + return dest; +} + +MIR_CORE_DLL(wchar_t*) mir_wstrncat(wchar_t *dest, const wchar_t *src, size_t len) +{ + if (dest == NULL) + return NULL; + + if (src == NULL) + *dest = 0; + else + wcsncat_s(dest, len, src, _TRUNCATE); + return dest; +} + +MIR_CORE_DLL(int) mir_strcmp(const char *p1, const char *p2) +{ + if (p1 == NULL) + return (p2 == NULL) ? 0 : -1; + if (p2 == NULL) + return 1; + return CompareStringA(LOCALE_USER_DEFAULT, 0, p1, -1, p2, -1) - 2; +} + +MIR_CORE_DLL(int) mir_wstrcmp(const wchar_t *p1, const wchar_t *p2) +{ + if (p1 == NULL) + return (p2 == NULL) ? 0 : -1; + if (p2 == NULL) + return 1; + return CompareStringW(LOCALE_USER_DEFAULT, 0, p1, -1, p2, -1) - 2; +} + +MIR_CORE_DLL(int) mir_strcmpi(const char *p1, const char *p2) +{ + if (p1 == NULL) + return (p2 == NULL) ? 0 : -1; + if (p2 == NULL) + return 1; + return CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, p1, -1, p2, -1) - 2; +} + +MIR_CORE_DLL(int) mir_wstrcmpi(const wchar_t *p1, const wchar_t *p2) +{ + if (p1 == NULL) + return (p2 == NULL) ? 0 : -1; + if (p2 == NULL) + return 1; + return CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, p1, -1, p2, -1) - 2; +} diff --git a/src/mir_core/src/winver.cpp b/src/mir_core/src/winver.cpp new file mode 100644 index 0000000000..ad011a8e40 --- /dev/null +++ b/src/mir_core/src/winver.cpp @@ -0,0 +1,93 @@ +/* +Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "commonheaders.h" + +static int dwWinVer; + +void InitWinver() +{ + DWORD dwVer = LOWORD( GetVersion()); + dwWinVer = MAKEWORD(HIBYTE(dwVer), LOBYTE(dwVer)); +} + +MIR_CORE_DLL(BOOL) IsWinVerVistaPlus() +{ + return dwWinVer >= _WIN32_WINNT_VISTA; +} + +MIR_CORE_DLL(BOOL) IsWinVer7Plus() +{ + return dwWinVer >= _WIN32_WINNT_WIN7; +} + +MIR_CORE_DLL(BOOL) IsFullScreen() +{ + RECT rcScreen = {0}; + + rcScreen.right = GetSystemMetrics(SM_CXSCREEN); + rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN); + + HMONITOR hMon = MonitorFromWindow(GetForegroundWindow(), MONITOR_DEFAULTTONEAREST); + MONITORINFO mi; + mi.cbSize = sizeof(mi); + if (GetMonitorInfo(hMon, &mi)) + rcScreen = mi.rcMonitor; + + HWND hWndDesktop = GetDesktopWindow(); + HWND hWndShell = GetShellWindow(); + + // check foregroundwindow + HWND hWnd = GetForegroundWindow(); + if (hWnd && hWnd != hWndDesktop && hWnd != hWndShell) { + TCHAR tszClassName[128] = _T(""); + GetClassName(hWnd, tszClassName, SIZEOF(tszClassName)); + if ( _tcscmp(tszClassName, _T("WorkerW"))) { + RECT rect, rectw, recti; + GetWindowRect(hWnd, &rectw); + + GetClientRect(hWnd, &rect); + ClientToScreen(hWnd, (LPPOINT)&rect); + ClientToScreen(hWnd, (LPPOINT)&rect.right); + + if (EqualRect(&rect, &rectw) && IntersectRect(&recti, &rect, &rcScreen) && EqualRect(&recti, &rcScreen)) + return true; + } + } + + return false; +} + +MIR_CORE_DLL(BOOL) IsWorkstationLocked(void) +{ + HDESK hDesk = OpenInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP); + if (hDesk == NULL) + return true; + + TCHAR tszName[100]; + DWORD cbName; + BOOL bLocked = (!GetUserObjectInformation(hDesk, UOI_NAME, tszName, SIZEOF(tszName), &cbName) || mir_tstrcmpi(tszName,_T("default")) != 0); + CloseDesktop(hDesk); + return bLocked; +} + +MIR_CORE_DLL(BOOL) IsScreenSaverRunning(void) +{ + BOOL rc = FALSE; + SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &rc, FALSE); + return rc != 0; +} diff --git a/src/mir_core/stdafx.cpp b/src/mir_core/stdafx.cpp deleted file mode 100644 index 9c953189b2..0000000000 --- a/src/mir_core/stdafx.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "commonheaders.h" \ No newline at end of file diff --git a/src/mir_core/subclass.cpp b/src/mir_core/subclass.cpp deleted file mode 100644 index ca5dc88d2b..0000000000 --- a/src/mir_core/subclass.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* -Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "commonheaders.h" - -struct MSubclassData -{ - HWND m_hWnd; - - int m_iHooks; - WNDPROC *m_hooks; - WNDPROC m_origWndProc; - - ~MSubclassData() - { - free(m_hooks); - } -}; - -static LIST arSubclass(10, LIST::FTSortFunc(HandleKeySortT)); - -///////////////////////////////////////////////////////////////////////////////////////// - -static LRESULT CALLBACK MSubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - MSubclassData *p = arSubclass.find((MSubclassData*)&hwnd); - if (p != NULL) { - if (p->m_iHooks) - return p->m_hooks[p->m_iHooks-1](hwnd, uMsg, wParam, lParam); - - return p->m_origWndProc(hwnd, uMsg, wParam, lParam); - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -MIR_CORE_DLL(void) mir_subclassWindow(HWND hWnd, WNDPROC wndProc) -{ - MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); - if (p == NULL) { - p = new MSubclassData; - p->m_hWnd = hWnd; - p->m_origWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MSubclassWndProc); - p->m_iHooks = 0; - p->m_hooks = (WNDPROC*)malloc( sizeof(WNDPROC)); - arSubclass.insert(p); - } - else { - for (int i=0; i < p->m_iHooks; i++) - if (p->m_hooks[i] == wndProc) - return; - - p->m_hooks = (WNDPROC*)realloc(p->m_hooks, (p->m_iHooks+1)*sizeof(WNDPROC)); - } - - p->m_hooks[p->m_iHooks++] = wndProc; -} - -MIR_CORE_DLL(void) mir_subclassWindowFull(HWND hWnd, WNDPROC wndProc, WNDPROC oldWndProc) -{ - MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); - if (p == NULL) { - p = new MSubclassData; - p->m_hWnd = hWnd; - p->m_origWndProc = oldWndProc; - p->m_iHooks = 0; - p->m_hooks = (WNDPROC*)malloc( sizeof(WNDPROC)); - arSubclass.insert(p); - - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MSubclassWndProc); - } - else { - for (int i=0; i < p->m_iHooks; i++) - if (p->m_hooks[i] == wndProc) - return; - - p->m_hooks = (WNDPROC*)realloc(p->m_hooks, (p->m_iHooks+1)*sizeof(WNDPROC)); - } - - p->m_hooks[p->m_iHooks++] = wndProc; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static void removeHook(MSubclassData *p, int idx) -{ - WNDPROC saveProc = p->m_hooks[idx]; - - // untie hook from a window to prevent calling mir_callNextSubclass from saveProc - for (int i=idx+1; i < p->m_iHooks; i++) - p->m_hooks[i-1] = p->m_hooks[i]; - p->m_iHooks--; -} - -MIR_CORE_DLL(void) mir_unsubclassWindow(HWND hWnd, WNDPROC wndProc) -{ - MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); - if (p == NULL) - return; - - for (int i=0; i < p->m_iHooks; i++) { - if (p->m_hooks[i] == wndProc) { - removeHook(p, i); - i--; - } - } - - if (p->m_iHooks == 0) { - arSubclass.remove(p); - delete p; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(LRESULT) mir_callNextSubclass(HWND hWnd, WNDPROC wndProc, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); - if (p == NULL) - return DefWindowProc(hWnd, uMsg, wParam, lParam); - - for (int i=p->m_iHooks-1; i >= 0; i--) { - if (p->m_hooks[i] != wndProc) - continue; - - // next hook exists, call it - if (i != 0) - return p->m_hooks[i-1](hWnd, uMsg, wParam, lParam); - - // last hook called, ping the default window procedure - if (uMsg != WM_DESTROY) - return p->m_origWndProc(hWnd, uMsg, wParam, lParam); - - WNDPROC saveProc = p->m_origWndProc; - arSubclass.remove(p); - delete p; - - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)saveProc); - return saveProc(hWnd, uMsg, wParam, lParam); - } - - // invalid / closed hook - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(void) KillModuleSubclassing(HMODULE hInst) -{ - for (int i=arSubclass.getCount()-1; i >= 0; i--) { - MSubclassData *p = arSubclass[i]; - for (int j=0; j < p->m_iHooks; j++) { - if ( GetInstByAddress(p->m_hooks[j]) == hInst) { - removeHook(p, j); - j--; - } - } - - if (p->m_iHooks == 0) { - arSubclass.remove(p); - delete p; - } - } -} diff --git a/src/mir_core/threads.cpp b/src/mir_core/threads.cpp deleted file mode 100644 index b1d6a23ebd..0000000000 --- a/src/mir_core/threads.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "commonheaders.h" - -#include - -///////////////////////////////////////////////////////////////////////////////////////// -// APC and mutex functions - -static void __stdcall DummyAPCFunc(ULONG_PTR) -{ - /* called in the context of thread that cleared it's APC queue */ - return; -} - -static int MirandaWaitForMutex(HANDLE hEvent) -{ - for (;;) { - // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result - DWORD rc = MsgWaitForMultipleObjectsEx(1, &hEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE); - if (rc == WAIT_OBJECT_0 + 1) { - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - if (IsDialogMessage(msg.hwnd, &msg)) continue; - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - else if (rc == WAIT_OBJECT_0) { // got object - return 1; - } - else if (rc == WAIT_ABANDONED_0 || rc == WAIT_FAILED) - return 0; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// exception handling - -static DWORD __cdecl sttDefaultFilter(DWORD, EXCEPTION_POINTERS*) -{ - return EXCEPTION_EXECUTE_HANDLER; -} - -pfnExceptionFilter pMirandaExceptFilter = sttDefaultFilter; - -MIR_CORE_DLL(pfnExceptionFilter) GetExceptionFilter() -{ - return pMirandaExceptFilter; -} - -MIR_CORE_DLL(pfnExceptionFilter) SetExceptionFilter(pfnExceptionFilter pMirandaExceptFilter) -{ - pfnExceptionFilter oldOne = pMirandaExceptFilter; - if (pMirandaExceptFilter != 0) - pMirandaExceptFilter = pMirandaExceptFilter; - return oldOne; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// thread support functions - -struct THREAD_WAIT_ENTRY -{ - DWORD dwThreadId; // valid if hThread isn't signalled - HANDLE hThread; - HINSTANCE hOwner; - void *pObject, *pEntryPoint; -}; - -static LIST threads(10, NumericKeySortT); - -struct FORK_ARG -{ - HANDLE hEvent; - union - { - pThreadFunc threadcode; - pThreadFuncEx threadcodeex; - }; - void *arg, *owner; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// forkthread - starts a new thread - -void __cdecl forkthread_r(void *arg) -{ - FORK_ARG *fa = (FORK_ARG*)arg; - pThreadFunc callercode = fa->threadcode; - void *cookie = fa->arg; - Thread_Push((HINSTANCE)callercode); - SetEvent(fa->hEvent); - - callercode(cookie); - - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - Thread_Pop(); -} - -MIR_CORE_DLL(UINT_PTR) forkthread(void(__cdecl *threadcode)(void*), unsigned long stacksize, void *arg) -{ - FORK_ARG fa; - fa.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - fa.threadcode = threadcode; - fa.arg = arg; - UINT_PTR rc = _beginthread(forkthread_r, stacksize, &fa); - if ((UINT_PTR)-1L != rc) - WaitForSingleObject(fa.hEvent, INFINITE); - - CloseHandle(fa.hEvent); - return rc; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// forkthreadex - starts a new thread with the extended info and returns the thread id - -unsigned __stdcall forkthreadex_r(void * arg) -{ - struct FORK_ARG *fa = (struct FORK_ARG *)arg; - pThreadFuncEx threadcode = fa->threadcodeex; - pThreadFuncOwner threadcodeex = (pThreadFuncOwner)fa->threadcodeex; - void *cookie = fa->arg; - void *owner = fa->owner; - unsigned long rc = 0; - - Thread_Push((HINSTANCE)threadcode, fa->owner); - SetEvent(fa->hEvent); - if (owner) - rc = threadcodeex(owner, cookie); - else - rc = threadcode(cookie); - - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - Thread_Pop(); - return rc; -} - -MIR_CORE_DLL(UINT_PTR) forkthreadex( - void *sec, - unsigned stacksize, - unsigned(__stdcall *threadcode)(void*), - void *owner, - void *arg, - unsigned *thraddr) -{ - struct FORK_ARG fa = { 0 }; - fa.threadcodeex = threadcode; - fa.arg = arg; - fa.owner = owner; - fa.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - UINT_PTR rc = _beginthreadex(sec, stacksize, forkthreadex_r, (void *)&fa, 0, thraddr); - if (rc) - WaitForSingleObject(fa.hEvent, INFINITE); - - CloseHandle(fa.hEvent); - return rc; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(void) KillObjectThreads(void* owner) -{ - if (owner == NULL) - return; - - WaitForSingleObject(hStackMutex, INFINITE); - - HANDLE *threadPool = (HANDLE*)alloca(threads.getCount()*sizeof(HANDLE)); - int threadCount = 0; - - for (int j = threads.getCount(); j--;) { - THREAD_WAIT_ENTRY *p = threads[j]; - if (p->pObject == owner) - threadPool[threadCount++] = p->hThread; - } - ReleaseMutex(hStackMutex); - - // is there anything to kill? - if (threadCount > 0) { - if (WaitForMultipleObjects(threadCount, threadPool, TRUE, 5000) == WAIT_TIMEOUT) { - // forcibly kill all remaining threads after 5 secs - WaitForSingleObject(hStackMutex, INFINITE); - for (int j = threads.getCount() - 1; j >= 0; j--) { - THREAD_WAIT_ENTRY* p = threads[j]; - if (p->pObject == owner) { - char szModuleName[MAX_PATH]; - GetModuleFileNameA(p->hOwner, szModuleName, sizeof(szModuleName)); - Netlib_Logf(0, "Killing objec thread %s:%p", szModuleName, p->dwThreadId); - TerminateThread(p->hThread, 9999); - CloseHandle(p->hThread); - threads.remove(j); - mir_free(p); - } - } - ReleaseMutex(hStackMutex); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static void CALLBACK KillAllThreads(HWND, UINT, UINT_PTR, DWORD) -{ - if (MirandaWaitForMutex(hStackMutex)) { - for (int j = 0; j < threads.getCount(); j++) { - THREAD_WAIT_ENTRY *p = threads[j]; - char szModuleName[MAX_PATH]; - GetModuleFileNameA(p->hOwner, szModuleName, sizeof(szModuleName)); - Netlib_Logf(0, "Killing thread %s:%p (%p)", szModuleName, p->dwThreadId, p->pEntryPoint); - TerminateThread(p->hThread, 9999); - CloseHandle(p->hThread); - mir_free(p); - } - - threads.destroy(); - - ReleaseMutex(hStackMutex); - SetEvent(hThreadQueueEmpty); - } -} - -MIR_CORE_DLL(void) Thread_Wait(void) -{ - // acquire the list and wake up any alertable threads - if (MirandaWaitForMutex(hStackMutex)) { - for (int j = 0; j < threads.getCount(); j++) - QueueUserAPC(DummyAPCFunc, threads[j]->hThread, 0); - ReleaseMutex(hStackMutex); - } - - // give all unclosed threads 5 seconds to close - SetTimer(NULL, 0, 5000, KillAllThreads); - - // wait til the thread list is empty - MirandaWaitForMutex(hThreadQueueEmpty); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG); -#define ThreadQuerySetWin32StartAddress 9 - -static void* GetCurrentThreadEntryPoint() -{ - pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread"); - if (NtQueryInformationThread == NULL) return 0; - - HANDLE hDupHandle, hCurrentProcess = GetCurrentProcess(); - if (!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)) { - SetLastError(ERROR_ACCESS_DENIED); - return NULL; - } - - DWORD_PTR dwStartAddress; - LONG ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL); - CloseHandle(hDupHandle); - - return (ntStatus != ERROR_SUCCESS) ? NULL : (void*)dwStartAddress; -} - -MIR_CORE_DLL(INT_PTR) Thread_Push(HINSTANCE hInst, void* pOwner) -{ - ResetEvent(hThreadQueueEmpty); // thread list is not empty - if (WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) { - THREAD_WAIT_ENTRY* p = (THREAD_WAIT_ENTRY*)mir_calloc(sizeof(THREAD_WAIT_ENTRY)); - - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &p->hThread, 0, FALSE, DUPLICATE_SAME_ACCESS); - p->dwThreadId = GetCurrentThreadId(); - p->pObject = pOwner; - if (pluginListAddr.getIndex(hInst) != -1) - p->hOwner = hInst; - else - p->hOwner = GetInstByAddress((hInst != NULL) ? (PVOID)hInst : GetCurrentThreadEntryPoint()); - p->pEntryPoint = hInst; - - threads.insert(p); - - ReleaseMutex(hStackMutex); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(INT_PTR) Thread_Pop() -{ - if (WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) { - DWORD dwThreadId = GetCurrentThreadId(); - for (int j = 0; j < threads.getCount(); j++) { - THREAD_WAIT_ENTRY *p = threads[j]; - if (p->dwThreadId == dwThreadId) { - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - CloseHandle(p->hThread); - threads.remove(j); - mir_free(p); - - if (!threads.getCount()) { - threads.destroy(); - ReleaseMutex(hStackMutex); - SetEvent(hThreadQueueEmpty); // thread list is empty now - return 0; - } - - ReleaseMutex(hStackMutex); - return 0; - } - } - ReleaseMutex(hStackMutex); - } - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -const DWORD MS_VC_EXCEPTION=0x406D1388; - -#pragma pack(push,8) -typedef struct tagTHREADNAME_INFO -{ - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to name (in user addr space). - DWORD dwThreadID; // Thread ID (-1=caller thread). - DWORD dwFlags; // Reserved for future use, must be zero. -} THREADNAME_INFO; -#pragma pack(pop) - -MIR_CORE_DLL(void) Thread_SetName(const char *szThreadName) -{ - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = szThreadName; - info.dwThreadID = GetCurrentThreadId(); - info.dwFlags = 0; - - __try { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except (EXCEPTION_EXECUTE_HANDLER) - {} -} diff --git a/src/mir_core/utf.cpp b/src/mir_core/utf.cpp deleted file mode 100644 index 1e30cdecf5..0000000000 --- a/src/mir_core/utf.cpp +++ /dev/null @@ -1,452 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - - Copyright 2000 Alexandre Julliard of Wine project - (UTF-8 conversion routines) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */ -static const char utf8_length[128] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xaf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0-0xbf */ - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xc0-0xcf */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xd0-0xdf */ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xe0-0xef */ - 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0-0xff */ -}; - -/* first byte mask depending on UTF-8 sequence length */ -static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 }; - -/* minimum Unicode value depending on UTF-8 sequence length */ -static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 }; - -/* get the next char value taking surrogates into account */ -static unsigned int getSurrogateValue(const wchar_t *src, unsigned int srclen) -{ - if (src[0] >= 0xd800 && src[0] <= 0xdfff) { /* surrogate pair */ - if (src[0] > 0xdbff || /* invalid high surrogate */ - srclen <= 1 || /* missing low surrogate */ - src[1] < 0xdc00 || src[1] > 0xdfff) /* invalid low surrogate */ - return 0; - return 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff); - } - return src[0]; -} - -/* query necessary dst length for src string */ -static int Ucs2toUtf8Len(const wchar_t *src, unsigned int srclen) -{ - int len; - unsigned int val; - - for (len = 0; srclen; srclen--, src++) { - if (*src < 0x80) { /* 0x00-0x7f: 1 byte */ - len++; - continue; - } - if (*src < 0x800) { /* 0x80-0x7ff: 2 bytes */ - len += 2; - continue; - } - if ( !(val = getSurrogateValue(src, srclen))) - return -2; - - if (val < 0x10000) /* 0x800-0xffff: 3 bytes */ - len += 3; - else { /* 0x10000-0x10ffff: 4 bytes */ - len += 4; - src++; - srclen--; - } - } - return len; -} - -MIR_CORE_DLL(int) Ucs2toUtf8Len(const wchar_t *src) -{ - if (src == 0) - return 0; - - return Ucs2toUtf8Len(src, (int)wcslen(src)); -} - -/* wide char to UTF-8 string conversion */ -/* return -1 on dst buffer overflow, -2 on invalid input char */ -int Ucs2toUtf8(const wchar_t *src, int srclen, char *dst, int dstlen) -{ - int len; - - for (len = dstlen; srclen; srclen--, src++) - { - WCHAR ch = *src; - unsigned int val; - - if (ch < 0x80) /* 0x00-0x7f: 1 byte */ - { - if ( !len--) return -1; /* overflow */ - *dst++ = ch; - continue; - } - - if (ch < 0x800) /* 0x80-0x7ff: 2 bytes */ - { - if ((len -= 2) < 0) return -1; /* overflow */ - dst[1] = 0x80 | (ch & 0x3f); - ch >>= 6; - dst[0] = 0xc0 | ch; - dst += 2; - continue; - } - - if ( !(val = getSurrogateValue(src, srclen))) - { - return -2; - } - - if (val < 0x10000) /* 0x800-0xffff: 3 bytes */ - { - if ((len -= 3) < 0) return -1; /* overflow */ - dst[2] = 0x80 | (val & 0x3f); - val >>= 6; - dst[1] = 0x80 | (val & 0x3f); - val >>= 6; - dst[0] = 0xe0 | val; - dst += 3; - } - else /* 0x10000-0x10ffff: 4 bytes */ - { - if ((len -= 4) < 0) return -1; /* overflow */ - dst[3] = 0x80 | (val & 0x3f); - val >>= 6; - dst[2] = 0x80 | (val & 0x3f); - val >>= 6; - dst[1] = 0x80 | (val & 0x3f); - val >>= 6; - dst[0] = 0xf0 | val; - dst += 4; - src++; - srclen--; - } - } - return dstlen - len; -} - -/* helper for the various utf8 mbstowcs functions */ -static unsigned int decodeUtf8Char(unsigned char ch, const char **str, const char *strend) -{ - unsigned int len = utf8_length[ch-0x80]; - unsigned int res = ch & utf8_mask[len]; - const char *end = *str + len; - - if (end > strend) return ~0; - switch(len) - { - case 3: - if ((ch = end[-3] ^ 0x80) >= 0x40) break; - res = (res << 6) | ch; - (*str)++; - case 2: - if ((ch = end[-2] ^ 0x80) >= 0x40) break; - res = (res << 6) | ch; - (*str)++; - case 1: - if ((ch = end[-1] ^ 0x80) >= 0x40) break; - res = (res << 6) | ch; - (*str)++; - if (res < utf8_minval[len]) break; - return res; - } - return ~0; -} - -/* query necessary dst length for src string */ -static inline int Utf8toUcs2Len(const char *src, int srclen) -{ - int ret = 0; - unsigned int res; - const char *srcend = src + srclen; - - while (src < srcend) - { - unsigned char ch = *src++; - if (ch < 0x80) /* special fast case for 7-bit ASCII */ - { - ret++; - continue; - } - if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0x10ffff) - { - if (res > 0xffff) ret++; - ret++; - } - else return -2; /* bad char */ - /* otherwise ignore it */ - } - return ret; -} - -/* UTF-8 to wide char string conversion */ -/* return -1 on dst buffer overflow, -2 on invalid input char */ -int Utf8toUcs2(const char *src, int srclen, wchar_t *dst, int dstlen) -{ - unsigned int res; - const char *srcend = src + srclen; - wchar_t *dstend = dst + dstlen; - - while ((dst < dstend) && (src < srcend)) - { - unsigned char ch = *src++; - if (ch < 0x80) /* special fast case for 7-bit ASCII */ - { - *dst++ = ch; - continue; - } - if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0xffff) - { - *dst++ = res; - } - else if (res <= 0x10ffff) /* we need surrogates */ - { - if (dst == dstend - 1) return -1; /* overflow */ - res -= 0x10000; - *dst++ = 0xd800 | (res >> 10); - *dst++ = 0xdc00 | (res & 0x3ff); - } - else return -2; /* bad char */ - /* otherwise ignore it */ - } - if (src < srcend) return -1; /* overflow */ - return dstlen - (dstend - dst); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format - -MIR_CORE_DLL(char*) Utf8DecodeCP(char *str, int codepage, wchar_t **ucs2) -{ - int len; - bool needs_free = false; - wchar_t* tempBuf = NULL; - if (ucs2) - *ucs2 = NULL; - - if (str == NULL) - return NULL; - - len = (int)strlen(str); - - if (len < 2) { - if (ucs2 != NULL) { - *ucs2 = tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); - MultiByteToWideChar(codepage, 0, str, len, tempBuf, len); - tempBuf[len] = 0; - } - return str; - } - - int destlen = Utf8toUcs2Len(str, len); - if (destlen < 0) - return NULL; - - if (ucs2 == NULL) { - __try - { - tempBuf = (wchar_t*)alloca((destlen + 1) * sizeof(wchar_t)); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - tempBuf = NULL; - needs_free = true; - } - } - - if (tempBuf == NULL) { - tempBuf = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t)); - if (tempBuf == NULL) - return NULL; - } - - Utf8toUcs2(str, len, tempBuf, destlen); - tempBuf[destlen] = 0; - WideCharToMultiByte(codepage, 0, tempBuf, -1, str, len + 1, "?", NULL); - - if (ucs2) - *ucs2 = tempBuf; - else if (needs_free) - mir_free(tempBuf); - - return str; -} - -MIR_CORE_DLL(char*) Utf8Decode(char *str, wchar_t **ucs2) -{ - return Utf8DecodeCP(str, Langpack_GetDefaultCodePage(), ucs2); -} - -MIR_CORE_DLL(wchar_t*) Utf8DecodeW(const char *str) -{ - if (str == NULL) - return NULL; - - int len = (int)strlen(str); - - int destlen = Utf8toUcs2Len(str, len); - if (destlen < 0) return NULL; - - wchar_t* ucs2 = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t)); - if (ucs2 == NULL) return NULL; - - if (Utf8toUcs2(str, len, ucs2, destlen) >= 0) - { - ucs2[destlen] = 0; - return ucs2; - } - - mir_free(ucs2); - - return NULL; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Utf8Encode - converts MBCS string to the UTF8-encoded format - -MIR_CORE_DLL(char*) Utf8EncodeCP(const char* src, int codepage) -{ - int len; - bool needs_free = false; - char* result = NULL; - wchar_t* tempBuf; - - if (src == NULL) - return NULL; - - len = (int)strlen(src); - - __try - { - tempBuf = (wchar_t*)alloca((len + 1) * sizeof(wchar_t)); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); - if (tempBuf == NULL) return NULL; - needs_free = true; - } - - len = MultiByteToWideChar(codepage, 0, src, -1, tempBuf, len + 1); - - int destlen = Ucs2toUtf8Len(tempBuf, len); - if (destlen >= 0) - { - result = (char*)mir_alloc(destlen + 1); - if (result) - { - Ucs2toUtf8(tempBuf, len, result, destlen); - result[destlen] = 0; - } - } - - if (needs_free) - mir_free(tempBuf); - - return result; -} - -MIR_CORE_DLL(char*) Utf8Encode(const char* src) -{ - return Utf8EncodeCP(src, Langpack_GetDefaultCodePage()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Utf8Encode - converts UCS2 string to the UTF8-encoded format - -MIR_CORE_DLL(char*) Utf8EncodeW(const wchar_t* src) -{ - if (src == NULL) - return NULL; - - int len = (int)wcslen(src); - - int destlen = Ucs2toUtf8Len(src, len); - if (destlen < 0) return NULL; - - char* result = (char*)mir_alloc(destlen + 1); - if (result == NULL) - return NULL; - - Ucs2toUtf8(src, len, result, destlen); - result[destlen] = 0; - - return result; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Utf8Encode - converts UCS2 string to the UTF8-encoded format - -MIR_CORE_DLL(BOOL) Utf8CheckString(const char *str) -{ - int expect_bytes = 0, utf_found = 0; - - if (!str) return 0; - - while (*str) { - if ((*str & 0x80) == 0) { - /* Looks like an ASCII character */ - if (expect_bytes) - /* byte of UTF-8 character expected */ - return 0; - } - else { - /* Looks like byte of an UTF-8 character */ - if (expect_bytes) { - /* expect_bytes already set: first byte of UTF-8 char already seen */ - if ((*str & 0xC0) != 0x80) { - /* again first byte ?!?! */ - return 0; - } - } - else { - /* First byte of the UTF-8 character */ - /* count initial one bits and set expect_bytes to 1 less */ - char ch = *str; - while (ch & 0x80) { - expect_bytes++; - ch = (ch & 0x7f) << 1; - } - } - /* OK, next byte of UTF-8 character */ - /* Decrement number of expected bytes */ - if (--expect_bytes == 0) - utf_found = 1; - } - str++; - } - - return (utf_found && expect_bytes == 0); -} diff --git a/src/mir_core/utils.cpp b/src/mir_core/utils.cpp deleted file mode 100644 index bf05b84b6e..0000000000 --- a/src/mir_core/utils.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "commonheaders.h" - -MIR_CORE_DLL(char*) replaceStr(char* &dest, const char *src) -{ - if (dest != NULL) - mir_free(dest); - - return dest = (src != NULL) ? mir_strdup(src) : NULL; -} - -MIR_CORE_DLL(WCHAR*) replaceStrW(WCHAR* &dest, const WCHAR *src) -{ - if (dest != NULL) - mir_free(dest); - - return dest = (src != NULL) ? mir_wstrdup(src) : NULL; -} - -MIR_CORE_DLL(char*) rtrim(char *str) -{ - if (str == NULL) - return NULL; - - char* p = strchr(str, 0); - while (--p >= str) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - *p = 0; break; - default: - return str; - } - } - return str; -} - -MIR_CORE_DLL(WCHAR*) rtrimw(WCHAR *str) -{ - if (str == NULL) - return NULL; - - WCHAR *p = _tcschr(str, 0); - while (--p >= str) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - *p = 0; break; - default: - return str; - } - } - return str; -} - -MIR_CORE_DLL(char*) ltrim(char *str) -{ - if (str == NULL) - return NULL; - - char* p = str; - for (;;) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - ++p; break; - default: - memmove(str, p, strlen(p) + 1); - return str; - } - } -} - -MIR_CORE_DLL(WCHAR*) ltrimw(WCHAR *str) -{ - if (str == NULL) - return NULL; - - WCHAR *p = str; - for (;;) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - ++p; break; - default: - memmove(str, p, sizeof(WCHAR)*(wcslen(p) + 1)); - return str; - } - } -} - -MIR_CORE_DLL(char*) ltrimp(char *str) -{ - if (str == NULL) - return NULL; - - char *p = str; - for (;;) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - ++p; break; - default: - return p; - } - } -} - -MIR_CORE_DLL(WCHAR*) ltrimpw(WCHAR *str) -{ - if (str == NULL) - return NULL; - - WCHAR *p = str; - for (;;) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - ++p; break; - default: - return p; - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(int) wildcmp(const char *name, const char *mask) -{ - if (name == NULL || mask == NULL) - return false; - - const char *last = '\0'; - for (;; mask++, name++) { - if (*mask != '?' && *mask != *name) break; - if (*name == '\0') return ((BOOL)!*mask); - } - if (*mask != '*') return FALSE; - for (;; mask++, name++) { - while (*mask == '*') { - last = mask++; - if (*mask == '\0') return ((BOOL)!*mask); /* true */ - } - if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ - if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last; - } -} - -MIR_CORE_DLL(int) wildcmpw(const WCHAR *name, const WCHAR *mask) -{ - if (name == NULL || mask == NULL) - return false; - - const WCHAR* last = '\0'; - for (;; mask++, name++) { - if (*mask != '?' && *mask != *name) break; - if (*name == '\0') return ((BOOL)!*mask); - } - if (*mask != '*') return FALSE; - for (;; mask++, name++) { - while (*mask == '*') { - last = mask++; - if (*mask == '\0') return ((BOOL)!*mask); /* true */ - } - if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ - if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last; - } -} - -#define _qtoupper(_c) (((_c) >= 'a' && (_c) <= 'z')?((_c)-'a'+'A'):(_c)) - -MIR_CORE_DLL(int) wildcmpi(const char *name, const char *mask) -{ - if (name == NULL || mask == NULL) - return false; - - const char *last = NULL; - for (;; mask++, name++) { - if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) break; - if (*name == '\0') return ((BOOL)!*mask); - } - if (*mask != '*') return FALSE; - for (;; mask++, name++) { - while (*mask == '*') { - last = mask++; - if (*mask == '\0') return ((BOOL)!*mask); /* true */ - } - if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ - if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) name -= (size_t)(mask - last) - 1, mask = last; - } -} - -MIR_CORE_DLL(int) wildcmpiw(const WCHAR *name, const WCHAR *mask) -{ - if (name == NULL || mask == NULL) - return false; - - const WCHAR* last = NULL; - for (;; mask++, name++) { - if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) break; - if (*name == '\0') return ((BOOL)!*mask); - } - if (*mask != '*') return FALSE; - for (;; mask++, name++) { - while (*mask == '*') { - last = mask++; - if (*mask == '\0') return ((BOOL)!*mask); /* true */ - } - if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ - if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) name -= (size_t)(mask - last) - 1, mask = last; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static char szHexTable[] = "0123456789abcdef"; - -MIR_CORE_DLL(char*) bin2hex(const void *pData, size_t len, char *dest) -{ - const BYTE *p = (const BYTE*)pData; - char *d = dest; - - for (size_t i = 0; i < len; i++, p++) { - *d++ = szHexTable[*p >> 4]; - *d++ = szHexTable[*p & 0x0F]; - } - *d = 0; - - return dest; -} - -MIR_CORE_DLL(WCHAR*) bin2hexW(const void *pData, size_t len, WCHAR *dest) -{ - const BYTE *p = (const BYTE*)pData; - WCHAR *d = dest; - - for (size_t i = 0; i < len; i++, p++) { - *d++ = szHexTable[*p >> 4]; - *d++ = szHexTable[*p & 0x0F]; - } - *d = 0; - - return dest; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#pragma intrinsic(strlen, strcpy, strcat, strcmp, wcslen, wcscpy, wcscat, wcscmp) - -MIR_CORE_DLL(size_t) mir_strlen(const char *p) -{ - return (p) ? strlen(p) : 0; -} - -MIR_CORE_DLL(size_t) mir_wstrlen(const wchar_t *p) -{ - return (p) ? wcslen(p) : 0; -} - -MIR_CORE_DLL(char*) mir_strcpy(char *dest, const char *src) -{ - if (dest == NULL) - return NULL; - - if (src == NULL) { - *dest = 0; - return dest; - } - - return strcpy(dest, src); -} - -MIR_CORE_DLL(wchar_t*) mir_wstrcpy(wchar_t *dest, const wchar_t *src) -{ - if (dest == NULL) - return NULL; - - if (src == NULL) { - *dest = 0; - return dest; - } - - return wcscpy(dest, src); -} - -MIR_CORE_DLL(char*) mir_strncpy(char *dest, const char *src, size_t len) -{ - if (dest == NULL) - return NULL; - - if (src == NULL) - *dest = 0; - else - strncpy_s(dest, len, src, _TRUNCATE); - return dest; -} - -MIR_CORE_DLL(wchar_t*) mir_wstrncpy(wchar_t *dest, const wchar_t *src, size_t len) -{ - if (dest == NULL) - return NULL; - - if (src == NULL) - *dest = 0; - else - wcsncpy_s(dest, len, src, _TRUNCATE); - return dest; -} - -MIR_CORE_DLL(char*) mir_strcat(char *dest, const char *src) -{ - if (dest == NULL) - return NULL; - - if (src == NULL) { - *dest = 0; - return dest; - } - - return strcat(dest, src); -} - -MIR_CORE_DLL(wchar_t*) mir_wstrcat(wchar_t *dest, const wchar_t *src) -{ - if (dest == NULL) - return NULL; - - if (src == NULL) { - *dest = 0; - return dest; - } - - return wcscat(dest, src); -} - -MIR_CORE_DLL(char*) mir_strncat(char *dest, const char *src, size_t len) -{ - if (dest == NULL) - return NULL; - - if (src == NULL) - *dest = 0; - else - strncat_s(dest, len, src, _TRUNCATE); - return dest; -} - -MIR_CORE_DLL(wchar_t*) mir_wstrncat(wchar_t *dest, const wchar_t *src, size_t len) -{ - if (dest == NULL) - return NULL; - - if (src == NULL) - *dest = 0; - else - wcsncat_s(dest, len, src, _TRUNCATE); - return dest; -} - -MIR_CORE_DLL(int) mir_strcmp(const char *p1, const char *p2) -{ - if (p1 == NULL) - return (p2 == NULL) ? 0 : -1; - if (p2 == NULL) - return 1; - return CompareStringA(LOCALE_USER_DEFAULT, 0, p1, -1, p2, -1) - 2; -} - -MIR_CORE_DLL(int) mir_wstrcmp(const wchar_t *p1, const wchar_t *p2) -{ - if (p1 == NULL) - return (p2 == NULL) ? 0 : -1; - if (p2 == NULL) - return 1; - return CompareStringW(LOCALE_USER_DEFAULT, 0, p1, -1, p2, -1) - 2; -} - -MIR_CORE_DLL(int) mir_strcmpi(const char *p1, const char *p2) -{ - if (p1 == NULL) - return (p2 == NULL) ? 0 : -1; - if (p2 == NULL) - return 1; - return CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, p1, -1, p2, -1) - 2; -} - -MIR_CORE_DLL(int) mir_wstrcmpi(const wchar_t *p1, const wchar_t *p2) -{ - if (p1 == NULL) - return (p2 == NULL) ? 0 : -1; - if (p2 == NULL) - return 1; - return CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, p1, -1, p2, -1) - 2; -} diff --git a/src/mir_core/winver.cpp b/src/mir_core/winver.cpp deleted file mode 100644 index ad011a8e40..0000000000 --- a/src/mir_core/winver.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "commonheaders.h" - -static int dwWinVer; - -void InitWinver() -{ - DWORD dwVer = LOWORD( GetVersion()); - dwWinVer = MAKEWORD(HIBYTE(dwVer), LOBYTE(dwVer)); -} - -MIR_CORE_DLL(BOOL) IsWinVerVistaPlus() -{ - return dwWinVer >= _WIN32_WINNT_VISTA; -} - -MIR_CORE_DLL(BOOL) IsWinVer7Plus() -{ - return dwWinVer >= _WIN32_WINNT_WIN7; -} - -MIR_CORE_DLL(BOOL) IsFullScreen() -{ - RECT rcScreen = {0}; - - rcScreen.right = GetSystemMetrics(SM_CXSCREEN); - rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN); - - HMONITOR hMon = MonitorFromWindow(GetForegroundWindow(), MONITOR_DEFAULTTONEAREST); - MONITORINFO mi; - mi.cbSize = sizeof(mi); - if (GetMonitorInfo(hMon, &mi)) - rcScreen = mi.rcMonitor; - - HWND hWndDesktop = GetDesktopWindow(); - HWND hWndShell = GetShellWindow(); - - // check foregroundwindow - HWND hWnd = GetForegroundWindow(); - if (hWnd && hWnd != hWndDesktop && hWnd != hWndShell) { - TCHAR tszClassName[128] = _T(""); - GetClassName(hWnd, tszClassName, SIZEOF(tszClassName)); - if ( _tcscmp(tszClassName, _T("WorkerW"))) { - RECT rect, rectw, recti; - GetWindowRect(hWnd, &rectw); - - GetClientRect(hWnd, &rect); - ClientToScreen(hWnd, (LPPOINT)&rect); - ClientToScreen(hWnd, (LPPOINT)&rect.right); - - if (EqualRect(&rect, &rectw) && IntersectRect(&recti, &rect, &rcScreen) && EqualRect(&recti, &rcScreen)) - return true; - } - } - - return false; -} - -MIR_CORE_DLL(BOOL) IsWorkstationLocked(void) -{ - HDESK hDesk = OpenInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP); - if (hDesk == NULL) - return true; - - TCHAR tszName[100]; - DWORD cbName; - BOOL bLocked = (!GetUserObjectInformation(hDesk, UOI_NAME, tszName, SIZEOF(tszName), &cbName) || mir_tstrcmpi(tszName,_T("default")) != 0); - CloseDesktop(hDesk); - return bLocked; -} - -MIR_CORE_DLL(BOOL) IsScreenSaverRunning(void) -{ - BOOL rc = FALSE; - SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &rc, FALSE); - return rc != 0; -} -- cgit v1.2.3