From f19ed36b66a807420c771a467a954114f027384c Mon Sep 17 00:00:00 2001 From: Rozhuk Ivan Date: Wed, 26 Nov 2014 23:48:18 +0000 Subject: SpellChecker: code cleanup git-svn-id: http://svn.miranda-ng.org/main/trunk@11110 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/SpellChecker/src/dictionary.cpp | 1929 +++++++++++----------- plugins/SpellChecker/src/hunspell/csutil.cxx | 3 + plugins/SpellChecker/src/hunspell/suggestmgr.cxx | 5 +- 3 files changed, 970 insertions(+), 967 deletions(-) (limited to 'plugins/SpellChecker') diff --git a/plugins/SpellChecker/src/dictionary.cpp b/plugins/SpellChecker/src/dictionary.cpp index cd27a3fd78..0926273837 100644 --- a/plugins/SpellChecker/src/dictionary.cpp +++ b/plugins/SpellChecker/src/dictionary.cpp @@ -1,965 +1,964 @@ -/* -Copyright (C) 2006-2010 Ricardo Pescuma Domenecci - -This is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -This 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this file; see the file license.txt. If -not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. -*/ - -#include "commons.h" - -#define APPPATH _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s") -#define MUICACHE _T("Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache") - - -// Additional languages that i could not find in Windows -struct { - TCHAR *language; - TCHAR *localized_name; -} aditionalLanguages[] = { - { _T("tl_PH"), LPGENT("Tagalog (Philippines)") }, - { _T("de_frami_neu"), LPGENT("German (Germany)") } -}; - -struct { - TCHAR *name; - TCHAR *key; -} otherHunspellApps[] = { - { _T("Thunderbird"), _T("thunderbird.exe") }, - { _T("Firefox"), _T("firefox.exe") } -}; - -struct { - char *name; - UINT codepage; -} codepages[] = { - { "ISO8859-1", 28591 }, - { "UTF-7", CP_UTF7 }, - { "UTF-8", CP_UTF8 }, - { "UTF7", CP_UTF7 }, - { "UTF8", CP_UTF8 }, - { "ISO8859-2", 28592 }, - { "ISO8859-3", 28593 }, - { "ISO8859-4", 28594 }, - { "ISO8859-5", 28595 }, - { "ISO8859-6", 28596 }, - { "ISO8859-7", 28597 }, - { "ISO8859-8", 28598 }, - { "ISO8859-9", 28599 }, - { "ASMO-708", 708 }, - { "DOS-720", 720 }, - { "iso-8859-6", 28596 }, - { "arabic", 28596 }, - { "csISOLatinArabic", 28596 }, - { "ECMA-114", 28596 }, - { "ISO_8859-6", 28596 }, - { "ISO_8859-6:1987", 28596 }, - { "iso-ir-127", 28596 }, - { "x-mac-arabic", 10004 }, - { "windows-1256", 1256 }, - { "cp1256", 1256 }, - { "ibm775", 775 }, - { "CP500", 775 }, - { "iso-8859-4", 28594 }, - { "csISOLatin4", 28594 }, - { "ISO_8859-4", 28594 }, - { "ISO_8859-4:1988", 28594 }, - { "iso-ir-110", 28594 }, - { "l4", 28594 }, - { "latin4", 28594 }, - { "windows-1257", 1257 }, - { "ibm852", 852 }, - { "cp852", 852 }, - { "iso-8859-2", 28592 }, - { "csISOLatin2", 28592 }, - { "iso_8859-2", 28592 }, - { "iso_8859-2:1987", 28592 }, - { "iso-ir-101", 28592 }, - { "l2", 28592 }, - { "latin2", 28592 }, - { "x-mac-ce", 10029 }, - { "windows-1250", 1250 }, - { "x-cp1250", 1250 }, - { "EUC-CN", 51936 }, - { "x-euc-cn", 51936 }, - { "gb2312", 936 }, - { "chinese", 936 }, - { "CN-GB", 936 }, - { "csGB2312", 936 }, - { "csGB231280", 936 }, - { "csISO58GB231280", 936 }, - { "GB_2312-80", 936 }, - { "GB231280", 936 }, - { "GB2312-80", 936 }, - { "GBK", 936 }, - { "iso-ir-58", 936 }, - { "hz-gb-2312", 52936 }, - { "x-mac-chinesesimp", 10008 }, - { "big5", 950 }, - { "cn-big5", 950 }, - { "csbig5", 950 }, - { "x-x-big5", 950 }, - { "x-Chinese-CNS", 20000 }, - { "x-Chinese-Eten", 20002 }, - { "x-mac-chinesetrad", 10002 }, - { "cp866", 866 }, - { "ibm866", 866 }, - { "iso-8859-5", 28595 }, - { "csISOLatin5", 28595 }, - { "csISOLatinCyrillic", 28595 }, - { "cyrillic", 28595 }, - { "ISO_8859-5", 28595 }, - { "ISO_8859-5:1988", 28595 }, - { "iso-ir-144", 28595 }, - { "l5", 28595 }, - { "KOI8-R", 20866 }, - { "csKOI8R", 20866 }, - { "koi", 20866 }, - { "koi8", 20866 }, - { "koi8r", 20866 }, - { "KOI8-U", 21866 }, - { "koi8-ru", 21866 }, - { "x-mac-cyrillic", 10007 }, - { "windows-1251", 1251 }, - { "Win1251", 1251 }, - { "x-cp1251", 1251 }, - { "x-Europa", 29001 }, - { "x-IA5-German", 20106 }, - { "ibm737", 737 }, - { "iso-8859-7", 28597 }, - { "csISOLatinGreek", 28597 }, - { "ECMA-118", 28597 }, - { "ELOT_928", 28597 }, - { "greek", 28597 }, - { "greek8", 28597 }, - { "ISO_8859-7", 28597 }, - { "ISO_8859-7:1987", 28597 }, - { "iso-ir-126", 28597 }, - { "x-mac-greek", 10006 }, - { "windows-1253", 1253 }, - { "ibm869", 869 }, - { "DOS-862", 862 }, - { "iso-8859-8-i", 38598 }, - { "logical", 38598 }, - { "iso-8859-8", 28598 }, - { "csISOLatinHebrew", 28598 }, - { "hebrew", 28598 }, - { "ISO_8859-8", 28598 }, - { "ISO_8859-8:1988", 28598 }, - { "ISO-8859-8", 28598 }, - { "iso-ir-138", 28598 }, - { "visual", 28598 }, - { "x-mac-hebrew", 10005 }, - { "windows-1255", 1255 }, - { "ISO_8859-8-I", 1255 }, - { "ISO-8859-8", 1255 }, - { "x-EBCDIC-Arabic", 20420 }, - { "x-EBCDIC-CyrillicRussian", 20880 }, - { "x-EBCDIC-CyrillicSerbianBulgarian", 21025 }, - { "x-EBCDIC-DenmarkNorway", 20277 }, - { "x-ebcdic-denmarknorway-euro", 1142 }, - { "x-EBCDIC-FinlandSweden", 20278 }, - { "x-ebcdic-finlandsweden-euro", 1143 }, - { "X-EBCDIC-France", 1143 }, - { "X-EBCDIC-France", 1143 }, - { "x-ebcdic-france-euro", 1147 }, - { "x-EBCDIC-Germany", 20273 }, - { "x-ebcdic-germany-euro", 1141 }, - { "x-EBCDIC-GreekModern", 875 }, - { "x-EBCDIC-Greek", 20423 }, - { "x-EBCDIC-Hebrew", 20424 }, - { "x-EBCDIC-Icelandic", 20871 }, - { "x-ebcdic-icelandic-euro", 1149 }, - { "x-ebcdic-international-euro", 1148 }, - { "x-EBCDIC-Italy", 20280 }, - { "x-ebcdic-italy-euro", 1144 }, - { "x-EBCDIC-JapaneseAndKana", 50930 }, - { "x-EBCDIC-JapaneseAndJapaneseLatin", 50939 }, - { "x-EBCDIC-JapaneseAndUSCanada", 50931 }, - { "x-EBCDIC-JapaneseKatakana", 20290 }, - { "x-EBCDIC-KoreanAndKoreanExtended", 50933 }, - { "x-EBCDIC-KoreanExtended", 20833 }, - { "CP870", 870 }, - { "x-EBCDIC-SimplifiedChinese", 50935 }, - { "X-EBCDIC-Spain", 20284 }, - { "x-ebcdic-spain-euro", 1145 }, - { "x-EBCDIC-Thai", 20838 }, - { "x-EBCDIC-TraditionalChinese", 50937 }, - { "CP1026", 1026 }, - { "x-EBCDIC-Turkish", 20905 }, - { "x-EBCDIC-UK", 20285 }, - { "x-ebcdic-uk-euro", 1146 }, - { "ebcdic-cp-us", 37 }, - { "x-ebcdic-cp-us-euro", 1140 }, - { "ibm861", 861 }, - { "x-mac-icelandic", 10079 }, - { "x-iscii-as", 57006 }, - { "x-iscii-be", 57003 }, - { "x-iscii-de", 57002 }, - { "x-iscii-gu", 57010 }, - { "x-iscii-ka", 57008 }, - { "x-iscii-ma", 57009 }, - { "x-iscii-or", 57007 }, - { "x-iscii-pa", 57011 }, - { "x-iscii-ta", 57004 }, - { "x-iscii-te", 57005 }, - { "euc-jp", 51932 }, - { "csEUCPkdFmtJapanese", 51932 }, - { "Extended_UNIX_Code_Packed_Format_for_Japanese", 51932 }, - { "x-euc", 51932 }, - { "x-euc-jp", 51932 }, - { "iso-2022-jp", 50220 }, - { "iso-2022-jp", 50222 }, - { "_iso-2022-jp$SIO", 50222 }, - { "csISO2022JP", 50221 }, - { "_iso-2022-jp", 50221 }, - { "x-mac-japanese", 10001 }, - { "shift_jis", 932 }, - { "csShiftJIS", 932 }, - { "csWindows31J", 932 }, - { "ms_Kanji", 932 }, - { "shift-jis", 932 }, - { "x-ms-cp932", 932 }, - { "x-sjis", 932 }, - { "ks_c_5601-1987", 949 }, - { "csKSC56011987", 949 }, - { "euc-kr", 949 }, - { "iso-ir-149", 949 }, - { "korean", 949 }, - { "ks_c_5601", 949 }, - { "ks_c_5601_1987", 949 }, - { "ks_c_5601-1989", 949 }, - { "KSC_5601", 949 }, - { "KSC5601", 949 }, - { "euc-kr", 51949 }, - { "csEUCKR", 51949 }, - { "iso-2022-kr", 50225 }, - { "csISO2022KR", 50225 }, - { "Johab", 1361 }, - { "x-mac-korean", 10003 }, - { "iso-8859-3", 28593 }, - { "csISO", 28593 }, - { "Latin3", 28593 }, - { "ISO_8859-3", 28593 }, - { "ISO_8859-3:1988", 28593 }, - { "iso-ir-109", 28593 }, - { "l3", 28593 }, - { "latin3", 28593 }, - { "iso-8859-15", 28605 }, - { "csISO", 28605 }, - { "Latin9", 28605 }, - { "ISO_8859-15", 28605 }, - { "l9", 28605 }, - { "latin9", 28605 }, - { "x-IA5-Norwegian", 20108 }, - { "IBM437", 437 }, - { "437", 437 }, - { "cp437", 437 }, - { "csPC8", 437 }, - { "CodePage437", 437 }, - { "x-IA5-Swedish", 20107 }, - { "windows-874", 874 }, - { "DOS-874", 874 }, - { "iso-8859-11", 874 }, - { "TIS-620", 874 }, - { "ibm857", 857 }, - { "iso-8859-9", 28599 }, - { "csISO", 28599 }, - { "Latin5", 28599 }, - { "ISO_8859-9", 28599 }, - { "ISO_8859-9:1989", 28599 }, - { "iso-ir-148", 28599 }, - { "l5", 28599 }, - { "latin5", 28599 }, - { "x-mac-turkish", 10081 }, - { "windows-1254", 1254 }, - { "ISO_8859-9", 1254 }, - { "ISO_8859-9:1989", 1254 }, - { "iso-8859-9", 1254 }, - { "iso-ir-148", 1254 }, - { "latin5", 1254 }, - { "unicode", 1200 }, - { "utf-16", 1200 }, - { "unicodeFFFE", 1201 }, - { "utf-7", 65000 }, - { "csUnicode11UTF7", 65000 }, - { "unicode-1-1-utf-7", 65000 }, - { "x-unicode-2-0-utf-7", 65000 }, - { "utf-8", 65001 }, - { "unicode-1-1-utf-8", 65001 }, - { "unicode-2-0-utf-8", 65001 }, - { "x-unicode-2-0-utf-8", 65001 }, - { "us-ascii", 20127 }, - { "ANSI_X3.4-1968", 20127 }, - { "ANSI_X3.4-1986", 20127 }, - { "ascii", 20127 }, - { "cp367", 20127 }, - { "csASCII", 20127 }, - { "IBM367", 20127 }, - { "ISO_646.irv:1991", 20127 }, - { "ISO646-US", 20127 }, - { "iso-ir-6us", 20127 }, - { "windows-1258", 1258 }, - { "ibm850", 850 }, - { "x-IA5", 20105 }, - { "iso-8859-1", 28591 }, - { "cp819", 28591 }, - { "csISO", 28591 }, - { "Latin1", 28591 }, - { "ibm819", 28591 }, - { "iso_8859-1", 28591 }, - { "iso_8859-1:1987", 28591 }, - { "iso-ir-100", 28591 }, - { "l1", 28591 }, - { "latin1", 28591 }, - { "macintosh", 10000 }, - { "Windows-1252", 1252 }, - { "ANSI_X3.4-1968", 1252 }, - { "ANSI_X3.4-1986", 1252 }, - { "ascii", 1252 }, - { "cp367", 1252 }, - { "cp819", 1252 }, - { "csASCII", 1252 }, - { "IBM367", 1252 }, - { "ibm819", 1252 }, - { "ISO_646.irv:1991", 1252 }, - { "iso_8859-1", 1252 }, - { "iso_8859-1:1987", 1252 }, - { "ISO646-US", 1252 }, - { "iso-ir-100", 1252 }, - { "iso-ir-6", 1252 }, - { "latin1", 1252 }, - { "us", 1252 }, - { "us-ascii", 1252 }, - { "x-ansi", 1252 }, - { "microsoft-cp1251", 1251 } -}; - -#define LANGUAGE_NOT_LOADED 1 -#define LANGUAGE_LOADING -1 -#define LANGUAGE_LOADED 0 - -void LoadThread(LPVOID hd); - -class HunspellDictionary : public Dictionary -{ -protected: - TCHAR fileWithoutExtension[1024]; - TCHAR userPath[1024]; - volatile int loaded; - Hunspell *hunspell; - TCHAR *wordChars; - UINT codePage; - - void loadCustomDict() - { - TCHAR filename[1024]; - mir_sntprintf(filename, SIZEOF(filename), _T("%s\\%s.cdic"), userPath, language); - - FILE *file = _tfopen(filename, _T("rb")); - if (file != NULL) { - char tmp[1024]; - char c; - int pos = 0; - while ((c = fgetc(file)) != EOF) { - if (c == '\n' || c == '\r' || pos >= SIZEOF(tmp) - 1) { - if (pos > 0) { - tmp[pos] = '\0'; - hunspell->add(tmp); - } - - pos = 0; - } - else { - tmp[pos] = c; - pos++; - } - } - fclose(file); - } - } - - void appendToCustomDict(const TCHAR *word) - { - CreateDirectoryTreeT(userPath); - - TCHAR filename[1024]; - mir_sntprintf(filename, SIZEOF(filename), _T("%s\\%s.cdic"), userPath, language); - - FILE *file = _tfopen(filename, _T("ab")); - if (file != NULL) { - char tmp[1024]; - toHunspell(tmp, word, SIZEOF(tmp)); - fprintf(file, "%s\n", tmp); - fclose(file); - } - } - - virtual void addWordInternal(const TCHAR * word) - { - if (loaded != LANGUAGE_LOADED) - return; - - char hunspell_word[1024]; - toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); - - hunspell->add(hunspell_word); - } - - void toHunspell(char *hunspellWord, const TCHAR *word, size_t hunspellWordLen) - { - WideCharToMultiByte(codePage, 0, word, -1, hunspellWord, (int)hunspellWordLen, NULL, NULL); - } - - TCHAR* fromHunspell(const char *hunspellWord) - { - int len = MultiByteToWideChar(codePage, 0, hunspellWord, -1, NULL, 0); - WCHAR *ret = (WCHAR *)malloc((len + 1) * sizeof(WCHAR)); - MultiByteToWideChar(codePage, 0, hunspellWord, -1, ret, len + 1); - return ret; - } - - TCHAR* fromHunspellAndFree(char *hunspellWord) - { - if (hunspellWord == NULL) - return NULL; - - TCHAR *ret = fromHunspell(hunspellWord); - free(hunspellWord); - return ret; - } - -public: - HunspellDictionary(TCHAR *aLanguage, TCHAR *aFileWithoutExtension, TCHAR *anUserPath, TCHAR *aSource) - { - lstrcpyn(language, aLanguage, SIZEOF(language)); - lstrcpyn(fileWithoutExtension, aFileWithoutExtension, SIZEOF(fileWithoutExtension)); - lstrcpyn(userPath, anUserPath, SIZEOF(userPath)); - if (aSource == NULL) - source[0] = _T('\0'); - else - lstrcpyn(source, aSource, SIZEOF(source)); - - loaded = LANGUAGE_NOT_LOADED; - localized_name[0] = _T('\0'); - english_name[0] = _T('\0'); - full_name[0] = _T('\0'); - hunspell = NULL; - wordChars = NULL; - codePage = CP_ACP; - autoReplace = NULL; - } - - virtual ~HunspellDictionary() - { - if (hunspell != NULL) - delete hunspell; - if (wordChars != NULL) - free(wordChars); - } - - TCHAR * merge(TCHAR * s1, TCHAR *s2) - { - int len1 = (s1 == NULL ? 0 : lstrlen(s1)); - int len2 = (s2 == NULL ? 0 : lstrlen(s2)); - - TCHAR *ret; - if (len1 > 0 && len2 > 0) { - ret = (TCHAR *)malloc(sizeof(TCHAR) * (len1 + len2 + 1)); - lstrcpyn(ret, s1, len1 + 1); - lstrcpyn(&ret[len1], s2, len2 + 1); - - FREE(s1); - FREE(s2); - } - else if (len1 > 0) { - ret = s1; - FREE(s2); - } - else if (len2 > 0) { - ret = s2; - FREE(s1); - } - else { - ret = (TCHAR *)malloc(sizeof(TCHAR)); - ret[0] = 0; - - FREE(s1); - FREE(s2); - } - - // Remove duplicated chars - int last = lstrlen(ret) - 1; - for (int i = 0; i <= last; i++) { - TCHAR c = ret[i]; - for (int j = last; j > i; j--) { - if (c != ret[j]) - continue; - if (j != last) - ret[j] = ret[last]; - ret[last] = _T('\0'); - last--; - } - } - - return ret; - } - - - void loadThread() - { - char dic[1024]; - char aff[1024]; - - - mir_snprintf(dic, SIZEOF(dic), "%S.dic", fileWithoutExtension); - mir_snprintf(aff, SIZEOF(aff), "%S.aff", fileWithoutExtension); - - - hunspell = new Hunspell(aff, dic); - - // Get codepage - const char *dic_enc = hunspell->get_dic_encoding(); - - TCHAR *hwordchars; - if (strcmp(dic_enc, "UTF-8") == 0) { - codePage = CP_UTF8; - - - int wcs_len; - hwordchars = fromHunspell((char *)hunspell->get_wordchars_utf16(&wcs_len)); - - } - else { - for (int i = 0; i < SIZEOF(codepages); i++) { - if (_strcmpi(codepages[i].name, dic_enc) == 0) { - if (IsValidCodePage(codepages[i].codepage)) - codePage = codepages[i].codepage; - break; - } - } - - hwordchars = fromHunspell(hunspell->get_wordchars()); - } - - TCHAR *casechars = fromHunspellAndFree(get_casechars(dic_enc)); - TCHAR *try_string = fromHunspellAndFree(hunspell->get_try_string()); - - wordChars = merge(merge(casechars, hwordchars), try_string); - - // Make a suggestion to load hunspell internalls - char ** words = NULL; - int count = hunspell->suggest(&words, "asdf"); - for (int i = 0; i < count; i++) - free(words[i]); - if (words != NULL) - free(words); - - loadCustomDict(); - - loaded = LANGUAGE_LOADED; - } - - // Return TRUE if the word is correct - virtual BOOL spell(const TCHAR *word) - { - load(); - if (loaded != LANGUAGE_LOADED) - return TRUE; - - // TODO Check if it was generated by auto-replacement - - char hunspell_word[1024]; - toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); - - return hunspell->spell(hunspell_word); - } - - // Return a list of suggestions to a word - virtual Suggestions suggest(const TCHAR * word) - { - Suggestions ret = { 0 }; - - load(); - if (loaded != LANGUAGE_LOADED) - return ret; - - char hunspell_word[1024]; - toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); - - char ** words = NULL; - ret.count = hunspell->suggest(&words, hunspell_word); - - if (ret.count > 0) { - // Oki, lets make our array - ret.words = (TCHAR **)malloc(ret.count * sizeof(TCHAR *)); - for (unsigned i = 0; i < ret.count; i++) { - ret.words[i] = fromHunspell(words[i]); - free(words[i]); - } - } - - if (words != NULL) - free(words); - - return ret; - } - - // Return a list of auto suggestions to a word - virtual Suggestions autoSuggest(const TCHAR * word) - { - Suggestions ret = { 0 }; - - load(); - if (loaded != LANGUAGE_LOADED) - return ret; - - char hunspell_word[1024]; - toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); - - char ** words; - int count = hunspell->suggest_auto(&words, hunspell_word); - - if (count <= 0) - return ret; - - // Oki, lets make our array - ret.count = count; - ret.words = (TCHAR **)malloc(ret.count * sizeof(TCHAR *)); - for (int i = 0; i < count; i++) { - ret.words[i] = fromHunspell(words[i]); - free(words[i]); - } - free(words); - - return ret; - } - - // Return a list of auto suggestions to a word - // You have to free the list AND each item - virtual TCHAR * autoSuggestOne(const TCHAR * word) - { - load(); - if (loaded != LANGUAGE_LOADED) - return NULL; - - char hunspell_word[1024]; - toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); - - char ** words; - int count = hunspell->suggest_auto(&words, hunspell_word); - - if (count <= 0) - return NULL; - - TCHAR *ret = fromHunspell(words[0]); - - // Oki, lets make our array - for (int i = 0; i < count; i++) - free(words[i]); - free(words); - - return ret; - } - - // Return TRUE if the char is a word char - virtual BOOL isWordChar(TCHAR c) - { - if (c == 0) - return FALSE; - - load(); - if (loaded != LANGUAGE_LOADED) - return TRUE; - - return _tcschr(wordChars, (_TINT)c) != NULL; - } - - // Assert that all needed data is loaded - virtual void load() - { - if (loaded == LANGUAGE_NOT_LOADED) { - loaded = LANGUAGE_LOADING; - mir_forkthread(LoadThread, this); - } - } - - virtual BOOL isLoaded() - { - return loaded == LANGUAGE_LOADED; - } - - - // Add a word to the user custom dict - virtual void addWord(const TCHAR * word) - { - addWordInternal(word); - appendToCustomDict(word); - } - - // Add a word to the list of ignored words - virtual void ignoreWord(const TCHAR * word) - { - addWordInternal(word); - } -}; - -void LoadThread(LPVOID hd) -{ - HunspellDictionary *dict = (HunspellDictionary *)hd; - dict->loadThread(); -} - - - -// To use with EnumLocalesProc :( -LIST *tmp_dicts; - -// To get the names of the languages -BOOL CALLBACK EnumLocalesProc(LPTSTR lpLocaleString) -{ - TCHAR *stopped = NULL; - USHORT langID = (USHORT)_tcstol(lpLocaleString, &stopped, 16); - - TCHAR ini[32]; - TCHAR end[32]; - GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SISO639LANGNAME, ini, SIZEOF(ini)); - GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SISO3166CTRYNAME, end, SIZEOF(end)); - - TCHAR name[64]; - mir_sntprintf(name, SIZEOF(name), _T("%s_%s"), ini, end); - - for (int i = 0; i < tmp_dicts->getCount(); i++) { - Dictionary *dict = (*tmp_dicts)[i]; - if (lstrcmpi(dict->language, name) == 0) { - GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SENGLANGUAGE, dict->english_name, SIZEOF(dict->english_name)); - - GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SLANGUAGE, dict->localized_name, SIZEOF(dict->localized_name)); - if (dict->localized_name[0] == 0) - GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SLOCALIZEDLANGUAGENAME, dict->localized_name, SIZEOF(dict->localized_name)); - if (dict->localized_name[0] == 0) - GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SNATIVEDISPLAYNAME, dict->localized_name, SIZEOF(dict->localized_name)); - if (dict->localized_name[0] == 0 && dict->english_name[0] != 0) { - TCHAR country[1024]; - GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SENGCOUNTRY, country, SIZEOF(country)); - - TCHAR name[1024]; - if (country[0] != 0) - mir_sntprintf(name, SIZEOF(name), _T("%s (%s)"), dict->english_name, country); - else - lstrcpyn(name, dict->english_name, SIZEOF(name)); - - lstrcpyn(dict->localized_name, TranslateTS(name), SIZEOF(dict->localized_name)); - } - - if (dict->localized_name[0] != 0) { - mir_sntprintf(dict->full_name, SIZEOF(dict->full_name), _T("%s [%s]"), dict->localized_name, dict->language); - } - break; - } - } - return TRUE; -} - - -void GetDictsInfo(LIST &dicts) -{ - tmp_dicts = &dicts; - EnumSystemLocales(EnumLocalesProc, LCID_SUPPORTED); - - // Try to get name from DB - for (int i = 0; i < dicts.getCount(); i++) { - Dictionary *dict = dicts[i]; - - if (dict->full_name[0] == _T('\0')) { - DBVARIANT dbv; - - char lang[128]; - WideCharToMultiByte(CP_ACP, 0, dict->language, -1, lang, sizeof(lang), NULL, NULL); - if (!db_get_ts(NULL, MODULE_NAME, lang, &dbv)) { - lstrcpyn(dict->localized_name, dbv.ptszVal, SIZEOF(dict->localized_name)); - db_free(&dbv); - } - - if (dict->localized_name[0] == _T('\0')) { - for (size_t j = 0; j < SIZEOF(aditionalLanguages); j++) { - if (!lstrcmp(aditionalLanguages[j].language, dict->language)) { - lstrcpyn(dict->localized_name, TranslateTS(aditionalLanguages[j].localized_name), SIZEOF(dict->localized_name)); - break; - } - } - } - - if (dict->localized_name[0] != _T('\0')) { - mir_sntprintf(dict->full_name, SIZEOF(dict->full_name), _T("%s [%s]"), dict->localized_name, dict->language); - } - else { - lstrcpyn(dict->full_name, dict->language, SIZEOF(dict->full_name)); - } - } - } -} - - -void GetHunspellDictionariesFromFolder(LIST &dicts, TCHAR *path, TCHAR *user_path, TCHAR *source) -{ - // Load the language files and create an array with then - TCHAR file[1024]; - mir_sntprintf(file, SIZEOF(file), _T("%s\\*.dic"), path); - - BOOL found = FALSE; - - WIN32_FIND_DATA ffd = { 0 }; - HANDLE hFFD = FindFirstFile(file, &ffd); - if (hFFD != INVALID_HANDLE_VALUE) { - do { - mir_sntprintf(file, SIZEOF(file), _T("%s\\%s"), path, ffd.cFileName); - - // Check .dic - DWORD attrib = GetFileAttributes(file); - if (attrib == 0xFFFFFFFF || (attrib & FILE_ATTRIBUTE_DIRECTORY)) - continue; - - // See if .aff exists too - lstrcpy(&file[lstrlen(file) - 4], _T(".aff")); - attrib = GetFileAttributes(file); - if (attrib == 0xFFFFFFFF || (attrib & FILE_ATTRIBUTE_DIRECTORY)) - continue; - - ffd.cFileName[lstrlen(ffd.cFileName) - 4] = _T('\0'); - - TCHAR *lang = ffd.cFileName; - - // Replace - for _ - for (int i = 0; i < lstrlen(lang); i++) - if (lang[i] == _T('-')) - lang[i] = _T('_'); - - // Check if dict is new - bool exists = false; - for (int i = 0; i < dicts.getCount() && !exists; i++) - if (lstrcmp(dicts[i]->language, lang) == 0) - exists = true; - - if (!exists) { - found = TRUE; - file[lstrlen(file) - 4] = _T('\0'); - dicts.insert(new HunspellDictionary(lang, file, user_path, source)); - } - } - while (FindNextFile(hFFD, &ffd)); - - FindClose(hFFD); - } -} - - -// Return a list of avaible languages -void GetAvaibleDictionaries(LIST &dicts, TCHAR *path, TCHAR *user_path) -{ - // Get miranda folder dicts - GetHunspellDictionariesFromFolder(dicts, path, user_path, NULL); - - if (opts.use_other_apps_dicts) { - // Get other apps dicts - for (int i = 0; i < SIZEOF(otherHunspellApps); i++) { - TCHAR key[1024]; - mir_sntprintf(key, SIZEOF(key), APPPATH, otherHunspellApps[i].key); - - HKEY hKey = 0; - LONG lResult = 0; - if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE, &hKey)) { - DWORD size = SIZEOF(key); - lResult = RegQueryValueEx(hKey, _T("Path"), NULL, NULL, (LPBYTE)key, &size); - RegCloseKey(hKey); - } - else { - // Not found in installed apps - Try MUICache - lResult = RegOpenKeyEx(HKEY_CURRENT_USER, MUICACHE, 0, KEY_QUERY_VALUE, &hKey); - if (ERROR_SUCCESS == lResult) { - DWORD numValues; - if (ERROR_SUCCESS != RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &numValues, NULL, NULL, NULL, NULL)) - numValues = 0; - - lResult = ERROR_NO_MORE_ITEMS; - for (DWORD local = 0; local < numValues; local++) { - DWORD cchValue = SIZEOF(key); - if (ERROR_SUCCESS != RegEnumValue(hKey, local, key, &cchValue, NULL, NULL, NULL, NULL)) - break; - key[cchValue] = 0; - TCHAR *pos; - if (pos = _tcsrchr(key, _T('\\'))) { - if (!lstrcmpi(&pos[1], otherHunspellApps[i].key)) { - pos[0] = 0; - lResult = ERROR_SUCCESS; - break; - } - } - } - RegCloseKey(hKey); - } - } - - if (ERROR_SUCCESS == lResult) { - TCHAR folder[1024]; - mir_sntprintf(folder, SIZEOF(folder), _T("%s\\Dictionaries"), key); - - GetHunspellDictionariesFromFolder(languages, folder, user_path, otherHunspellApps[i].name); - } - } - } - - GetDictsInfo(dicts); - - // Yeah, yeah, yeah, I know, but this is the easiest way... - SortedList *sl = (SortedList *)&dicts; - - // Sort dicts - for (int i = 0; i < dicts.getCount(); i++) { - for (int j = i + 1; j < dicts.getCount(); j++) { - if (lstrcmp(dicts[i]->full_name, dicts[j]->full_name) > 0) { - Dictionary *dict = dicts[i]; - sl->items[i] = dicts[j]; - sl->items[j] = dict; - } - } - } -} - - -// Free the list returned by GetAvaibleDictionaries -void FreeDictionaries(LIST &dicts) -{ - for (int i = 0; i < dicts.getCount(); i++) - delete dicts[i]; - - dicts.destroy(); -} - -Dictionary::~Dictionary() -{ - delete autoReplace; -} - -// Free the list returned by GetAvaibleDictionaries -void FreeSuggestions(Suggestions &suggestions) -{ - for (size_t i = 0; i < suggestions.count; i++) - free(suggestions.words[i]); - - free(suggestions.words); - - suggestions.words = NULL; - suggestions.count = 0; -} +/* +Copyright (C) 2006-2010 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "commons.h" + +#define APPPATH _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s") +#define MUICACHE _T("Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache") + + +// Additional languages that i could not find in Windows +struct { + TCHAR *language; + TCHAR *localized_name; +} aditionalLanguages[] = { + { _T("tl_PH"), LPGENT("Tagalog (Philippines)") }, + { _T("de_frami_neu"), LPGENT("German (Germany)") } +}; + +struct { + TCHAR *name; + TCHAR *key; +} otherHunspellApps[] = { + { _T("Thunderbird"), _T("thunderbird.exe") }, + { _T("Firefox"), _T("firefox.exe") } +}; + +struct { + char *name; + UINT codepage; +} codepages[] = { + { "ISO8859-1", 28591 }, + { "UTF-7", CP_UTF7 }, + { "UTF-8", CP_UTF8 }, + { "UTF7", CP_UTF7 }, + { "UTF8", CP_UTF8 }, + { "ISO8859-2", 28592 }, + { "ISO8859-3", 28593 }, + { "ISO8859-4", 28594 }, + { "ISO8859-5", 28595 }, + { "ISO8859-6", 28596 }, + { "ISO8859-7", 28597 }, + { "ISO8859-8", 28598 }, + { "ISO8859-9", 28599 }, + { "ASMO-708", 708 }, + { "DOS-720", 720 }, + { "iso-8859-6", 28596 }, + { "arabic", 28596 }, + { "csISOLatinArabic", 28596 }, + { "ECMA-114", 28596 }, + { "ISO_8859-6", 28596 }, + { "ISO_8859-6:1987", 28596 }, + { "iso-ir-127", 28596 }, + { "x-mac-arabic", 10004 }, + { "windows-1256", 1256 }, + { "cp1256", 1256 }, + { "ibm775", 775 }, + { "CP500", 775 }, + { "iso-8859-4", 28594 }, + { "csISOLatin4", 28594 }, + { "ISO_8859-4", 28594 }, + { "ISO_8859-4:1988", 28594 }, + { "iso-ir-110", 28594 }, + { "l4", 28594 }, + { "latin4", 28594 }, + { "windows-1257", 1257 }, + { "ibm852", 852 }, + { "cp852", 852 }, + { "iso-8859-2", 28592 }, + { "csISOLatin2", 28592 }, + { "iso_8859-2", 28592 }, + { "iso_8859-2:1987", 28592 }, + { "iso-ir-101", 28592 }, + { "l2", 28592 }, + { "latin2", 28592 }, + { "x-mac-ce", 10029 }, + { "windows-1250", 1250 }, + { "x-cp1250", 1250 }, + { "EUC-CN", 51936 }, + { "x-euc-cn", 51936 }, + { "gb2312", 936 }, + { "chinese", 936 }, + { "CN-GB", 936 }, + { "csGB2312", 936 }, + { "csGB231280", 936 }, + { "csISO58GB231280", 936 }, + { "GB_2312-80", 936 }, + { "GB231280", 936 }, + { "GB2312-80", 936 }, + { "GBK", 936 }, + { "iso-ir-58", 936 }, + { "hz-gb-2312", 52936 }, + { "x-mac-chinesesimp", 10008 }, + { "big5", 950 }, + { "cn-big5", 950 }, + { "csbig5", 950 }, + { "x-x-big5", 950 }, + { "x-Chinese-CNS", 20000 }, + { "x-Chinese-Eten", 20002 }, + { "x-mac-chinesetrad", 10002 }, + { "cp866", 866 }, + { "ibm866", 866 }, + { "iso-8859-5", 28595 }, + { "csISOLatin5", 28595 }, + { "csISOLatinCyrillic", 28595 }, + { "cyrillic", 28595 }, + { "ISO_8859-5", 28595 }, + { "ISO_8859-5:1988", 28595 }, + { "iso-ir-144", 28595 }, + { "l5", 28595 }, + { "KOI8-R", 20866 }, + { "csKOI8R", 20866 }, + { "koi", 20866 }, + { "koi8", 20866 }, + { "koi8r", 20866 }, + { "KOI8-U", 21866 }, + { "koi8-ru", 21866 }, + { "x-mac-cyrillic", 10007 }, + { "windows-1251", 1251 }, + { "Win1251", 1251 }, + { "x-cp1251", 1251 }, + { "x-Europa", 29001 }, + { "x-IA5-German", 20106 }, + { "ibm737", 737 }, + { "iso-8859-7", 28597 }, + { "csISOLatinGreek", 28597 }, + { "ECMA-118", 28597 }, + { "ELOT_928", 28597 }, + { "greek", 28597 }, + { "greek8", 28597 }, + { "ISO_8859-7", 28597 }, + { "ISO_8859-7:1987", 28597 }, + { "iso-ir-126", 28597 }, + { "x-mac-greek", 10006 }, + { "windows-1253", 1253 }, + { "ibm869", 869 }, + { "DOS-862", 862 }, + { "iso-8859-8-i", 38598 }, + { "logical", 38598 }, + { "iso-8859-8", 28598 }, + { "csISOLatinHebrew", 28598 }, + { "hebrew", 28598 }, + { "ISO_8859-8", 28598 }, + { "ISO_8859-8:1988", 28598 }, + { "ISO-8859-8", 28598 }, + { "iso-ir-138", 28598 }, + { "visual", 28598 }, + { "x-mac-hebrew", 10005 }, + { "windows-1255", 1255 }, + { "ISO_8859-8-I", 1255 }, + { "ISO-8859-8", 1255 }, + { "x-EBCDIC-Arabic", 20420 }, + { "x-EBCDIC-CyrillicRussian", 20880 }, + { "x-EBCDIC-CyrillicSerbianBulgarian", 21025 }, + { "x-EBCDIC-DenmarkNorway", 20277 }, + { "x-ebcdic-denmarknorway-euro", 1142 }, + { "x-EBCDIC-FinlandSweden", 20278 }, + { "x-ebcdic-finlandsweden-euro", 1143 }, + { "X-EBCDIC-France", 1143 }, + { "X-EBCDIC-France", 1143 }, + { "x-ebcdic-france-euro", 1147 }, + { "x-EBCDIC-Germany", 20273 }, + { "x-ebcdic-germany-euro", 1141 }, + { "x-EBCDIC-GreekModern", 875 }, + { "x-EBCDIC-Greek", 20423 }, + { "x-EBCDIC-Hebrew", 20424 }, + { "x-EBCDIC-Icelandic", 20871 }, + { "x-ebcdic-icelandic-euro", 1149 }, + { "x-ebcdic-international-euro", 1148 }, + { "x-EBCDIC-Italy", 20280 }, + { "x-ebcdic-italy-euro", 1144 }, + { "x-EBCDIC-JapaneseAndKana", 50930 }, + { "x-EBCDIC-JapaneseAndJapaneseLatin", 50939 }, + { "x-EBCDIC-JapaneseAndUSCanada", 50931 }, + { "x-EBCDIC-JapaneseKatakana", 20290 }, + { "x-EBCDIC-KoreanAndKoreanExtended", 50933 }, + { "x-EBCDIC-KoreanExtended", 20833 }, + { "CP870", 870 }, + { "x-EBCDIC-SimplifiedChinese", 50935 }, + { "X-EBCDIC-Spain", 20284 }, + { "x-ebcdic-spain-euro", 1145 }, + { "x-EBCDIC-Thai", 20838 }, + { "x-EBCDIC-TraditionalChinese", 50937 }, + { "CP1026", 1026 }, + { "x-EBCDIC-Turkish", 20905 }, + { "x-EBCDIC-UK", 20285 }, + { "x-ebcdic-uk-euro", 1146 }, + { "ebcdic-cp-us", 37 }, + { "x-ebcdic-cp-us-euro", 1140 }, + { "ibm861", 861 }, + { "x-mac-icelandic", 10079 }, + { "x-iscii-as", 57006 }, + { "x-iscii-be", 57003 }, + { "x-iscii-de", 57002 }, + { "x-iscii-gu", 57010 }, + { "x-iscii-ka", 57008 }, + { "x-iscii-ma", 57009 }, + { "x-iscii-or", 57007 }, + { "x-iscii-pa", 57011 }, + { "x-iscii-ta", 57004 }, + { "x-iscii-te", 57005 }, + { "euc-jp", 51932 }, + { "csEUCPkdFmtJapanese", 51932 }, + { "Extended_UNIX_Code_Packed_Format_for_Japanese", 51932 }, + { "x-euc", 51932 }, + { "x-euc-jp", 51932 }, + { "iso-2022-jp", 50220 }, + { "iso-2022-jp", 50222 }, + { "_iso-2022-jp$SIO", 50222 }, + { "csISO2022JP", 50221 }, + { "_iso-2022-jp", 50221 }, + { "x-mac-japanese", 10001 }, + { "shift_jis", 932 }, + { "csShiftJIS", 932 }, + { "csWindows31J", 932 }, + { "ms_Kanji", 932 }, + { "shift-jis", 932 }, + { "x-ms-cp932", 932 }, + { "x-sjis", 932 }, + { "ks_c_5601-1987", 949 }, + { "csKSC56011987", 949 }, + { "euc-kr", 949 }, + { "iso-ir-149", 949 }, + { "korean", 949 }, + { "ks_c_5601", 949 }, + { "ks_c_5601_1987", 949 }, + { "ks_c_5601-1989", 949 }, + { "KSC_5601", 949 }, + { "KSC5601", 949 }, + { "euc-kr", 51949 }, + { "csEUCKR", 51949 }, + { "iso-2022-kr", 50225 }, + { "csISO2022KR", 50225 }, + { "Johab", 1361 }, + { "x-mac-korean", 10003 }, + { "iso-8859-3", 28593 }, + { "csISO", 28593 }, + { "Latin3", 28593 }, + { "ISO_8859-3", 28593 }, + { "ISO_8859-3:1988", 28593 }, + { "iso-ir-109", 28593 }, + { "l3", 28593 }, + { "latin3", 28593 }, + { "iso-8859-15", 28605 }, + { "csISO", 28605 }, + { "Latin9", 28605 }, + { "ISO_8859-15", 28605 }, + { "l9", 28605 }, + { "latin9", 28605 }, + { "x-IA5-Norwegian", 20108 }, + { "IBM437", 437 }, + { "437", 437 }, + { "cp437", 437 }, + { "csPC8", 437 }, + { "CodePage437", 437 }, + { "x-IA5-Swedish", 20107 }, + { "windows-874", 874 }, + { "DOS-874", 874 }, + { "iso-8859-11", 874 }, + { "TIS-620", 874 }, + { "ibm857", 857 }, + { "iso-8859-9", 28599 }, + { "csISO", 28599 }, + { "Latin5", 28599 }, + { "ISO_8859-9", 28599 }, + { "ISO_8859-9:1989", 28599 }, + { "iso-ir-148", 28599 }, + { "l5", 28599 }, + { "latin5", 28599 }, + { "x-mac-turkish", 10081 }, + { "windows-1254", 1254 }, + { "ISO_8859-9", 1254 }, + { "ISO_8859-9:1989", 1254 }, + { "iso-8859-9", 1254 }, + { "iso-ir-148", 1254 }, + { "latin5", 1254 }, + { "unicode", 1200 }, + { "utf-16", 1200 }, + { "unicodeFFFE", 1201 }, + { "utf-7", 65000 }, + { "csUnicode11UTF7", 65000 }, + { "unicode-1-1-utf-7", 65000 }, + { "x-unicode-2-0-utf-7", 65000 }, + { "utf-8", 65001 }, + { "unicode-1-1-utf-8", 65001 }, + { "unicode-2-0-utf-8", 65001 }, + { "x-unicode-2-0-utf-8", 65001 }, + { "us-ascii", 20127 }, + { "ANSI_X3.4-1968", 20127 }, + { "ANSI_X3.4-1986", 20127 }, + { "ascii", 20127 }, + { "cp367", 20127 }, + { "csASCII", 20127 }, + { "IBM367", 20127 }, + { "ISO_646.irv:1991", 20127 }, + { "ISO646-US", 20127 }, + { "iso-ir-6us", 20127 }, + { "windows-1258", 1258 }, + { "ibm850", 850 }, + { "x-IA5", 20105 }, + { "iso-8859-1", 28591 }, + { "cp819", 28591 }, + { "csISO", 28591 }, + { "Latin1", 28591 }, + { "ibm819", 28591 }, + { "iso_8859-1", 28591 }, + { "iso_8859-1:1987", 28591 }, + { "iso-ir-100", 28591 }, + { "l1", 28591 }, + { "latin1", 28591 }, + { "macintosh", 10000 }, + { "Windows-1252", 1252 }, + { "ANSI_X3.4-1968", 1252 }, + { "ANSI_X3.4-1986", 1252 }, + { "ascii", 1252 }, + { "cp367", 1252 }, + { "cp819", 1252 }, + { "csASCII", 1252 }, + { "IBM367", 1252 }, + { "ibm819", 1252 }, + { "ISO_646.irv:1991", 1252 }, + { "iso_8859-1", 1252 }, + { "iso_8859-1:1987", 1252 }, + { "ISO646-US", 1252 }, + { "iso-ir-100", 1252 }, + { "iso-ir-6", 1252 }, + { "latin1", 1252 }, + { "us", 1252 }, + { "us-ascii", 1252 }, + { "x-ansi", 1252 }, + { "microsoft-cp1251", 1251 } +}; + +#define LANGUAGE_NOT_LOADED 1 +#define LANGUAGE_LOADING -1 +#define LANGUAGE_LOADED 0 + +void LoadThread(LPVOID hd); + +class HunspellDictionary : public Dictionary +{ +protected: + TCHAR fileWithoutExtension[1024]; + TCHAR userPath[1024]; + volatile int loaded; + Hunspell *hunspell; + TCHAR *wordChars; + UINT codePage; + + void loadCustomDict() + { + TCHAR filename[1024]; + mir_sntprintf(filename, SIZEOF(filename), _T("%s\\%s.cdic"), userPath, language); + + FILE *file = _tfopen(filename, _T("rb")); + if (file != NULL) { + char tmp[1024]; + char c; + int pos = 0; + while ((c = fgetc(file)) != EOF) { + if (c == '\n' || c == '\r' || pos >= SIZEOF(tmp) - 1) { + if (pos > 0) { + tmp[pos] = '\0'; + hunspell->add(tmp); + } + + pos = 0; + } + else { + tmp[pos] = c; + pos++; + } + } + fclose(file); + } + } + + void appendToCustomDict(const TCHAR *word) + { + CreateDirectoryTreeT(userPath); + + TCHAR filename[1024]; + mir_sntprintf(filename, SIZEOF(filename), _T("%s\\%s.cdic"), userPath, language); + + FILE *file = _tfopen(filename, _T("ab")); + if (file != NULL) { + char tmp[1024]; + toHunspell(tmp, word, SIZEOF(tmp)); + fprintf(file, "%s\n", tmp); + fclose(file); + } + } + + virtual void addWordInternal(const TCHAR * word) + { + if (loaded != LANGUAGE_LOADED) + return; + + char hunspell_word[1024]; + toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); + + hunspell->add(hunspell_word); + } + + void toHunspell(char *hunspellWord, const TCHAR *word, size_t hunspellWordLen) + { + WideCharToMultiByte(codePage, 0, word, -1, hunspellWord, (int)hunspellWordLen, NULL, NULL); + } + + TCHAR* fromHunspell(const char *hunspellWord) + { + int len = MultiByteToWideChar(codePage, 0, hunspellWord, -1, NULL, 0); + WCHAR *ret = (WCHAR *)malloc((len + 1) * sizeof(WCHAR)); + MultiByteToWideChar(codePage, 0, hunspellWord, -1, ret, len + 1); + return ret; + } + + TCHAR* fromHunspellAndFree(char *hunspellWord) + { + if (hunspellWord == NULL) + return NULL; + + TCHAR *ret = fromHunspell(hunspellWord); + free(hunspellWord); + return ret; + } + +public: + HunspellDictionary(TCHAR *aLanguage, TCHAR *aFileWithoutExtension, TCHAR *anUserPath, TCHAR *aSource) + { + lstrcpyn(language, aLanguage, SIZEOF(language)); + lstrcpyn(fileWithoutExtension, aFileWithoutExtension, SIZEOF(fileWithoutExtension)); + lstrcpyn(userPath, anUserPath, SIZEOF(userPath)); + if (aSource == NULL) + source[0] = _T('\0'); + else + lstrcpyn(source, aSource, SIZEOF(source)); + + loaded = LANGUAGE_NOT_LOADED; + localized_name[0] = _T('\0'); + english_name[0] = _T('\0'); + full_name[0] = _T('\0'); + hunspell = NULL; + wordChars = NULL; + codePage = CP_ACP; + autoReplace = NULL; + } + + virtual ~HunspellDictionary() + { + if (hunspell != NULL) + delete hunspell; + if (wordChars != NULL) + free(wordChars); + } + + TCHAR * merge(TCHAR * s1, TCHAR *s2) + { + int len1 = (s1 == NULL ? 0 : lstrlen(s1)); + int len2 = (s2 == NULL ? 0 : lstrlen(s2)); + + TCHAR *ret; + if (len1 > 0 && len2 > 0) { + ret = (TCHAR *)malloc(sizeof(TCHAR) * (len1 + len2 + 1)); + lstrcpyn(ret, s1, len1 + 1); + lstrcpyn(&ret[len1], s2, len2 + 1); + + FREE(s1); + FREE(s2); + } + else if (len1 > 0) { + ret = s1; + FREE(s2); + } + else if (len2 > 0) { + ret = s2; + FREE(s1); + } + else { + ret = (TCHAR *)malloc(sizeof(TCHAR)); + ret[0] = 0; + + FREE(s1); + FREE(s2); + } + + // Remove duplicated chars + int last = lstrlen(ret) - 1; + for (int i = 0; i <= last; i++) { + TCHAR c = ret[i]; + for (int j = last; j > i; j--) { + if (c != ret[j]) + continue; + if (j != last) + ret[j] = ret[last]; + ret[last] = _T('\0'); + last--; + } + } + + return ret; + } + + + void loadThread() + { + char dic[1024]; + char aff[1024]; + + + mir_snprintf(dic, SIZEOF(dic), "%S.dic", fileWithoutExtension); + mir_snprintf(aff, SIZEOF(aff), "%S.aff", fileWithoutExtension); + + + hunspell = new Hunspell(aff, dic); + + // Get codepage + const char *dic_enc = hunspell->get_dic_encoding(); + + TCHAR *hwordchars; + if (strcmp(dic_enc, "UTF-8") == 0) { + codePage = CP_UTF8; + + + int wcs_len; + hwordchars = fromHunspell((char *)hunspell->get_wordchars_utf16(&wcs_len)); + + } + else { + for (int i = 0; i < SIZEOF(codepages); i++) { + if (_strcmpi(codepages[i].name, dic_enc) == 0) { + if (IsValidCodePage(codepages[i].codepage)) + codePage = codepages[i].codepage; + break; + } + } + + hwordchars = fromHunspell(hunspell->get_wordchars()); + } + + TCHAR *casechars = fromHunspellAndFree(get_casechars(dic_enc)); + TCHAR *try_string = fromHunspellAndFree(hunspell->get_try_string()); + + wordChars = merge(merge(casechars, hwordchars), try_string); + + // Make a suggestion to load hunspell internalls + char ** words = NULL; + int count = hunspell->suggest(&words, "asdf"); + for (int i = 0; i < count; i++) + free(words[i]); + if (words != NULL) + free(words); + + loadCustomDict(); + + loaded = LANGUAGE_LOADED; + } + + // Return TRUE if the word is correct + virtual BOOL spell(const TCHAR *word) + { + load(); + if (loaded != LANGUAGE_LOADED) + return TRUE; + + // TODO Check if it was generated by auto-replacement + + char hunspell_word[1024]; + toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); + + return hunspell->spell(hunspell_word); + } + + // Return a list of suggestions to a word + virtual Suggestions suggest(const TCHAR * word) + { + Suggestions ret = { 0 }; + + load(); + if (loaded != LANGUAGE_LOADED) + return ret; + + char hunspell_word[1024]; + toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); + + char ** words = NULL; + ret.count = hunspell->suggest(&words, hunspell_word); + + if (ret.count > 0 && words != NULL) { + // Oki, lets make our array + ret.words = (TCHAR **)malloc(ret.count * sizeof(TCHAR *)); + for (unsigned i = 0; i < ret.count; i++) { + ret.words[i] = fromHunspell(words[i]); + free(words[i]); + } + } + if (words != NULL) + free(words); + + return ret; + } + + // Return a list of auto suggestions to a word + virtual Suggestions autoSuggest(const TCHAR * word) + { + Suggestions ret = { 0 }; + + load(); + if (loaded != LANGUAGE_LOADED) + return ret; + + char hunspell_word[1024]; + toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); + + char ** words; + int count = hunspell->suggest_auto(&words, hunspell_word); + + if (count <= 0) + return ret; + + // Oki, lets make our array + ret.count = count; + ret.words = (TCHAR **)malloc(ret.count * sizeof(TCHAR *)); + for (int i = 0; i < count; i++) { + ret.words[i] = fromHunspell(words[i]); + free(words[i]); + } + free(words); + + return ret; + } + + // Return a list of auto suggestions to a word + // You have to free the list AND each item + virtual TCHAR * autoSuggestOne(const TCHAR * word) + { + load(); + if (loaded != LANGUAGE_LOADED) + return NULL; + + char hunspell_word[1024]; + toHunspell(hunspell_word, word, SIZEOF(hunspell_word)); + + char ** words; + int count = hunspell->suggest_auto(&words, hunspell_word); + + if (count <= 0) + return NULL; + + TCHAR *ret = fromHunspell(words[0]); + + // Oki, lets make our array + for (int i = 0; i < count; i++) + free(words[i]); + free(words); + + return ret; + } + + // Return TRUE if the char is a word char + virtual BOOL isWordChar(TCHAR c) + { + if (c == 0) + return FALSE; + + load(); + if (loaded != LANGUAGE_LOADED) + return TRUE; + + return _tcschr(wordChars, (_TINT)c) != NULL; + } + + // Assert that all needed data is loaded + virtual void load() + { + if (loaded == LANGUAGE_NOT_LOADED) { + loaded = LANGUAGE_LOADING; + mir_forkthread(LoadThread, this); + } + } + + virtual BOOL isLoaded() + { + return loaded == LANGUAGE_LOADED; + } + + + // Add a word to the user custom dict + virtual void addWord(const TCHAR * word) + { + addWordInternal(word); + appendToCustomDict(word); + } + + // Add a word to the list of ignored words + virtual void ignoreWord(const TCHAR * word) + { + addWordInternal(word); + } +}; + +void LoadThread(LPVOID hd) +{ + HunspellDictionary *dict = (HunspellDictionary *)hd; + dict->loadThread(); +} + + + +// To use with EnumLocalesProc :( +LIST *tmp_dicts; + +// To get the names of the languages +BOOL CALLBACK EnumLocalesProc(LPTSTR lpLocaleString) +{ + TCHAR *stopped = NULL; + USHORT langID = (USHORT)_tcstol(lpLocaleString, &stopped, 16); + + TCHAR ini[32]; + TCHAR end[32]; + GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SISO639LANGNAME, ini, SIZEOF(ini)); + GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SISO3166CTRYNAME, end, SIZEOF(end)); + + TCHAR name[64]; + mir_sntprintf(name, SIZEOF(name), _T("%s_%s"), ini, end); + + for (int i = 0; i < tmp_dicts->getCount(); i++) { + Dictionary *dict = (*tmp_dicts)[i]; + if (lstrcmpi(dict->language, name) == 0) { + GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SENGLANGUAGE, dict->english_name, SIZEOF(dict->english_name)); + + GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SLANGUAGE, dict->localized_name, SIZEOF(dict->localized_name)); + if (dict->localized_name[0] == 0) + GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SLOCALIZEDLANGUAGENAME, dict->localized_name, SIZEOF(dict->localized_name)); + if (dict->localized_name[0] == 0) + GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SNATIVEDISPLAYNAME, dict->localized_name, SIZEOF(dict->localized_name)); + if (dict->localized_name[0] == 0 && dict->english_name[0] != 0) { + TCHAR country[1024]; + GetLocaleInfo(MAKELCID(langID, 0), LOCALE_SENGCOUNTRY, country, SIZEOF(country)); + + TCHAR name[1024]; + if (country[0] != 0) + mir_sntprintf(name, SIZEOF(name), _T("%s (%s)"), dict->english_name, country); + else + lstrcpyn(name, dict->english_name, SIZEOF(name)); + + lstrcpyn(dict->localized_name, TranslateTS(name), SIZEOF(dict->localized_name)); + } + + if (dict->localized_name[0] != 0) { + mir_sntprintf(dict->full_name, SIZEOF(dict->full_name), _T("%s [%s]"), dict->localized_name, dict->language); + } + break; + } + } + return TRUE; +} + + +void GetDictsInfo(LIST &dicts) +{ + tmp_dicts = &dicts; + EnumSystemLocales(EnumLocalesProc, LCID_SUPPORTED); + + // Try to get name from DB + for (int i = 0; i < dicts.getCount(); i++) { + Dictionary *dict = dicts[i]; + + if (dict->full_name[0] == _T('\0')) { + DBVARIANT dbv; + + char lang[128]; + WideCharToMultiByte(CP_ACP, 0, dict->language, -1, lang, sizeof(lang), NULL, NULL); + if (!db_get_ts(NULL, MODULE_NAME, lang, &dbv)) { + lstrcpyn(dict->localized_name, dbv.ptszVal, SIZEOF(dict->localized_name)); + db_free(&dbv); + } + + if (dict->localized_name[0] == _T('\0')) { + for (size_t j = 0; j < SIZEOF(aditionalLanguages); j++) { + if (!lstrcmp(aditionalLanguages[j].language, dict->language)) { + lstrcpyn(dict->localized_name, TranslateTS(aditionalLanguages[j].localized_name), SIZEOF(dict->localized_name)); + break; + } + } + } + + if (dict->localized_name[0] != _T('\0')) { + mir_sntprintf(dict->full_name, SIZEOF(dict->full_name), _T("%s [%s]"), dict->localized_name, dict->language); + } + else { + lstrcpyn(dict->full_name, dict->language, SIZEOF(dict->full_name)); + } + } + } +} + + +void GetHunspellDictionariesFromFolder(LIST &dicts, TCHAR *path, TCHAR *user_path, TCHAR *source) +{ + // Load the language files and create an array with then + TCHAR file[1024]; + mir_sntprintf(file, SIZEOF(file), _T("%s\\*.dic"), path); + + BOOL found = FALSE; + + WIN32_FIND_DATA ffd = { 0 }; + HANDLE hFFD = FindFirstFile(file, &ffd); + if (hFFD != INVALID_HANDLE_VALUE) { + do { + mir_sntprintf(file, SIZEOF(file), _T("%s\\%s"), path, ffd.cFileName); + + // Check .dic + DWORD attrib = GetFileAttributes(file); + if (attrib == 0xFFFFFFFF || (attrib & FILE_ATTRIBUTE_DIRECTORY)) + continue; + + // See if .aff exists too + lstrcpy(&file[lstrlen(file) - 4], _T(".aff")); + attrib = GetFileAttributes(file); + if (attrib == 0xFFFFFFFF || (attrib & FILE_ATTRIBUTE_DIRECTORY)) + continue; + + ffd.cFileName[lstrlen(ffd.cFileName) - 4] = _T('\0'); + + TCHAR *lang = ffd.cFileName; + + // Replace - for _ + for (int i = 0; i < lstrlen(lang); i++) + if (lang[i] == _T('-')) + lang[i] = _T('_'); + + // Check if dict is new + bool exists = false; + for (int i = 0; i < dicts.getCount() && !exists; i++) + if (lstrcmp(dicts[i]->language, lang) == 0) + exists = true; + + if (!exists) { + found = TRUE; + file[lstrlen(file) - 4] = _T('\0'); + dicts.insert(new HunspellDictionary(lang, file, user_path, source)); + } + } + while (FindNextFile(hFFD, &ffd)); + + FindClose(hFFD); + } +} + + +// Return a list of avaible languages +void GetAvaibleDictionaries(LIST &dicts, TCHAR *path, TCHAR *user_path) +{ + // Get miranda folder dicts + GetHunspellDictionariesFromFolder(dicts, path, user_path, NULL); + + if (opts.use_other_apps_dicts) { + // Get other apps dicts + for (int i = 0; i < SIZEOF(otherHunspellApps); i++) { + TCHAR key[1024]; + mir_sntprintf(key, SIZEOF(key), APPPATH, otherHunspellApps[i].key); + + HKEY hKey = 0; + LONG lResult = 0; + if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE, &hKey)) { + DWORD size = SIZEOF(key); + lResult = RegQueryValueEx(hKey, _T("Path"), NULL, NULL, (LPBYTE)key, &size); + RegCloseKey(hKey); + } + else { + // Not found in installed apps - Try MUICache + lResult = RegOpenKeyEx(HKEY_CURRENT_USER, MUICACHE, 0, KEY_QUERY_VALUE, &hKey); + if (ERROR_SUCCESS == lResult) { + DWORD numValues; + if (ERROR_SUCCESS != RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &numValues, NULL, NULL, NULL, NULL)) + numValues = 0; + + lResult = ERROR_NO_MORE_ITEMS; + for (DWORD local = 0; local < numValues; local++) { + DWORD cchValue = SIZEOF(key); + if (ERROR_SUCCESS != RegEnumValue(hKey, local, key, &cchValue, NULL, NULL, NULL, NULL)) + break; + key[cchValue] = 0; + TCHAR *pos; + if (pos = _tcsrchr(key, _T('\\'))) { + if (!lstrcmpi(&pos[1], otherHunspellApps[i].key)) { + pos[0] = 0; + lResult = ERROR_SUCCESS; + break; + } + } + } + RegCloseKey(hKey); + } + } + + if (ERROR_SUCCESS == lResult) { + TCHAR folder[1024]; + mir_sntprintf(folder, SIZEOF(folder), _T("%s\\Dictionaries"), key); + + GetHunspellDictionariesFromFolder(languages, folder, user_path, otherHunspellApps[i].name); + } + } + } + + GetDictsInfo(dicts); + + // Yeah, yeah, yeah, I know, but this is the easiest way... + SortedList *sl = (SortedList *)&dicts; + + // Sort dicts + for (int i = 0; i < dicts.getCount(); i++) { + for (int j = i + 1; j < dicts.getCount(); j++) { + if (lstrcmp(dicts[i]->full_name, dicts[j]->full_name) > 0) { + Dictionary *dict = dicts[i]; + sl->items[i] = dicts[j]; + sl->items[j] = dict; + } + } + } +} + + +// Free the list returned by GetAvaibleDictionaries +void FreeDictionaries(LIST &dicts) +{ + for (int i = 0; i < dicts.getCount(); i++) + delete dicts[i]; + + dicts.destroy(); +} + +Dictionary::~Dictionary() +{ + delete autoReplace; +} + +// Free the list returned by GetAvaibleDictionaries +void FreeSuggestions(Suggestions &suggestions) +{ + for (size_t i = 0; i < suggestions.count; i++) + free(suggestions.words[i]); + + free(suggestions.words); + + suggestions.words = NULL; + suggestions.count = 0; +} diff --git a/plugins/SpellChecker/src/hunspell/csutil.cxx b/plugins/SpellChecker/src/hunspell/csutil.cxx index cf24bc06dd..ee78edbc40 100644 --- a/plugins/SpellChecker/src/hunspell/csutil.cxx +++ b/plugins/SpellChecker/src/hunspell/csutil.cxx @@ -343,6 +343,9 @@ char * line_uniq(char * text, char breakchar) { char ** lines; int linenum = line_tok(text, &lines, breakchar); int i; + + if (linenum == 0) + return NULL; strcpy(text, lines[0]); for ( i = 1; i < linenum; i++ ) { int dup = 0; diff --git a/plugins/SpellChecker/src/hunspell/suggestmgr.cxx b/plugins/SpellChecker/src/hunspell/suggestmgr.cxx index d89630849c..843075e62f 100644 --- a/plugins/SpellChecker/src/hunspell/suggestmgr.cxx +++ b/plugins/SpellChecker/src/hunspell/suggestmgr.cxx @@ -1578,7 +1578,8 @@ char * SuggestMgr::suggest_morph_for_spelling_error(const char * word) { char * p = NULL; char ** wlst = (char **) calloc(maxSug, sizeof(char *)); - if (!**wlst) return NULL; + if (!wlst) + return NULL; // we will use only the first suggestion for (int i = 0; i < maxSug - 1; i++) wlst[i] = ""; int ns = suggest(&wlst, word, maxSug - 1, NULL); @@ -1586,7 +1587,7 @@ char * SuggestMgr::suggest_morph_for_spelling_error(const char * word) p = suggest_morph(wlst[maxSug - 1]); free(wlst[maxSug - 1]); } - if (wlst) free(wlst); + free(wlst); return p; } #endif // END OF HUNSPELL_EXPERIMENTAL CODE -- cgit v1.2.3