diff options
-rw-r--r-- | plugins/SpellChecker/src/dictionary.cpp | 1929 | ||||
-rw-r--r-- | plugins/SpellChecker/src/hunspell/csutil.cxx | 3 | ||||
-rw-r--r-- | plugins/SpellChecker/src/hunspell/suggestmgr.cxx | 5 |
3 files changed, 970 insertions, 967 deletions
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<Dictionary> *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<Dictionary> &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<Dictionary> &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<Dictionary> &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<Dictionary> &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<Dictionary> *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<Dictionary> &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<Dictionary> &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<Dictionary> &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<Dictionary> &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 |