From 1ce002432b3a5c0bb0a4c9f9eb8d399d649fe283 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 6 Jul 2012 08:31:38 +0000 Subject: - mir_core.dll moved to the core :) - plugins now obtain the fake langpack id if langpack is absent git-svn-id: http://svn.miranda-ng.org/main/trunk@787 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/core/miranda.h | 6 +- src/mir_core/commonheaders.cpp | 2 + src/mir_core/commonheaders.h | 63 +++ src/mir_core/db.cpp | 191 ++++++++++ src/mir_core/langpack.cpp | 631 +++++++++++++++++++++++++++++++ src/mir_core/lists.cpp | 278 ++++++++++++++ src/mir_core/md5.cpp | 358 ++++++++++++++++++ src/mir_core/memory.cpp | 280 ++++++++++++++ src/mir_core/mir_core.def | 126 ++++++ src/mir_core/mir_core_10.vcxproj | 238 ++++++++++++ src/mir_core/mir_core_10.vcxproj.filters | 76 ++++ src/mir_core/miranda.cpp | 97 +++++ src/mir_core/miranda.h | 131 +++++++ src/mir_core/modules.cpp | 601 +++++++++++++++++++++++++++++ src/mir_core/path.cpp | 210 ++++++++++ src/mir_core/sha1.cpp | 155 ++++++++ src/mir_core/threads.cpp | 372 ++++++++++++++++++ src/mir_core/utf.cpp | 406 ++++++++++++++++++++ src/mir_core/utils.cpp | 150 ++++++++ src/modules/icolib/extracticon.cpp | 2 +- src/modules/langpack/lpservices.cpp | 4 +- src/modules/options/options.cpp | 2 - src/modules/plugins/newplugins.cpp | 102 +++-- src/modules/plugins/pluginopts.cpp | 2 +- src/modules/plugins/plugins.h | 3 +- 25 files changed, 4437 insertions(+), 49 deletions(-) create mode 100644 src/mir_core/commonheaders.cpp create mode 100644 src/mir_core/commonheaders.h create mode 100644 src/mir_core/db.cpp create mode 100644 src/mir_core/langpack.cpp create mode 100644 src/mir_core/lists.cpp create mode 100644 src/mir_core/md5.cpp create mode 100644 src/mir_core/memory.cpp create mode 100644 src/mir_core/mir_core.def create mode 100644 src/mir_core/mir_core_10.vcxproj create mode 100644 src/mir_core/mir_core_10.vcxproj.filters create mode 100644 src/mir_core/miranda.cpp create mode 100644 src/mir_core/miranda.h create mode 100644 src/mir_core/modules.cpp create mode 100644 src/mir_core/path.cpp create mode 100644 src/mir_core/sha1.cpp create mode 100644 src/mir_core/threads.cpp create mode 100644 src/mir_core/utf.cpp create mode 100644 src/mir_core/utils.cpp (limited to 'src') diff --git a/src/core/miranda.h b/src/core/miranda.h index 3b08c636ba..c1dcb75f95 100644 --- a/src/core/miranda.h +++ b/src/core/miranda.h @@ -128,6 +128,11 @@ void KillModuleSounds(int hLangpack); extern HINSTANCE hInst; extern HANDLE hOkToExitEvent, hModulesLoadedEvent, hevLoadModule, hevUnloadModule; +/**** newplugins.cpp *******************************************************************/ + +char* GetPluginNameByInstance(HINSTANCE hInstance); +int GetPluginFakeId(const MUUID &uuid, int hLangpack); + /**** utf.cpp **************************************************************************/ __forceinline char* Utf8DecodeA(const char* src) @@ -247,6 +252,5 @@ public: extern "C" { - MIR_CORE_DLL(int) Langpack_GetPluginHandle(PLUGININFOEX* pInfo); MIR_CORE_DLL(int) Langpack_MarkPluginLoaded(PLUGININFOEX* pInfo); }; diff --git a/src/mir_core/commonheaders.cpp b/src/mir_core/commonheaders.cpp new file mode 100644 index 0000000000..95b2201163 --- /dev/null +++ b/src/mir_core/commonheaders.cpp @@ -0,0 +1,2 @@ +#include "commonheaders.h" + diff --git a/src/mir_core/commonheaders.h b/src/mir_core/commonheaders.h new file mode 100644 index 0000000000..2d04e12f4b --- /dev/null +++ b/src/mir_core/commonheaders.h @@ -0,0 +1,63 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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 MIRANDA_VER 0x0A00 + +#define WINVER 0x0700 +#define _WIN32_WINNT 0x0700 +#define _WIN32_IE 0x0601 + +#define INCL_WINSOCK_API_TYPEDEFS 1 + +#include "m_stdhdr.h" + +#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 diff --git a/src/mir_core/db.cpp b/src/mir_core/db.cpp new file mode 100644 index 0000000000..37b89d8399 --- /dev/null +++ b/src/mir_core/db.cpp @@ -0,0 +1,191 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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(int) db_get_b(HANDLE hContact, const char *szModule, const char *szSetting, int errorValue) +{ + DBVARIANT dbv; + DBCONTACTGETSETTING cgs; + cgs.szModule = szModule; + cgs.szSetting = szSetting; + cgs.pValue = &dbv; + if (CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&cgs)) + return errorValue; + return dbv.bVal; +} + +MIR_CORE_DLL(int) db_get_w(HANDLE hContact, const char *szModule, const char *szSetting, int errorValue) +{ + DBVARIANT dbv; + DBCONTACTGETSETTING cgs; + cgs.szModule = szModule; + cgs.szSetting = szSetting; + cgs.pValue = &dbv; + if (CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&cgs)) + return errorValue; + return dbv.wVal; +} + +MIR_CORE_DLL(DWORD) db_get_dw(HANDLE hContact, const char *szModule, const char *szSetting, DWORD errorValue) +{ + DBVARIANT dbv; + DBCONTACTGETSETTING cgs; + cgs.szModule = szModule; + cgs.szSetting = szSetting; + cgs.pValue = &dbv; + if (CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&cgs)) + return errorValue; + return dbv.dVal; +} + +MIR_CORE_DLL(INT_PTR) db_get(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) +{ + DBCONTACTGETSETTING cgs; + cgs.szModule = szModule; + cgs.szSetting = szSetting; + cgs.pValue = dbv; + + return CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&cgs); +} + +MIR_CORE_DLL(INT_PTR) db_get_s(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType) +{ + DBCONTACTGETSETTING cgs; + cgs.szModule = szModule; + cgs.szSetting = szSetting; + cgs.pValue = dbv; + dbv->type = (BYTE)nType; + return CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&cgs); +} + +MIR_CORE_DLL(char*) db_get_sa(HANDLE hContact, const char *szModule, const char *szSetting) +{ + char *str = NULL; + DBVARIANT dbv = {0}; + db_get_s(hContact, szModule, szSetting, &dbv, DBVT_ASCIIZ); + if (dbv.type == DBVT_ASCIIZ) + str = mir_strdup(dbv.pszVal); + DBFreeVariant(&dbv); + return str; +} + +MIR_CORE_DLL(wchar_t*) db_get_wsa(HANDLE hContact, const char *szModule, const char *szSetting) +{ + wchar_t *str = NULL; + DBVARIANT dbv={0}; + db_get_s(hContact, szModule, szSetting, &dbv, DBVT_WCHAR); + if (dbv.type == DBVT_WCHAR) + str = mir_wstrdup(dbv.pwszVal); + DBFreeVariant(&dbv); + return str; +} + +MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv) +{ + return CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)dbv); +} + +MIR_CORE_DLL(INT_PTR) db_unset(HANDLE hContact, const char *szModule, const char *szSetting) +{ + DBCONTACTGETSETTING cgs; + cgs.szModule = szModule; + cgs.szSetting = szSetting; + return CallService(MS_DB_CONTACT_DELETESETTING, (WPARAM)hContact, (LPARAM)&cgs); +} + +MIR_CORE_DLL(INT_PTR) db_set_b(HANDLE hContact, const char *szModule, const char *szSetting, BYTE val) +{ + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_BYTE; + cws.value.bVal = val; + return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_w(HANDLE hContact, const char *szModule, const char *szSetting, WORD val) +{ + DBCONTACTWRITESETTING cws; + + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_WORD; + cws.value.wVal = val; + return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_dw(HANDLE hContact, const char *szModule, const char *szSetting, DWORD val) +{ + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_DWORD; + cws.value.dVal = val; + return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_s(HANDLE hContact, const char *szModule, const char *szSetting, const char *val) +{ + DBCONTACTWRITESETTING cws; + + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_ASCIIZ; + cws.value.pszVal = (char*)val; + return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_ws(HANDLE hContact, const char *szModule, const char *szSetting, const WCHAR *val) +{ + DBCONTACTWRITESETTING cws; + + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_WCHAR; + cws.value.pwszVal = (WCHAR*)val; + return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_utf(HANDLE hContact, const char *szModule, const char *szSetting, const char *val) +{ + DBCONTACTWRITESETTING cws; + + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_UTF8; + cws.value.pszVal = (char*)val; + return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_blob(HANDLE hContact, const char *szModule, const char *szSetting, void *val, unsigned len) +{ + 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 CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws); +} diff --git a/src/mir_core/langpack.cpp b/src/mir_core/langpack.cpp new file mode 100644 index 0000000000..015af8f469 --- /dev/null +++ b/src/mir_core/langpack.cpp @@ -0,0 +1,631 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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 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 BOOL bModuleInitialized = FALSE; + +struct LangPackEntry { + DWORD englishHash; + char *local; + wchar_t *wlocal; + MUUID* pMuuid; + LangPackEntry* pNext; // for langpack items with the same hash value +}; + +struct LangPackStruct { + TCHAR filename[MAX_PATH]; + TCHAR filePath[MAX_PATH]; + char language[64]; + char lastModifiedUsing[64]; + char authors[256]; + char authorEmail[128]; + LangPackEntry *entry; + int entryCount, entriesAlloced; + LCID localeID; + UINT defaultANSICp; +} static langPack; + +static int IsEmpty(char *str) +{ + int i = 0; + + while (str[i]) + { + if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') + return 0; + i++; + } + return 1; +} + +static void ConvertBackslashes(char *str, UINT fileCp) +{ + char *pstr; + for (pstr = str; *pstr; pstr = CharNextExA(fileCp, pstr, 0)) { + if (*pstr == '\\') { + switch(pstr[1]) { + case 'n': *pstr = '\n'; break; + case 't': *pstr = '\t'; break; + case 'r': *pstr = '\r'; break; + default: *pstr = pstr[1]; break; + } + memmove(pstr+1, pstr+2, strlen(pstr+2) + 1); +} } } + +#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, UINT fileCp) +{ + 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* fileName = mir_a2t(ltrim(line+9)); + mir_sntprintf(tszFileName, SIZEOF(tszFileName), _T("%s%s"), langPack.filePath, fileName); + mir_free(fileName); + + FILE* p = _tfopen(tszFileName, _T("r")); + if (p) { + line[0] = 0; + fgets(line, SIZEOF(line), p); + + UINT fileCp = CP_ACP; + if (strlen(line) >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf') { + fileCp = CP_UTF8; + fseek(p, 3, SEEK_SET); + } + else { + fileCp = langPack.defaultANSICp; + fseek(p, 0, SEEK_SET); + } + + LoadLangPackFile(p, line, fileCp); + fclose(p); + } + } + 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; + } + + ConvertBackslashes(line, fileCp); + + if (line[0] == '[' && line[ lstrlenA(line)-1 ] == ']') { + if (langPack.entryCount && langPack.entry[ langPack.entryCount-1].local == NULL) + langPack.entryCount--; + + char* pszLine = line+1; + line[ lstrlenA(line)-1 ] = '\0'; + if (++langPack.entryCount > langPack.entriesAlloced) { + langPack.entriesAlloced += 128; + langPack.entry = (LangPackEntry*)mir_realloc(langPack.entry, sizeof(LangPackEntry)*langPack.entriesAlloced); + } + + LangPackEntry* E = &langPack.entry[ langPack.entryCount-1 ]; + E->englishHash = mir_hashstr(pszLine); + E->local = NULL; + E->wlocal = NULL; + E->pMuuid = pCurrentMuuid; + E->pNext = NULL; + continue; + } + + if ( !langPack.entryCount) + continue; + + LangPackEntry* E = &langPack.entry[ langPack.entryCount-1 ]; + if (E->local == NULL) { + E->local = mir_strdup(line); + if (fileCp == CP_UTF8) + Utf8DecodeCP(E->local, langPack.defaultANSICp, NULL); + + int iNeeded = MultiByteToWideChar(fileCp, 0, line, -1, 0, 0); + E->wlocal = (wchar_t *)mir_alloc((iNeeded+1) * sizeof(wchar_t)); + MultiByteToWideChar(fileCp, 0, line, -1, E->wlocal, iNeeded); + } + else { + size_t iOldLenA = strlen(E->local); + E->local = (char*)mir_realloc(E->local, iOldLenA + strlen(line) + 2); + strcat(E->local, "\n"); + strcat(E->local, line); + + if (fileCp == CP_UTF8) + Utf8DecodeCP(E->local + iOldLenA + 1, langPack.defaultANSICp, NULL); + + int iNeeded = MultiByteToWideChar(fileCp, 0, line, -1, 0, 0); + size_t iOldLen = wcslen(E->wlocal); + E->wlocal = (wchar_t*)mir_realloc(E->wlocal, (sizeof(wchar_t) * (iOldLen + iNeeded + 2))); + wcscat(E->wlocal, L"\n"); + MultiByteToWideChar(fileCp, 0, line, -1, E->wlocal + iOldLen + 1, iNeeded); + } + } +} + +MIR_CORE_DLL(int) LoadLangPack(const TCHAR *szLangPack) +{ + int startOfLine=0; + USHORT langID; + + lstrcpy(langPack.filename, szLangPack); + lstrcpy(langPack.filePath, szLangPack); + TCHAR* p = _tcsrchr(langPack.filePath, '\\'); + if (p) + p[1] = 0; + + FILE *fp = _tfopen(szLangPack, _T("rt")); + if (fp == NULL) + return 1; + + char line[ LANGPACK_BUF_SIZE ] = ""; + fgets(line, SIZEOF(line), fp); + + UINT fileCp = CP_ACP; + size_t lineLen = strlen(line); + if (lineLen >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf') + { + fileCp = CP_UTF8; + memmove(line, line + 3, lineLen - 2); + } + + lrtrim(line); + if (lstrcmpA(line, "Miranda Language Pack Version 1")) { + fclose(fp); + return 2; + } + + //headers + while ( !feof(fp)) { + startOfLine = ftell(fp); + if (fgets(line, SIZEOF(line), 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) { + fclose(fp); + return 3; + } + + *pszColon++ = 0; + if ( !lstrcmpA(line, "Language")) {mir_snprintf(langPack.language, sizeof(langPack.language), "%s", pszColon); lrtrim(langPack.language);} + else if ( !lstrcmpA(line, "Last-Modified-Using")) {mir_snprintf(langPack.lastModifiedUsing, sizeof(langPack.lastModifiedUsing), "%s", pszColon); lrtrim(langPack.lastModifiedUsing);} + else if ( !lstrcmpA(line, "Authors")) {mir_snprintf(langPack.authors, sizeof(langPack.authors), "%s", pszColon); lrtrim(langPack.authors);} + else if ( !lstrcmpA(line, "Author-email")) {mir_snprintf(langPack.authorEmail, sizeof(langPack.authorEmail), "%s", pszColon); lrtrim(langPack.authorEmail);} + else if ( !lstrcmpA(line, "Locale")) { + char szBuf[20], *stopped; + + lrtrim(pszColon + 1); + langID = (USHORT)strtol(pszColon, &stopped, 16); + langPack.localeID = MAKELCID(langID, 0); + GetLocaleInfoA(langPack.localeID, LOCALE_IDEFAULTANSICODEPAGE, szBuf, 10); + szBuf[5] = 0; // codepages have max. 5 digits + langPack.defaultANSICp = atoi(szBuf); + if (fileCp == CP_ACP) + fileCp = langPack.defaultANSICp; + } + } + + //body + fseek(fp, startOfLine, SEEK_SET); + langPack.entriesAlloced = 0; + + LoadLangPackFile(fp, line, fileCp); + fclose(fp); + pCurrentMuuid = NULL; + + qsort(langPack.entry, langPack.entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +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 (langPack.entryCount == 0 || szEnglish == NULL) + return (char*)szEnglish; + + LangPackEntry key, *entry; + key.englishHash = W ? hashstrW(szEnglish) : mir_hashstr(szEnglish); + entry = (LangPackEntry*)bsearch(&key, langPack.entry, langPack.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; + } } } + + return W ? (char *)entry->wlocal : entry->local; +} + +MIR_CORE_DLL(int) Langpack_GetDefaultCodePage() +{ + return langPack.defaultANSICp; +} + +MIR_CORE_DLL(int) Langpack_GetDefaultLocale() +{ + return (langPack.localeID == 0) ? LOCALE_USER_DEFAULT : langPack.localeID; +} + +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; + mii.cbSize = MENUITEMINFO_V4_SIZE; + 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 ( !lstrcmpi(szClass, _T("static")) || !lstrcmpi(szClass, _T("hyperlink")) || !lstrcmpi(szClass, _T("button")) || !lstrcmpi(szClass, _T("MButtonClass")) || !lstrcmpi(szClass, _T("MHeaderbarCtrl"))) + TranslateWindow(uuid, hwnd); + else if ( !lstrcmpi(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 (langPack.entryCount == 0) + return; + + LangPackEntry *s = langPack.entry+1, *d = s, *pLast = langPack.entry; + DWORD dwSavedHash = langPack.entry->englishHash; + bool bSortNeeded = false; + + for (int i=1; i < langPack.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) { + langPack.entryCount = (int)(d - langPack.entry); + qsort(langPack.entry, langPack.entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(int) LoadLangPackModule(void) +{ + bModuleInitialized = TRUE; + + ZeroMemory(&langPack, sizeof(langPack)); + + TCHAR szSearch[MAX_PATH]; + PathToAbsoluteT(_T("langpack_*.txt"), szSearch, NULL); + + WIN32_FIND_DATA fd; + HANDLE hFind = FindFirstFile(szSearch, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + PathToAbsoluteT(fd.cFileName, szSearch, NULL); + FindClose(hFind); + LoadLangPack(szSearch); + } + return 0; +} + +void UnloadLangPackModule() +{ + if ( !bModuleInitialized) return; + + int i; + for (i=0; i < lMuuids.getCount(); i++) + mir_free(lMuuids[i]); + lMuuids.destroy(); + + LangPackEntry* p = langPack.entry; + for (i=0; i < langPack.entryCount; i++, p++) { + if (p->pNext != NULL) { + for (LangPackEntry* p1 = p->pNext; p1 != NULL;) { + LangPackEntry* p2 = p1; p1 = p1->pNext; + mir_free(p2->local); + mir_free(p2->wlocal); + mir_free(p2); + } } + + mir_free(p->local); + mir_free(p->wlocal); + } + + if (langPack.entryCount) { + mir_free(langPack.entry); + langPack.entry=0; + langPack.entryCount=0; +} } + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(void) ReloadLangpack(TCHAR *pszStr) +{ + if (pszStr == NULL) + pszStr = langPack.filename; + + UnloadLangPackModule(); + LoadLangPack(pszStr); + Langpack_SortDuplicates(); +} diff --git a/src/mir_core/lists.cpp b/src/mir_core/lists.cpp new file mode 100644 index 0000000000..e4996fc156 --- /dev/null +++ b/src/mir_core/lists.cpp @@ -0,0 +1,278 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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 index; + + if ( !List_GetIndex(p_list, p_value, &index)) + return(NULL); + + return(p_list->items[ index ]); +} + +#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_index = -1; + return 0; + } + + switch ((INT_PTR)p_list->sortFunc) + { + case 0: + break; + + case HandleKeySort: +#ifdef _WIN64 + { + const unsigned __int64 val = *(unsigned __int64 *)p_value; + int low = 0; + int high = p_list->realCount - 1; + + 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; + } + + *p_index = low; + } + break; +#endif + + case NumericKeySort: + { + const unsigned val = *(unsigned *)p_value; + int low = 0; + int high = p_list->realCount - 1; + + 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; + } + + *p_index = low; + } + break; + + case PtrKeySort: + { + int low = 0; + int high = p_list->realCount - 1; + + 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; + } + + *p_index = low; + } + break; + + default: + { + int low = 0; + int high = p_list->realCount - 1; + + 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; + } + + *p_index = low; + } + break; + } + + return 0; +} + +MIR_CORE_DLL(int) List_IndexOf(SortedList* p_list, void* p_value) +{ + if (p_value == NULL) + return -1; + + int i; + for (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 = list->realCount; + 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 = -1; + if (List_GetIndex(list, p, &idx)) + 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) +{ + int i; + + d->increment = s->increment; + d->sortFunc = s->sortFunc; + + for (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/md5.cpp b/src/mir_core/md5.cpp new file mode 100644 index 0000000000..a7d7a641e3 --- /dev/null +++ b/src/mir_core/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 ((mir_md5_word_t)~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 mir_md5_byte_t *data /*[64]*/) +{ + mir_md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + mir_md5_word_t t; + /* Define storage for little-endian or both types of CPUs. */ + mir_md5_word_t xbuf[16]; + const mir_md5_word_t *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 mir_md5_byte_t *)&w)) /* dynamic little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if ( !((data - (const mir_md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const mir_md5_word_t *)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 mir_md5_byte_t *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 mir_md5_byte_t *data, int nbytes) +{ + const mir_md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + mir_md5_word_t nbits = (mir_md5_word_t)(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, mir_md5_byte_t digest[16]) +{ + static const mir_md5_byte_t 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 + }; + mir_md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (mir_md5_byte_t)(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] = (mir_md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + +MIR_CORE_DLL(void) mir_md5_hash(const mir_md5_byte_t *data, int len, mir_md5_byte_t 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 new file mode 100644 index 0000000000..0ecddc6717 --- /dev/null +++ b/src/mir_core/memory.cpp @@ -0,0 +1,280 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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) { + char* p = (char*)mir_alloc(strlen(str)+1); + if (p) + strcpy(p, str); + return p; + } + return NULL; +} + +/******************************************************************************/ + +MIR_CORE_DLL(char*) mir_strndup(const char* str, size_t len) +{ + if (str != NULL && len != 0) { + char* p = (char*)mir_alloc(len + 1); + if ( !p) { + memcpy(p, str, len); + p[ len ] = 0; + } + return p; + } + return NULL; +} + +/******************************************************************************/ + +MIR_CORE_DLL(WCHAR*) mir_wstrdup(const WCHAR* str) +{ + if (str != NULL) { + WCHAR* p = (WCHAR*)mir_alloc(sizeof(WCHAR)*(wcslen(str)+1)); + if (p) + wcscpy(p, str); + return p; + } + return NULL; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_snprintf(char *buffer, size_t count, const char* fmt, ...) +{ + va_list va; + int len; + + va_start(va, fmt); + len = _vsnprintf(buffer, count-1, fmt, va); + va_end(va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_sntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, ...) +{ + va_list va; + int len; + + va_start(va, fmt); + 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; + + len = _vsnprintf(buffer, count-1, fmt, va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_vsntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, va_list va) +{ + int len; + + 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 new file mode 100644 index 0000000000..43dd94d7ac --- /dev/null +++ b/src/mir_core/mir_core.def @@ -0,0 +1,126 @@ +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_vsntprintf @100 +mir_wstrdup @101 +rtrim @102 +wildcmp @103 +wrtrim @104 +mir_snprintf @105 +mir_sntprintf @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 diff --git a/src/mir_core/mir_core_10.vcxproj b/src/mir_core/mir_core_10.vcxproj new file mode 100644 index 0000000000..e5f452eb61 --- /dev/null +++ b/src/mir_core/mir_core_10.vcxproj @@ -0,0 +1,238 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + mir_core + {D9EFEA4B-B817-4DE1-BD62-68A5DB8F5F60} + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + Unicode + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + $(SolutionDir)$(Configuration)\ + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)\ + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + EnableFastChecks + MultiThreadedDebugDLL + true + Level3 + EditAndContinue + 4996;%(DisableSpecificWarnings) + WIN32;_DEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions) + Use + commonheaders.h + + + _DEBUG;%(PreprocessorDefinitions) + ..\..\include\msapi + + + mir_core.def + true + false + Windows + miranda32.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)\lib + $(IntDir)$(TargetName).lib + + + + + + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + EnableFastChecks + MultiThreadedDebugDLL + true + Level3 + 4996;%(DisableSpecificWarnings) + WIN64;_DEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions) + Use + commonheaders.h + + + _DEBUG;%(PreprocessorDefinitions) + ..\..\include\msapi + + + mir_core.def + true + false + $(IntDir)$(TargetName)64.lib + Windows + miranda64.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)\lib + /ignore:4197 %(AdditionalOptions) + + + + + Full + OnlyExplicitInline + Size + ..\..\include;%(AdditionalIncludeDirectories) + true + false + true + Level3 + 4996;%(DisableSpecificWarnings) + WIN32;NDEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions) + Use + commonheaders.h + + + NDEBUG;%(PreprocessorDefinitions) + ..\..\include\msapi + + + mir_core.def + true + true + true + false + Windows + miranda32.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)\lib + $(IntDir)$(TargetName).lib + + + + + + + + + + + + + Full + OnlyExplicitInline + Size + ..\..\include;%(AdditionalIncludeDirectories) + true + false + true + Level3 + 4996;%(DisableSpecificWarnings) + WIN64;NDEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions) + Use + commonheaders.h + + + NDEBUG;%(PreprocessorDefinitions) + ..\..\include\msapi + + + mir_core.def + true + true + true + false + $(IntDir)$(TargetName)64.lib + Windows + miranda64.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)\lib + /ignore:4197 %(AdditionalOptions) + + + + + + \ No newline at end of file diff --git a/src/mir_core/mir_core_10.vcxproj.filters b/src/mir_core/mir_core_10.vcxproj.filters new file mode 100644 index 0000000000..27b6a42604 --- /dev/null +++ b/src/mir_core/mir_core_10.vcxproj.filters @@ -0,0 +1,76 @@ + + + + + {bf74d1c9-acd8-4fba-837d-734f024521c9} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {a578a180-0eb9-4c3e-b4ae-0eaefa01d207} + + + + + 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 + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/src/mir_core/miranda.cpp b/src/mir_core/miranda.cpp new file mode 100644 index 0000000000..b059e11cb7 --- /dev/null +++ b/src/mir_core/miranda.cpp @@ -0,0 +1,97 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2012 Miranda ICQ/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); + +int hLangpack = 0; +HINSTANCE hInst = 0; + +HANDLE hStackMutex, hThreadQueueEmpty; + +///////////////////////////////////////////////////////////////////////////////////////// +// module init + +static LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_NULL) SleepEx(0, TRUE); + 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); + + if ( IsWinVerXPPlus()) { + 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); + 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"); + + InitPathUtils(); + InitialiseModularEngine(); +} + +MIR_CORE_DLL(void) UnloadCoreModule(void) +{ + DestroyWindow(hAPCWindow); + CloseHandle(hStackMutex); + + DestroyModularEngine(); + UnloadLangPackModule(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// entry point + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) { + hInst = hinstDLL; + LoadCoreModule(); + } + return TRUE; +} diff --git a/src/mir_core/miranda.h b/src/mir_core/miranda.h new file mode 100644 index 0000000000..af71276ac4 --- /dev/null +++ b/src/mir_core/miranda.h @@ -0,0 +1,131 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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 NEWSTR_ALLOCA(A) (A == NULL)?NULL:strcpy((char*)alloca(strlen(A)+1), A) +#define NEWTSTR_ALLOCA(A) (A == NULL)?NULL:_tcscpy((TCHAR*)alloca((_tcslen(A)+1)* sizeof(TCHAR)), A) + +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); + +extern HINSTANCE hInst; +extern HWND hAPCWindow; +extern HANDLE hStackMutex, hThreadQueueEmpty; + +/**** 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); + +/**** 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 new file mode 100644 index 0000000000..f87c7bb192 --- /dev/null +++ b/src/mir_core/modules.cpp @@ -0,0 +1,601 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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 + +// 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; +static HANDLE hMainThread; +static HANDLE hMissingService; +static THook *pLastHook = NULL; + +///////////////////////////////////////////////////////////////////////////////////////// + +static int QueueMainThread(PAPCFUNC pFunc, void* pParam, HANDLE hDoneEvent) +{ + int result = QueueUserAPC(pFunc, hMainThread, (ULONG_PTR)pParam); + PostMessage(hAPCWindow, WM_NULL, 0, 0); // let this get processed in its own time + if (hDoneEvent) { + WaitForSingleObject(hDoneEvent, INFINITE); + CloseHandle(hDoneEvent); + } + 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 (pLastHook == (THook*)hEvent) + pLastHook = NULL; + + 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) + 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); + + mir_ptr item; + item->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + item->hook = (THook*)hEvent; + item->wParam = wParam; + item->lParam = lParam; + QueueMainThread(HookToMainAPCFunc, item, item->hDoneEvent); + return item->result; +} + +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) { + if (p->subscriber) 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); + + mir_ptr item; + item->wParam = wParam; + item->lParam = lParam; + item->name = name; + item->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + QueueMainThread(CallServiceToMainAPCFunc, item, item->hDoneEvent); + return item->result; +} + +MIR_CORE_DLL(int) CallFunctionAsync(void (__stdcall *func)(void *), void *arg) +{ + 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]); +} + +/////////////////////////////////////////////////////////////////////////////// + +int InitialiseModularEngine(void) +{ + InitializeCriticalSection(&csHooks); + InitializeCriticalSection(&csServices); + + mainThreadId = GetCurrentThreadId(); + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS); + + hMissingService = CreateHookableEvent(ME_SYSTEM_MISSINGSERVICE); + return 0; +} + +void DestroyModularEngine(void) +{ + DestroyHooks(); + hooks.destroy(); + DeleteCriticalSection(&csHooks); + + DestroyServices(); + services.destroy(); + DeleteCriticalSection(&csServices); + + CloseHandle(hMainThread); +} diff --git a/src/mir_core/path.cpp b/src/mir_core/path.cpp new file mode 100644 index 0000000000..fada3dcd18 --- /dev/null +++ b/src/mir_core/path.cpp @@ -0,0 +1,210 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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 char szMirandaPathLower[MAX_PATH]; +static TCHAR szMirandaPathW[MAX_PATH]; +static TCHAR szMirandaPathWLower[MAX_PATH]; + +static int pathIsAbsolute(const char *path) +{ + if (strlen(path) <= 2) + return 0; + if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) + return 1; + return 0; +} + +MIR_CORE_DLL(int) PathToRelative(const char *pSrc, char *pOut) +{ + if ( !pSrc || !strlen(pSrc) || strlen(pSrc)>MAX_PATH) return 0; + if ( !pathIsAbsolute(pSrc)) { + mir_snprintf(pOut, MAX_PATH, "%s", pSrc); + return (int)strlen(pOut); + } + + char szTmp[MAX_PATH]; + mir_snprintf(szTmp, SIZEOF(szTmp), "%s", pSrc); + _strlwr(szTmp); + if (strstr(szTmp, szMirandaPathLower)) { + mir_snprintf(pOut, MAX_PATH, "%s", pSrc+strlen(szMirandaPathLower)); + return (int)strlen(pOut); + } + else { + mir_snprintf(pOut, MAX_PATH, "%s", pSrc); + return (int)strlen(pOut); + } +} + +MIR_CORE_DLL(int) PathToAbsolute(const char *pSrc, char *pOut, char* base) +{ + if ( !pSrc || !strlen(pSrc) || strlen(pSrc) > MAX_PATH) + return 0; + + if (base == NULL) + base = szMirandaPath; + + char buf[MAX_PATH]; + if (pSrc[0] < ' ') + return mir_snprintf(pOut, MAX_PATH, "%s", pSrc); + else if (pathIsAbsolute(pSrc)) + return GetFullPathNameA(pSrc, MAX_PATH, pOut, NULL); + else if (pSrc[0] != '\\') + mir_snprintf(buf, MAX_PATH, "%s%s", base, pSrc); + else + mir_snprintf(buf, MAX_PATH, "%s%s", base, pSrc+1); + + return GetFullPathNameA(buf, MAX_PATH, 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) +{ + DWORD dwAttributes; + char *pszLastBackslash, szTestDir[ MAX_PATH ]; + + lstrcpynA(szTestDir, szDir, SIZEOF(szTestDir)); + if ((dwAttributes = GetFileAttributesA(szTestDir)) != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) + return 0; + + pszLastBackslash = strrchr(szTestDir, '\\'); + if (pszLastBackslash == NULL) + return 0; + + *pszLastBackslash = '\0'; + CreateDirectoryTree(szTestDir); + *pszLastBackslash = '\\'; + return (CreateDirectoryA(szTestDir, NULL) == 0) ? GetLastError() : 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int pathIsAbsoluteW(const TCHAR *path) +{ + if (lstrlen(path) <= 2) + return 0; + if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) + return 1; + return 0; +} + +MIR_CORE_DLL(int) PathToRelativeW(const WCHAR *pSrc, WCHAR *pOut) +{ + if ( !pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH) + return 0; + + if ( !pathIsAbsoluteW(pSrc)) + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + else { + TCHAR szTmp[MAX_PATH]; + + mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc); + _tcslwr(szTmp); + if (_tcsstr(szTmp, szMirandaPathWLower)) + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc+lstrlen(szMirandaPathWLower)); + else + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + } + return lstrlen(pOut); +} + +MIR_CORE_DLL(int) PathToAbsoluteW(const TCHAR *pSrc, TCHAR *pOut, TCHAR* base) +{ + if ( !pSrc || !wcslen(pSrc) || wcslen(pSrc) > MAX_PATH) + return 0; + + if (base == NULL) + base = szMirandaPathW; + + TCHAR buf[MAX_PATH]; + if (pSrc[0] < ' ') + return mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + else if (pathIsAbsoluteW(pSrc)) + return GetFullPathName(pSrc, MAX_PATH, pOut, NULL); + else if (pSrc[0] != '\\') + mir_sntprintf(buf, MAX_PATH, _T("%s%s"), base, pSrc); + else + mir_sntprintf(buf, MAX_PATH, _T("%s%s"), base, pSrc+1); + + 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) +{ + DWORD dwAttributes; + WCHAR* pszLastBackslash, szTestDir[ MAX_PATH ]; + + lstrcpynW(szTestDir, szDir, SIZEOF(szTestDir)); + if ((dwAttributes = GetFileAttributesW(szTestDir)) != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) + return 0; + + pszLastBackslash = wcsrchr(szTestDir, '\\'); + if (pszLastBackslash == NULL) + return 0; + + *pszLastBackslash = '\0'; + CreateDirectoryTreeW(szTestDir); + *pszLastBackslash = '\\'; + return (CreateDirectoryW(szTestDir, NULL) == 0) ? GetLastError() : 0; +} + +int InitPathUtils(void) +{ + char *p = 0; + GetModuleFileNameA(hInst, szMirandaPath, SIZEOF(szMirandaPath)); + p = strrchr(szMirandaPath, '\\'); + if (p) + p[1] = 0; + mir_snprintf(szMirandaPathLower, MAX_PATH, "%s", szMirandaPath); + _strlwr(szMirandaPathLower); + + GetModuleFileName(hInst, szMirandaPathW, SIZEOF(szMirandaPathW)); + TCHAR *tp = _tcsrchr(szMirandaPathW, '\\'); + if (tp) + tp[1] = 0; + mir_sntprintf(szMirandaPathWLower, SIZEOF(szMirandaPathWLower), _T("%s"), szMirandaPathW); + _tcslwr(szMirandaPathWLower); + return 0; +} diff --git a/src/mir_core/sha1.cpp b/src/mir_core/sha1.cpp new file mode 100644 index 0000000000..9e1b376d92 --- /dev/null +++ b/src/mir_core/sha1.cpp @@ -0,0 +1,155 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SHA 180-1 Reference Implementation (Compact version). + * + * The Initial Developer of the Original Code is + * Paul Kocher of Cryptography Research. + * Portions created by the Initial Developer are Copyright (C) 1995-9 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "commonheaders.h" + +#define SHA_ROTL(X, n) (((X) << (n)) | ((X) >> (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, mir_sha1_byte_t *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, mir_sha1_byte_t 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(mir_sha1_byte_t *dataIn, int len, mir_sha1_byte_t hashout[20]) +{ + mir_sha1_ctx ctx; + + mir_sha1_init(&ctx); + mir_sha1_append(&ctx, dataIn, len); + mir_sha1_finish(&ctx, hashout); +} diff --git a/src/mir_core/threads.cpp b/src/mir_core/threads.cpp new file mode 100644 index 0000000000..90dcdaaf5d --- /dev/null +++ b/src/mir_core/threads.cpp @@ -0,0 +1,372 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2012 Miranda ICQ/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" + +///////////////////////////////////////////////////////////////////////////////////////// +// 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; + //PVOID addr; +}; + +static LIST threads(10, NumericKeySortT); + +struct FORK_ARG { + HANDLE hEvent; + pThreadFunc threadcode; + pThreadFuncEx threadcodeex; + void *arg, *owner; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// forkthread - starts a new thread + +void __cdecl forkthread_r(void * arg) +{ + struct FORK_ARG * fa = (struct FORK_ARG *) arg; + void (*callercode)(void*)=fa->threadcode; + void * cookie=fa->arg; + Thread_Push(( HINSTANCE)callercode); + SetEvent(fa->hEvent); + __try + { + callercode(cookie); + } + __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation())) + { + } + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + Thread_Pop(); + return; +} + +MIR_CORE_DLL(UINT_PTR) forkthread( void (__cdecl *threadcode)(void*), unsigned long stacksize, void *arg) +{ + UINT_PTR rc; + struct FORK_ARG fa; + fa.hEvent=CreateEvent(NULL, FALSE, FALSE, NULL); + fa.threadcode=threadcode; + fa.arg=arg; + 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); + __try + { + if (owner) + rc = threadcodeex(owner, cookie); + else + rc = threadcode(cookie); + } + __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation())) + { + } + + 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) +{ + UINT_PTR rc; + struct FORK_ARG fa = { 0 }; + fa.threadcodeex = threadcode; + fa.arg = arg; + fa.owner = owner; + fa.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + 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) { + 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)); + 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() +{ + LONG ntStatus; + HANDLE hDupHandle, hCurrentProcess; + DWORD_PTR dwStartAddress; + + pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread" ); + if(NtQueryInformationThread == NULL) return 0; + + hCurrentProcess = GetCurrentProcess(); + if(!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)){ + SetLastError(ERROR_ACCESS_DENIED); + return NULL; + } + ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL); + CloseHandle(hDupHandle); + + if(ntStatus != ERROR_SUCCESS) return 0; + return ( 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()); + + 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 new file mode 100644 index 0000000000..ddf2d1ca9f --- /dev/null +++ b/src/mir_core/utf.cpp @@ -0,0 +1,406 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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; +} diff --git a/src/mir_core/utils.cpp b/src/mir_core/utils.cpp new file mode 100644 index 0000000000..4ebba2f293 --- /dev/null +++ b/src/mir_core/utils.cpp @@ -0,0 +1,150 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/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*) 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*) wrtrim(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(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(int) wildcmp(char * name, char * mask) +{ + 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; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +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; +} diff --git a/src/modules/icolib/extracticon.cpp b/src/modules/icolib/extracticon.cpp index 6a53f767cc..e5906045a1 100644 --- a/src/modules/icolib/extracticon.cpp +++ b/src/modules/icolib/extracticon.cpp @@ -57,7 +57,7 @@ void* _RelativeVirtualAddresstoPtr(IMAGE_DOS_HEADER* pDosHeader, DWORD rva) IMAGE_SECTION_HEADER* cSection = &pSection[i]; DWORD size = cSection->Misc.VirtualSize ? cSection->Misc.VirtualSize : cSection->SizeOfRawData; - if (rva >= cSection->VirtualAddress && rva < cSection->VirtualAddress + size) + if (rva >= cSection->VirtualAddress && rva < cSection->VirtualAddress + size) return (LPBYTE)pDosHeader + cSection->PointerToRawData + (rva - cSection->VirtualAddress); } diff --git a/src/modules/langpack/lpservices.cpp b/src/modules/langpack/lpservices.cpp index b7ae5ef563..36f9e3c40b 100644 --- a/src/modules/langpack/lpservices.cpp +++ b/src/modules/langpack/lpservices.cpp @@ -43,7 +43,9 @@ static INT_PTR srvTranslateMenu(WPARAM wParam, LPARAM lParam) static INT_PTR srvRegisterLP(WPARAM wParam, LPARAM lParam) { - *(int*)wParam = Langpack_MarkPluginLoaded((PLUGININFOEX*)lParam); + PLUGININFOEX* ppi = (PLUGININFOEX*)lParam; + if (wParam && ppi) + *( int* )wParam = GetPluginFakeId(ppi->uuid, Langpack_MarkPluginLoaded(ppi)); return 0; } diff --git a/src/modules/options/options.cpp b/src/modules/options/options.cpp index 4a4f79688b..1a9d855822 100644 --- a/src/modules/options/options.cpp +++ b/src/modules/options/options.cpp @@ -40,8 +40,6 @@ static int FilterPage = 0; static int FilterLoadProgress = 100; static int FilterTimerId = 0; -char* GetPluginNameByInstance(HINSTANCE hInstance); - struct OptionsPageInit { int pageCount; diff --git a/src/modules/plugins/newplugins.cpp b/src/modules/plugins/newplugins.cpp index a07f371e42..7bbcc57411 100644 --- a/src/modules/plugins/newplugins.cpp +++ b/src/modules/plugins/newplugins.cpp @@ -68,7 +68,7 @@ static BOOL bModuleInitialized = FALSE; TCHAR mirandabootini[MAX_PATH]; static DWORD mirandaVersion; -static int serviceModeIdx = -1; +static int serviceModeIdx = -1, sttFakeID = -100; static HANDLE hPluginListHeap = NULL; static int askAboutIgnoredPlugins; @@ -81,18 +81,8 @@ void UninitIni(void); int LoadDatabaseModule(void); -char* GetPluginNameByInstance(HINSTANCE hInstance) -{ - if (pluginList.getCount() == 0) - return NULL; - - for (int i=0; i < pluginList.getCount(); i++) { - pluginEntry* pe = pluginList[i]; - if (pe->bpi.pluginInfo && pe->bpi.hInst == hInstance) - return pe->bpi.pluginInfo->shortName; - } - return NULL; -} +///////////////////////////////////////////////////////////////////////////////////////// +// basic functions int equalUUID(const MUUID& u1, const MUUID& u2) { @@ -119,6 +109,37 @@ int getDefaultPluginIdx(const MUUID& muuid) return -1; } +///////////////////////////////////////////////////////////////////////////////////////// +// global functions + +char* GetPluginNameByInstance(HINSTANCE hInstance) +{ + if (pluginList.getCount() == 0) + return NULL; + + for (int i=0; i < pluginList.getCount(); i++) { + pluginEntry* p = pluginList[i]; + if (p->bpi.pluginInfo && p->bpi.hInst == hInstance) + return p->bpi.pluginInfo->shortName; + } + return NULL; +} + +int GetPluginFakeId(const MUUID &uuid, int hLangpack) +{ + for (int i=0; i < pluginList.getCount(); i++) { + pluginEntry* p = pluginList[i]; + if ( !p->bpi.hInst) + continue; + + if ( equalUUID(p->bpi.pluginInfo->uuid, uuid)) + return p->hLangpack = (hLangpack) ? hLangpack : --sttFakeID; + } + + return 0; +} + + MUUID miid_last = MIID_LAST; MUUID miid_chat = MIID_CHAT; MUUID miid_srmm = MIID_SRMM; @@ -264,11 +285,8 @@ LBL_Ok: } // perform any API related tasks to freeing -void Plugin_Uninit(pluginEntry* p, bool bDynamic) +void Plugin_Uninit(pluginEntry* p) { - if (bDynamic && p->bpi.hInst) - CallPluginEventHook(p->bpi.hInst, hOkToExitEvent, 0, 0); - // if it was an installed database plugin, call its unload if (p->pclass & PCLASS_DB) p->bpi.dblink->Unload(p->pclass & PCLASS_OK); @@ -283,24 +301,6 @@ void Plugin_Uninit(pluginEntry* p, bool bDynamic) KillModuleEventHooks(p->bpi.hInst); KillModuleServices(p->bpi.hInst); - if (bDynamic) { - int hLangpack = Langpack_GetPluginHandle(p->bpi.pluginInfo); - if (hLangpack != 0) { - KillModuleMenus(hLangpack); - KillModuleFonts(hLangpack); - KillModuleColours(hLangpack); - KillModuleEffects(hLangpack); - KillModuleIcons(hLangpack); - KillModuleHotkeys(hLangpack); - KillModuleSounds(hLangpack); - } - - // release default plugin - for (int i=0; i < SIZEOF(pluginDefault); i++) - if (pluginDefault[i].pImpl == p) - pluginDefault[i].pImpl = NULL; - } - FreeLibrary(p->bpi.hInst); ZeroMemory(&p->bpi, sizeof(p->bpi)); } @@ -310,15 +310,33 @@ void Plugin_Uninit(pluginEntry* p, bool bDynamic) int Plugin_UnloadDyn(pluginEntry* p) { - if (CallPluginEventHook(p->bpi.hInst, hOkToExitEvent, 0, 0) != 0) - return FALSE; + if (p->bpi.hInst) { + if (CallPluginEventHook(p->bpi.hInst, hOkToExitEvent, 0, 0) != 0) + return FALSE; - NotifyEventHooks(hevUnloadModule, (WPARAM)p->bpi.InfoEx, (LPARAM)p->bpi.hInst); + NotifyEventHooks(hevUnloadModule, (WPARAM)p->bpi.InfoEx, (LPARAM)p->bpi.hInst); - CallPluginEventHook(p->bpi.hInst, hPreShutdownEvent, 0, 0); - CallPluginEventHook(p->bpi.hInst, hShutdownEvent, 0, 0); + CallPluginEventHook(p->bpi.hInst, hPreShutdownEvent, 0, 0); + CallPluginEventHook(p->bpi.hInst, hShutdownEvent, 0, 0); + } + + int hLangpack = p->hLangpack; + if (hLangpack != 0) { + KillModuleMenus(hLangpack); + KillModuleFonts(hLangpack); + KillModuleColours(hLangpack); + KillModuleEffects(hLangpack); + KillModuleIcons(hLangpack); + KillModuleHotkeys(hLangpack); + KillModuleSounds(hLangpack); + } + + // release default plugin + for (int i=0; i < SIZEOF(pluginDefault); i++) + if (pluginDefault[i].pImpl == p) + pluginDefault[i].pImpl = NULL; - Plugin_Uninit(p, true); + Plugin_Uninit(p); return TRUE; } @@ -578,7 +596,7 @@ bool LoadCorePlugin(MuuidReplacement& mr) pluginEntry* pPlug = OpenPlugin(tszPlugName, _T("Core"), exe); if (pPlug->pclass & PCLASS_FAILED) { LBL_Error: - Plugin_Uninit(pPlug, true); + Plugin_UnloadDyn(pPlug); return FALSE; } diff --git a/src/modules/plugins/pluginopts.cpp b/src/modules/plugins/pluginopts.cpp index b8384ae593..15f9219192 100644 --- a/src/modules/plugins/pluginopts.cpp +++ b/src/modules/plugins/pluginopts.cpp @@ -167,7 +167,7 @@ static int LoadPluginDynamically(PluginListItemData* dat) pluginEntry* pPlug = OpenPlugin(dat->fileName, _T("Plugins"), exe); if (pPlug->pclass & PCLASS_FAILED) { LBL_Error: - Plugin_Uninit(pPlug, true); + Plugin_UnloadDyn(pPlug); return FALSE; } diff --git a/src/modules/plugins/plugins.h b/src/modules/plugins/plugins.h index 85922fcae8..4dcf76f439 100644 --- a/src/modules/plugins/plugins.h +++ b/src/modules/plugins/plugins.h @@ -48,6 +48,7 @@ struct pluginEntry { TCHAR pluginname[64]; unsigned int pclass; // PCLASS_* + int hLangpack; BASIC_PLUGIN_INFO bpi; pluginEntry* nextclass; }; @@ -70,7 +71,7 @@ int checkAPI(TCHAR* plugin, BASIC_PLUGIN_INFO* bpi, DWORD mirandaVersion, int ch pluginEntry* OpenPlugin(TCHAR *tszFileName, TCHAR *dir, TCHAR *path); bool TryLoadPlugin(pluginEntry *p, TCHAR *dir, bool bDynamic); -void Plugin_Uninit(pluginEntry* p, bool bDynamic = false); +void Plugin_Uninit(pluginEntry* p); int Plugin_UnloadDyn(pluginEntry* p); typedef BOOL (*SCAN_PLUGINS_CALLBACK) (WIN32_FIND_DATA * fd, TCHAR *path, WPARAM wParam, LPARAM lParam); -- cgit v1.2.3