diff options
author | George Hazan <george.hazan@gmail.com> | 2012-05-17 14:57:45 +0000 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2012-05-17 14:57:45 +0000 |
commit | 11771cfdeade7fbb283a208138c6561ba779779c (patch) | |
tree | 581a04d194df28c44594545c496976b25b0e1c2e /tools/dbtool/langpack.cpp | |
parent | b968287dc40d6c6207c2ab758a22cfc9c10917b2 (diff) |
'tools' folder renamed
git-svn-id: http://svn.miranda-ng.org/main/trunk@12 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'tools/dbtool/langpack.cpp')
-rw-r--r-- | tools/dbtool/langpack.cpp | 392 |
1 files changed, 392 insertions, 0 deletions
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->englishHash<arg2->englishHash) 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->linePos<arg2->linePos) return -1;
+ if(arg1->linePos>arg2->linePos) return 1;
+ return 0;
+}
+
+
+static int SortLangPackHashesProc2(struct LangPackEntry *arg1,struct LangPackEntry *arg2)
+{
+ if(arg1->englishHash<arg2->englishHash) 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;
+ }
+}
+
|