From 11771cfdeade7fbb283a208138c6561ba779779c Mon Sep 17 00:00:00 2001 From: George Hazan Date: Thu, 17 May 2012 14:57:45 +0000 Subject: 'tools' folder renamed git-svn-id: http://svn.miranda-ng.org/main/trunk@12 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- tools/dbtool/langpack.cpp | 392 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 tools/dbtool/langpack.cpp (limited to 'tools/dbtool/langpack.cpp') diff --git a/tools/dbtool/langpack.cpp b/tools/dbtool/langpack.cpp new file mode 100644 index 0000000000..85df5cdf22 --- /dev/null +++ b/tools/dbtool/langpack.cpp @@ -0,0 +1,392 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2011 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 "dbtool.h" + +struct LangPackEntry { + unsigned linePos; + DWORD englishHash; + char *english; //not currently used, the hash does everything + char *local; + wchar_t *wlocal; +}; + +struct LangPackStruct { + TCHAR filename[MAX_PATH]; + char language[64]; + char lastModifiedUsing[64]; + char authors[256]; + char authorEmail[128]; + struct LangPackEntry *entry; + int entryCount; + LCID localeID; + UINT defaultANSICp; +} static langPack; + +static void TrimString(char *str) +{ + size_t start, len = strlen(str); + while(str[0] && (unsigned char)str[len-1] <= ' ') str[--len] = 0; + for (start = 0; str[start] && (unsigned char)str[start] <= ' '; start++); + memmove(str, str + start, len - start + 1); +} + +static void TrimStringSimple(char *str) +{ + size_t len = strlen(str); + if (str[len-1] == '\n') str[--len] = '\0'; + if (str[len-1] == '\r') str[len-1] = '\0'; +} + +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; +} + +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 +unsigned int __fastcall 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; +} + +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 hash(buf, len); +} + +__inline unsigned int hashstr(const char * key) +{ + if (key == NULL) return 0; + const unsigned int len = (unsigned int)strlen((const char*)key); + return hash(key, len); +} + +#ifdef _DEBUG +#pragma optimize( "", on ) +#endif + +static int SortLangPackHashesProc(struct LangPackEntry *arg1,struct LangPackEntry *arg2) +{ + if(arg1->englishHashenglishHash) return -1; + if(arg1->englishHash>arg2->englishHash) return 1; + /* both source strings of the same hash (may not be the same string thou) put + the one that was written first to be found first */ + if(arg1->linePoslinePos) return -1; + if(arg1->linePos>arg2->linePos) return 1; + return 0; +} + + +static int SortLangPackHashesProc2(struct LangPackEntry *arg1,struct LangPackEntry *arg2) +{ + if(arg1->englishHashenglishHash) return -1; + if(arg1->englishHash>arg2->englishHash) return 1; + return 0; +} + +static int LoadLangPack(const TCHAR *szLangPack) +{ + FILE *fp; + char line[4096] = ""; + char *pszColon; + char *pszLine; + int entriesAlloced; + int startOfLine=0; + unsigned int linePos=1; + LCID langID; + UINT fileCp = CP_ACP; + + lstrcpy(langPack.filename,szLangPack); + fp = _tfopen(szLangPack,_T("rt")); + if(fp==NULL) return 1; + fgets(line,sizeof(line),fp); + 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); + } + TrimString(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; + TrimString(line); + if(IsEmpty(line) || line[0]==';' || line[0]==0) continue; + if(line[0]=='[') break; + pszColon=strchr(line,':'); + if(pszColon==NULL) {fclose(fp); return 3;} + *pszColon=0; + if(!lstrcmpA(line,"Language")) {_snprintf(langPack.language,sizeof(langPack.language),"%s",pszColon+1); TrimString(langPack.language);} + else if(!lstrcmpA(line,"Last-Modified-Using")) {_snprintf(langPack.lastModifiedUsing,sizeof(langPack.lastModifiedUsing),"%s",pszColon+1); TrimString(langPack.lastModifiedUsing);} + else if(!lstrcmpA(line,"Authors")) {_snprintf(langPack.authors,sizeof(langPack.authors),"%s",pszColon+1); TrimString(langPack.authors);} + else if(!lstrcmpA(line,"Author-email")) {_snprintf(langPack.authorEmail,sizeof(langPack.authorEmail),"%s",pszColon+1); TrimString(langPack.authorEmail);} + else if(!lstrcmpA(line, "Locale")) { + char szBuf[20], *stopped; + + TrimString(pszColon + 1); + langID = (USHORT)strtol(pszColon + 1, &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); + entriesAlloced=0; + while(!feof(fp)) { + if(fgets(line,sizeof(line),fp)==NULL) break; + if(IsEmpty(line) || line[0]==';' || line[0]==0) continue; + TrimStringSimple(line); + ConvertBackslashes(line, fileCp); + if(line[0]=='[' && line[lstrlenA(line)-1]==']') { + if(langPack.entryCount && langPack.entry[langPack.entryCount-1].local==NULL) { + if(langPack.entry[langPack.entryCount-1].english!=NULL) free(langPack.entry[langPack.entryCount-1].english); + langPack.entryCount--; + } + pszLine = line+1; + line[lstrlenA(line)-1]='\0'; + TrimStringSimple(line); + if(++langPack.entryCount>entriesAlloced) { + entriesAlloced+=128; + langPack.entry=(struct LangPackEntry*)realloc(langPack.entry,sizeof(struct LangPackEntry)*entriesAlloced); + } + langPack.entry[langPack.entryCount-1].english=NULL; + langPack.entry[langPack.entryCount-1].englishHash=hashstr(pszLine); + langPack.entry[langPack.entryCount-1].local=NULL; + langPack.entry[langPack.entryCount-1].wlocal = NULL; + langPack.entry[langPack.entryCount-1].linePos=linePos++; + } + else if(langPack.entryCount) { + struct LangPackEntry* E = &langPack.entry[langPack.entryCount-1]; + + if(E->local==NULL) { + E->local = _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 *)malloc((iNeeded+1) * sizeof(wchar_t)); + MultiByteToWideChar(fileCp, 0, line, -1, E->wlocal, iNeeded); + } + } + else { + size_t iOldLenA = strlen(E->local); + E->local = (char*)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*)realloc(E->wlocal, ( sizeof(wchar_t) * ( iOldLen + iNeeded + 2))); + wcscat(E->wlocal, L"\n"); + MultiByteToWideChar(fileCp, 0, line, -1, E->wlocal + iOldLen+1, iNeeded); + } + } + } + } + fclose(fp); + + qsort(langPack.entry,langPack.entryCount,sizeof(LangPackEntry),(int(*)(const void*,const void*))SortLangPackHashesProc); + + return 0; +} + +char *LangPackTranslateString(const char *szEnglish, const int W) +{ + struct LangPackEntry key,*entry; + + if ( langPack.entryCount == 0 || szEnglish == NULL ) return (char*)szEnglish; + + key.englishHash = W ? hashstrW(szEnglish) : hashstr(szEnglish); + entry=(struct LangPackEntry*)bsearch(&key,langPack.entry,langPack.entryCount,sizeof(struct LangPackEntry),(int(*)(const void*,const void*))SortLangPackHashesProc2); + if(entry==NULL) return (char*)szEnglish; + while(entry>langPack.entry) + { + entry--; + if(entry->englishHash!=key.englishHash) { + entry++; + return W ? (char *)entry->wlocal : entry->local; + } + } + return W ? (char *)entry->wlocal : entry->local; +} + +#if defined( _UNICODE ) + #define FLAGS 1 +#else + #define FLAGS 0 +#endif + +static void TranslateWindow( HWND hwnd ) +{ + TCHAR title[2048]; + GetWindowText(hwnd, title, SIZEOF( title )); + { + TCHAR* result = ( TCHAR* )LangPackTranslateString(( char* )title, FLAGS ); + if ( result != title ) + SetWindowText(hwnd, result ); +} } + +static BOOL CALLBACK TranslateDialogEnumProc(HWND hwnd,LPARAM lParam) +{ + TCHAR szClass[32]; + int id = GetDlgCtrlID( hwnd ); + + GetClassName(hwnd,szClass,SIZEOF(szClass)); + if(!lstrcmpi(szClass,_T("static")) || !lstrcmpi(szClass,_T("hyperlink")) || !lstrcmpi(szClass,_T("button")) || !lstrcmpi(szClass,_T("MButtonClass"))) + TranslateWindow(hwnd); + else if(!lstrcmpi(szClass,_T("edit"))) { + if ( GetWindowLong(hwnd,GWL_STYLE)&ES_READONLY) + TranslateWindow(hwnd); + } + return TRUE; +} + +int TranslateDialog( HWND hwndDlg ) +{ + TranslateWindow( hwndDlg ); + EnumChildWindows( hwndDlg,TranslateDialogEnumProc,0); + return 0; +} + +void LoadLangPackModule(void) +{ + HANDLE hFind; + TCHAR szSearch[MAX_PATH], *str2, szLangPack[MAX_PATH]; + WIN32_FIND_DATA fd; + + GetModuleFileName(GetModuleHandle(NULL),szSearch,MAX_PATH); + str2 = _tcsrchr(szSearch, '\\'); + if (str2) *str2 = 0; else str2 = szSearch; + _tcscat(szSearch, _T("\\langpack_*.txt")); + hFind = FindFirstFile(szSearch, &fd); + if (hFind != INVALID_HANDLE_VALUE) + { + FindClose(hFind); + + _tcscpy(str2 + 1, fd.cFileName); + _tcscpy(szLangPack, szSearch); + LoadLangPack(szLangPack); + } +} + +void UnloadLangPackModule(void) +{ + for (int i = 0; i < langPack.entryCount; i++) { + free(langPack.entry[i].english); + free(langPack.entry[i].local); + free(langPack.entry[i].wlocal); + } + if (langPack.entryCount) { + free(langPack.entry); + langPack.entry=0; + langPack.entryCount=0; + } +} + -- cgit v1.2.3