From 939b54967dcda681318271d203eedd1dcf5ce934 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Wed, 27 Jun 2012 05:25:13 +0000 Subject: renamed as the rest git-svn-id: http://svn.miranda-ng.org/main/trunk@645 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Mir_core/commonheaders.cpp | 2 + plugins/Mir_core/commonheaders.h | 63 +++ plugins/Mir_core/langpack.cpp | 630 ++++++++++++++++++++++++++ plugins/Mir_core/lists.cpp | 278 ++++++++++++ plugins/Mir_core/memory.cpp | 280 ++++++++++++ plugins/Mir_core/mir_core.def | 5 + plugins/Mir_core/mir_core_10.vcxproj | 217 +++++++++ plugins/Mir_core/mir_core_10.vcxproj.filters | 67 +++ plugins/Mir_core/miranda.cpp | 403 +++++++++++++++++ plugins/Mir_core/miranda.h | 128 ++++++ plugins/Mir_core/modules.cpp | 644 +++++++++++++++++++++++++++ plugins/Mir_core/path.cpp | 210 +++++++++ plugins/Mir_core/utf.cpp | 406 +++++++++++++++++ plugins/Mir_core/utils.cpp | 150 +++++++ 14 files changed, 3483 insertions(+) create mode 100644 plugins/Mir_core/commonheaders.cpp create mode 100644 plugins/Mir_core/commonheaders.h create mode 100644 plugins/Mir_core/langpack.cpp create mode 100644 plugins/Mir_core/lists.cpp create mode 100644 plugins/Mir_core/memory.cpp create mode 100644 plugins/Mir_core/mir_core.def create mode 100644 plugins/Mir_core/mir_core_10.vcxproj create mode 100644 plugins/Mir_core/mir_core_10.vcxproj.filters create mode 100644 plugins/Mir_core/miranda.cpp create mode 100644 plugins/Mir_core/miranda.h create mode 100644 plugins/Mir_core/modules.cpp create mode 100644 plugins/Mir_core/path.cpp create mode 100644 plugins/Mir_core/utf.cpp create mode 100644 plugins/Mir_core/utils.cpp (limited to 'plugins/Mir_core') diff --git a/plugins/Mir_core/commonheaders.cpp b/plugins/Mir_core/commonheaders.cpp new file mode 100644 index 0000000000..95b2201163 --- /dev/null +++ b/plugins/Mir_core/commonheaders.cpp @@ -0,0 +1,2 @@ +#include "commonheaders.h" + diff --git a/plugins/Mir_core/commonheaders.h b/plugins/Mir_core/commonheaders.h new file mode 100644 index 0000000000..2d04e12f4b --- /dev/null +++ b/plugins/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/plugins/Mir_core/langpack.cpp b/plugins/Mir_core/langpack.cpp new file mode 100644 index 0000000000..d38dd6807d --- /dev/null +++ b/plugins/Mir_core/langpack.cpp @@ -0,0 +1,630 @@ +/* + +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 LangPackMuuid* p1, const LangPackMuuid* p2) +{ + return memcmp(&p1->muuid, &p2->muuid, sizeof(MUUID)); +} + +static LIST lMuuids(10, CompareMuuids); +static LangPackMuuid* pCurrentMuuid = NULL; + +static BOOL bModuleInitialized = FALSE; + +struct LangPackEntry { + DWORD englishHash; + char *local; + wchar_t *wlocal; + LangPackMuuid* 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 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; + + LangPackMuuid* pNew = (LangPackMuuid*)mir_alloc(sizeof(LangPackMuuid)); + memcpy(&pNew->muuid, &t, sizeof(t)); + pNew->pInfo = NULL; + 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(LangPackMuuid* pUuid, const char *szEnglish, const int W) +{ + if (langPack.entryCount == 0 || szEnglish == NULL) + return (char*)szEnglish; + + LangPackEntry key, *entry; + key.englishHash = W ? mir_hashstrW((WCHAR*)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) LangPackGetDefaultCodePage() +{ + return langPack.defaultANSICp; +} + +MIR_CORE_DLL(int) LangPackGetDefaultLocale() +{ + return (langPack.localeID == 0) ? LOCALE_USER_DEFAULT : langPack.localeID; +} + +MIR_CORE_DLL(TCHAR*) LangPackPcharToTchar(const char* pszStr) +{ + if (pszStr == NULL) + return NULL; + + { int len = (int)strlen(pszStr); + TCHAR* result = (TCHAR*)alloca((len+1)*sizeof(TCHAR)); + MultiByteToWideChar(LangPackGetDefaultCodePage(), 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(LangPackLookupUuid(hLangpack), str, FALSE); +} + +MIR_CORE_DLL(WCHAR*) TranslateW_LP(const WCHAR* str, int hLangpack) +{ + return (WCHAR*)LangPackTranslateString(LangPackLookupUuid(hLangpack), (LPCSTR)str, TRUE); +} + +MIR_CORE_DLL(void) TranslateMenu_LP(HMENU hMenu, int hLangpack) +{ + LangPackMuuid* uuid = LangPackLookupUuid(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(LangPackMuuid* 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); + + LangPackMuuid* uuid = LangPackLookupUuid(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(LangPackLookupUuid(hLangpack), hDlg); + EnumChildWindows(hDlg, TranslateDialogEnumProc, hLangpack); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(LangPackMuuid*) LangPackLookupUuid(WPARAM wParam) +{ + int idx = (wParam >> 16) & 0xFFFF; + return (idx > 0 && idx <= lMuuids.getCount()) ? lMuuids[ idx-1 ] : NULL; +} + +MIR_CORE_DLL(int) LangPackMarkPluginLoaded(PLUGININFOEX* pInfo) +{ + LangPackMuuid tmp; tmp.muuid = pInfo->uuid; + int idx = lMuuids.getIndex(&tmp); + if (idx == -1) + return 0; + + lMuuids[ idx ]->pInfo = pInfo; + return (idx+1) << 16; +} + +MIR_CORE_DLL(void) LangPackDropUnusedItems(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->pMuuid != NULL && s->pMuuid->pInfo == NULL) + s->pMuuid = NULL; + + 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); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +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); + LangPackDropUnusedItems(); +} diff --git a/plugins/Mir_core/lists.cpp b/plugins/Mir_core/lists.cpp new file mode 100644 index 0000000000..e4996fc156 --- /dev/null +++ b/plugins/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/plugins/Mir_core/memory.cpp b/plugins/Mir_core/memory.cpp new file mode 100644 index 0000000000..25b4d880c2 --- /dev/null +++ b/plugins/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_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_CORE_DLL(void*) mir_calloc(size_t size) +{ + void* p = mir_alloc(size); + if (p != NULL) + memset(p, 0, size); + return p; +} + +/******************************************************************************/ + +MIR_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_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, LangPackGetDefaultCodePage()); +} + +/******************************************************************************/ + +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, LangPackGetDefaultCodePage()); +} diff --git a/plugins/Mir_core/mir_core.def b/plugins/Mir_core/mir_core.def new file mode 100644 index 0000000000..78e8323ff8 --- /dev/null +++ b/plugins/Mir_core/mir_core.def @@ -0,0 +1,5 @@ +LIBRARY mir_core + +EXPORTS + CallContactService @1 + CallProtoService @2 diff --git a/plugins/Mir_core/mir_core_10.vcxproj b/plugins/Mir_core/mir_core_10.vcxproj new file mode 100644 index 0000000000..e3da90ac2b --- /dev/null +++ b/plugins/Mir_core/mir_core_10.vcxproj @@ -0,0 +1,217 @@ + + + + + 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).lib + Windows + miranda64.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)\lib + + + + + 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).lib + Windows + miranda64.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies) + $(SolutionDir)\lib + + + + + + \ No newline at end of file diff --git a/plugins/Mir_core/mir_core_10.vcxproj.filters b/plugins/Mir_core/mir_core_10.vcxproj.filters new file mode 100644 index 0000000000..1a051134b1 --- /dev/null +++ b/plugins/Mir_core/mir_core_10.vcxproj.filters @@ -0,0 +1,67 @@ + + + + + {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 + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/plugins/Mir_core/miranda.cpp b/plugins/Mir_core/miranda.cpp new file mode 100644 index 0000000000..7f48e05bb2 --- /dev/null +++ b/plugins/Mir_core/miranda.cpp @@ -0,0 +1,403 @@ +/* + +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); + +HANDLE hStackMutex, hThreadQueueEmpty; +int hLangpack = 0; +HINSTANCE hInst = 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; + CallService(MS_SYSTEM_THREAD_PUSH, 0, (LPARAM)callercode); + SetEvent(fa->hEvent); + __try + { + callercode(cookie); + } + __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation())) + { + } + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + CallService(MS_SYSTEM_THREAD_POP, 0, 0); + 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; + + CallService(MS_SYSTEM_THREAD_PUSH, (WPARAM)fa->owner, (LPARAM)threadcode); + SetEvent(fa->hEvent); + __try + { + if (owner) + rc = threadcodeex(owner, cookie); + else + rc = threadcode(cookie); + } + __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation())) + { + } + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + CallService(MS_SYSTEM_THREAD_POP, 0, 0); + 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; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 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; + } +} + +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) 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); + } + } +} + +MIR_CORE_DLL(void) UnwindThreadWait(void) +{ + // acquire the list and wake up any alertable threads + if ( MirandaWaitForMutex(hStackMutex)) { + int j; + for (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 + +MIR_CORE_DLL(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) UnwindThreadPush(WPARAM wParam, LPARAM lParam) +{ + 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 = (void*)wParam; + p->hOwner = GetInstByAddress((void*)lParam); + p->addr = (void*)lParam; + threads.insert(p); + + ReleaseMutex(hStackMutex); + } + return 0; +} + +MIR_CORE_DLL(INT_PTR) UnwindThreadPop(WPARAM, LPARAM) +{ + 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; +} + +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); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// module init + +static void LoadSystemModule(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); + + #ifdef WIN64 + HMODULE mirInst = GetModuleHandleA("miranda64.exe"); + #else + HMODULE mirInst = GetModuleHandleA("miranda32.exe"); + #endif + RecalculateTime = (void (*)()) GetProcAddress(mirInst, "RecalculateTime"); + + InitPathUtils(); + InitialiseModularEngine(); +} + +static void UnloadSystemModule(void) +{ + DestroyModularEngine(); + UnloadLangPackModule(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// entry point + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) { + hInst = hinstDLL; + LoadSystemModule(); + } + else if(fdwReason == DLL_PROCESS_DETACH) + UnloadSystemModule(); + return TRUE; +} diff --git a/plugins/Mir_core/miranda.h b/plugins/Mir_core/miranda.h new file mode 100644 index 0000000000..8a03e4111c --- /dev/null +++ b/plugins/Mir_core/miranda.h @@ -0,0 +1,128 @@ +/* + +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) + +struct LangPackMuuid +{ + MUUID muuid; + PLUGININFOEX* pInfo; +}; + +MIR_CORE_DLL(int) LangPackMarkPluginLoaded(PLUGININFOEX* pInfo); + +MIR_CORE_DLL(LangPackMuuid*) LangPackLookupUuid(WPARAM wParam); + +int LoadLangPackModule(void); +void UnloadLangPackModule(void); + +int InitialiseModularEngine(void); +void DestroyModularEngine(void); + +int InitPathUtils(void); + +extern HINSTANCE hInst; + +/**** 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; + }; + }; +}; + +struct THook +{ + char name[ MAXMODULELABELLENGTH ]; + int id; + int subscriberCount; + THookSubscriber* subscriber; + MIRANDAHOOK pfnHook; + CRITICAL_SECTION csHook; +}; + +/**** langpack.cpp *********************************************************************/ + +char* LangPackTranslateString(struct LangPackMuuid* 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/plugins/Mir_core/modules.cpp b/plugins/Mir_core/modules.cpp new file mode 100644 index 0000000000..6a9aa54bcb --- /dev/null +++ b/plugins/Mir_core/modules.cpp @@ -0,0 +1,644 @@ +/* + +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; + +/////////////////////////////////////////////////////////////////////////////// +// HOOKS + +MIR_CORE_DLL(HANDLE) CreateHookableEvent(const char *name) +{ + THook* ret; + int idx; + + if (name == NULL) + return NULL; + + EnterCriticalSection(&csHooks); + if ((idx = hooks.getIndex((THook*)name)) != -1) { + LeaveCriticalSection(&csHooks); + return NULL; + } + + ret = (THook*)mir_alloc(sizeof(THook)); + strncpy(ret->name, name, sizeof(ret->name)); ret->name[ MAXMODULELABELLENGTH-1 ] = 0; + ret->id = hookId++; + ret->subscriberCount = 0; + ret->subscriber = NULL; + ret->pfnHook = NULL; + InitializeCriticalSection(&ret->csHook); + hooks.insert(ret); + + LeaveCriticalSection(&csHooks); + return (HANDLE)ret; +} + +MIR_CORE_DLL(int) DestroyHookableEvent(HANDLE hEvent) +{ + EnterCriticalSection(&csHooks); + if (pLastHook == (THook*)hEvent) + pLastHook = NULL; + + int idx; + if ((idx = hooks.getIndex((THook*)hEvent)) == -1) { + LeaveCriticalSection(&csHooks); + return 1; + } + + THook* p = hooks[idx]; + if (p->subscriberCount) { + mir_free(p->subscriber); + p->subscriber = NULL; + p->subscriberCount = 0; + } + hooks.remove(idx); + DeleteCriticalSection(&p->csHook); + mir_free(p); + + LeaveCriticalSection(&csHooks); + return 0; +} + +MIR_CORE_DLL(int) SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook) +{ + THook* p = (THook*)hEvent; + + EnterCriticalSection(&csHooks); + if (hooks.getIndex(p) != -1) + p->pfnHook = pfnHook; + LeaveCriticalSection(&csHooks); + return 0; +} + +MIR_CORE_DLL(int) CallPluginEventHook(HINSTANCE hInst, HANDLE hEvent, WPARAM wParam, LPARAM lParam) +{ + int returnVal = 0; + THook* p = (THook*)hEvent; + if (p == NULL) + return -1; + + EnterCriticalSection(&p->csHook); + for (int i = 0; i < p->subscriberCount; i++) { + THookSubscriber* s = &p->subscriber[i]; + if (s->hOwner != hInst) + continue; + + 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) + break; + } + + if (p->subscriberCount == 0 && p->pfnHook != 0) + returnVal = p->pfnHook(wParam, lParam); + + LeaveCriticalSection(&p->csHook); + return returnVal; +} + +MIR_CORE_DLL(int) CallHookSubscribers(HANDLE hEvent, WPARAM wParam, LPARAM lParam) +{ + int returnVal = 0; + THook* p = (THook*)hEvent; + if (p == NULL) + return -1; + + EnterCriticalSection(&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]; + 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) + break; + } + + // check for no hooks and call the default hook if any + if (p->subscriberCount == 0 && p->pfnHook != 0) + returnVal = p->pfnHook(wParam, lParam); + + LeaveCriticalSection(&p->csHook); + return returnVal; +} + +static int checkHook(HANDLE hHook) +{ + if (hHook == NULL) + return -1; + + EnterCriticalSection(&csHooks); + if (pLastHook != hHook || !pLastHook) { + if (hooks.getIndex((THook*)hHook) == -1) { + LeaveCriticalSection(&csHooks); + return -1; + } + pLastHook = (THook*)hHook; + } + LeaveCriticalSection(&csHooks); + return 0; +} + +static void CALLBACK HookToMainAPCFunc(ULONG_PTR dwParam) +{ + THookToMainThreadItem* item = (THookToMainThreadItem*)dwParam; + + if (checkHook(item->hook) == -1) + item->result = -1; + else + item->result = CallHookSubscribers(item->hook, item->wParam, item->lParam); + SetEvent(item->hDoneEvent); +} + +MIR_CORE_DLL(int) NotifyEventHooks(HANDLE hEvent, WPARAM wParam, LPARAM lParam) +{ + extern HWND hAPCWindow; + + if ( GetCurrentThreadId() != mainThreadId) { + THookToMainThreadItem item; + + item.hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + item.hook = (THook*)hEvent; + item.wParam = wParam; + item.lParam = lParam; + + QueueUserAPC(HookToMainAPCFunc, hMainThread, (ULONG_PTR)&item); + PostMessage(hAPCWindow, WM_NULL, 0, 0); // let it process APC even if we're in a common dialog + WaitForSingleObject(item.hDoneEvent, INFINITE); + CloseHandle(item.hDoneEvent); + return item.result; + } + + return (checkHook(hEvent) == -1) ? -1 : CallHookSubscribers(hEvent, wParam, lParam); +} + +static HANDLE HookEventInt(int type, const char* name, MIRANDAHOOK hookProc, void* object, LPARAM lParam) +{ + int idx; + THook* p; + HANDLE ret; + + EnterCriticalSection(&csHooks); + if ((idx = hooks.getIndex((THook*)name)) == -1) { + #ifdef _DEBUG + OutputDebugStringA("Attempt to hook: \t"); + OutputDebugStringA(name); + OutputDebugStringA("\n"); + #endif + LeaveCriticalSection(&csHooks); + return NULL; + } + + 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++; + + ret = (HANDLE)((p->id << 16) | p->subscriberCount); + LeaveCriticalSection(&csHooks); + return ret; +} + +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) +{ + int idx; + THook* p; + HANDLE ret; + + EnterCriticalSection(&csHooks); + if ((idx = hooks.getIndex((THook*)name)) == -1) { + #ifdef _DEBUG + MessageBoxA(NULL, "Attempt to hook non-existant event", name, MB_OK); + #endif + LeaveCriticalSection(&csHooks); + return NULL; + } + + 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++; + + ret = (HANDLE)((p->id << 16) | p->subscriberCount); + LeaveCriticalSection(&csHooks); + return ret; +} + +MIR_CORE_DLL(int) UnhookEvent(HANDLE hHook) +{ + int i; + THook* p = NULL; + + int hookId = (int)hHook >> 16; + int subscriberId = ((int)hHook & 0xFFFF) - 1; + + if (hHook == NULL) return 0; + + EnterCriticalSection(&csHooks); + for (i = 0; i < hooks.getCount(); i++) { + if (hooks[i]->id == hookId) { + p = hooks[i]; + break; + } } + + if (p == NULL) { + LeaveCriticalSection(&csHooks); + return 1; + } + + if (subscriberId >= p->subscriberCount || subscriberId < 0) { + LeaveCriticalSection(&csHooks); + 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; + } + LeaveCriticalSection(&csHooks); + return 0; +} + +MIR_CORE_DLL(void) KillModuleEventHooks(HINSTANCE hInst) +{ + int i, j; + + EnterCriticalSection(&csHooks); + for (i = hooks.getCount()-1; i >= 0; i--) { + if (hooks[i]->subscriberCount == 0) + continue; + + for (j = hooks[i]->subscriberCount-1; j >= 0; j--) { + if (hooks[i]->subscriber[j].hOwner == hInst) { + 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; + } } } + + LeaveCriticalSection(&csHooks); +} + +MIR_CORE_DLL(void) KillObjectEventHooks(void* pObject) +{ + int i, j; + + EnterCriticalSection(&csHooks); + for (i = hooks.getCount()-1; i >= 0; i--) { + if (hooks[i]->subscriberCount == 0) + continue; + + for (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; + } } } + + LeaveCriticalSection(&csHooks); +} + +/////////////////////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); + + EnterCriticalSection(&csServices); + + if (services.getIndex(&tmp) != -1) { + LeaveCriticalSection(&csServices); + 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); + + LeaveCriticalSection(&csServices); + 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) +{ + int idx; + + EnterCriticalSection(&csServices); + if ((idx = services.getIndex((TService*)&hService)) != -1) { + mir_free(services[idx]); + services.remove(idx); + } + + LeaveCriticalSection(&csServices); + return 0; +} + +MIR_CORE_DLL(int) ServiceExists(const char *name) +{ + if (name == NULL) + return FALSE; + + EnterCriticalSection(&csServices); + int ret = FindServiceByName(name) != NULL; + LeaveCriticalSection(&csServices); + return ret; +} + +MIR_CORE_DLL(INT_PTR) CallService(const char *name, WPARAM wParam, LPARAM lParam) +{ + #ifdef _DEBUG + if (name == NULL) { + MessageBoxA(0, "Someone tried to CallService(NULL, ..) see stack trace for details", "", 0); + DebugBreak(); + return CALLSERVICE_NOTFOUND; + } + #else + if (name == NULL) return CALLSERVICE_NOTFOUND; + #endif + + EnterCriticalSection(&csServices); + TService *pService = FindServiceByName(name); + if (pService == NULL) { + LeaveCriticalSection(&csServices); + #ifdef _DEBUG + OutputDebugStringA("Missing service called: \t"); + OutputDebugStringA(name); + OutputDebugStringA("\n"); + #endif + + return CALLSERVICE_NOTFOUND; + } + + MIRANDASERVICE pfnService = pService->pfnService; + int flags = pService->flags; + LPARAM fnParam = pService->lParam; + void* object = pService->object; + LeaveCriticalSection(&csServices); + 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) +{ + extern HWND hAPCWindow; + + 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) { + TServiceToMainThreadItem item; + item.wParam = wParam; + item.lParam = lParam; + item.name = name; + item.hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + QueueUserAPC(CallServiceToMainAPCFunc, hMainThread, (ULONG_PTR) &item); + PostMessage(hAPCWindow, WM_NULL, 0, 0); // let this get processed in its own time + WaitForSingleObject(item.hDoneEvent, INFINITE); + CloseHandle(item.hDoneEvent); + return item.result; + } + + return CallService(name, wParam, lParam); +} + +MIR_CORE_DLL(int) CallFunctionAsync(void (__stdcall *func)(void *), void *arg) +{ + extern HWND hAPCWindow; + int r = QueueUserAPC((void (__stdcall *)(ULONG_PTR))func, hMainThread, (ULONG_PTR)arg); + PostMessage(hAPCWindow, WM_NULL, 0, 0); + return r; +} + +MIR_CORE_DLL(void) KillModuleServices(HINSTANCE hInst) +{ + int i; + + EnterCriticalSection(&csServices); + for (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); + } } + + LeaveCriticalSection(&csServices); +} + +MIR_CORE_DLL(void) KillObjectServices(void* pObject) +{ + int i; + + EnterCriticalSection(&csServices); + for (i = services.getCount()-1; i >= 0; i--) + if (services[i]->object == pObject) + DestroyServiceFunction((HANDLE)services[i]->nameHash); + + LeaveCriticalSection(&csServices); +} + +/////////////////////////////////////////////////////////////////////////////// + +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) +{ + EnterCriticalSection(&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); + } + hooks.destroy(); + LeaveCriticalSection(&csHooks); + DeleteCriticalSection(&csHooks); + + EnterCriticalSection(&csServices); + for (int j=0; j < services.getCount(); j++) + mir_free(services[j]); + + services.destroy(); + LeaveCriticalSection(&csServices); + DeleteCriticalSection(&csServices); + CloseHandle(hMainThread); +} diff --git a/plugins/Mir_core/path.cpp b/plugins/Mir_core/path.cpp new file mode 100644 index 0000000000..fada3dcd18 --- /dev/null +++ b/plugins/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/plugins/Mir_core/utf.cpp b/plugins/Mir_core/utf.cpp new file mode 100644 index 0000000000..5ec6042758 --- /dev/null +++ b/plugins/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, LangPackGetDefaultCodePage(), 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, LangPackGetDefaultCodePage()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// 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/plugins/Mir_core/utils.cpp b/plugins/Mir_core/utils.cpp new file mode 100644 index 0000000000..f0fcdcfa07 --- /dev/null +++ b/plugins/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; +} + +static 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; +} -- cgit v1.2.3