Index: third_party/hunspell_new/src/hunspell/hashmgr.cxx |
diff --git a/third_party/hunspell_new/src/hunspell/hashmgr.cxx b/third_party/hunspell_new/src/hunspell/hashmgr.cxx |
deleted file mode 100644 |
index 5b7c269a3a34249f15724b03a1f172d8e973f883..0000000000000000000000000000000000000000 |
--- a/third_party/hunspell_new/src/hunspell/hashmgr.cxx |
+++ /dev/null |
@@ -1,1168 +0,0 @@ |
-#include "license.hunspell" |
-#include "license.myspell" |
- |
-#include <stdlib.h> |
-#include <string.h> |
-#include <stdio.h> |
-#include <ctype.h> |
- |
-#include "hashmgr.hxx" |
-#include "csutil.hxx" |
-#include "atypes.hxx" |
- |
-// build a hash table from a munched word list |
- |
-#ifdef HUNSPELL_CHROME_CLIENT |
-HashMgr::HashMgr(hunspell::BDictReader* reader) |
-{ |
- bdict_reader = reader; |
-#else |
-HashMgr::HashMgr(const char * tpath, const char * apath, const char * key) |
-{ |
-#endif |
- tablesize = 0; |
- tableptr = NULL; |
- flag_mode = FLAG_CHAR; |
- complexprefixes = 0; |
- utf8 = 0; |
- langnum = 0; |
- lang = NULL; |
- enc = NULL; |
- csconv = 0; |
- ignorechars = NULL; |
- ignorechars_utf16 = NULL; |
- ignorechars_utf16_len = 0; |
- numaliasf = 0; |
- aliasf = NULL; |
- numaliasm = 0; |
- aliasm = NULL; |
- forbiddenword = FORBIDDENWORD; // forbidden word signing flag |
-#ifdef HUNSPELL_CHROME_CLIENT |
- // No tables to load, just the AF lines. |
- load_config(NULL, NULL); |
- int ec = LoadAFLines(); |
-#else |
- load_config(apath, key); |
- int ec = load_tables(tpath, key); |
-#endif |
- if (ec) { |
- /* error condition - what should we do here */ |
- HUNSPELL_WARNING(stderr, "Hash Manager Error : %d\n",ec); |
- if (tableptr) { |
- free(tableptr); |
- tableptr = NULL; |
- } |
- tablesize = 0; |
- } |
-} |
- |
- |
-HashMgr::~HashMgr() |
-{ |
- if (tableptr) { |
- // now pass through hash table freeing up everything |
- // go through column by column of the table |
- for (int i=0; i < tablesize; i++) { |
- struct hentry * pt = tableptr[i]; |
- struct hentry * nt = NULL; |
- while(pt) { |
- nt = pt->next; |
- if (pt->astr && (!aliasf || TESTAFF(pt->astr, ONLYUPCASEFLAG, pt->alen))) free(pt->astr); |
- free(pt); |
- pt = nt; |
- } |
- } |
- free(tableptr); |
- } |
- tablesize = 0; |
- |
- if (aliasf) { |
- for (int j = 0; j < (numaliasf); j++) free(aliasf[j]); |
- free(aliasf); |
- aliasf = NULL; |
- if (aliasflen) { |
- free(aliasflen); |
- aliasflen = NULL; |
- } |
- } |
- if (aliasm) { |
- for (int j = 0; j < (numaliasm); j++) free(aliasm[j]); |
- free(aliasm); |
- aliasm = NULL; |
- } |
- |
-#ifndef OPENOFFICEORG |
-#ifndef MOZILLA_CLIENT |
- if (utf8) free_utf_tbl(); |
-#endif |
-#endif |
- |
- if (enc) free(enc); |
- if (lang) free(lang); |
- |
- if (ignorechars) free(ignorechars); |
- if (ignorechars_utf16) free(ignorechars_utf16); |
- |
-#ifdef HUNSPELL_CHROME_CLIENT |
- EmptyHentryCache(); |
- for (std::vector<std::string*>::iterator it = pointer_to_strings_.begin(); |
- it != pointer_to_strings_.end(); ++it) { |
- delete *it; |
- } |
-#endif |
-#ifdef MOZILLA_CLIENT |
- delete [] csconv; |
-#endif |
-} |
- |
-#ifdef HUNSPELL_CHROME_CLIENT |
-void HashMgr::EmptyHentryCache() { |
- // We need to delete each cache entry, and each additional one in the linked |
- // list of homonyms. |
- for (HEntryCache::iterator i = hentry_cache.begin(); |
- i != hentry_cache.end(); ++i) { |
- hentry* cur = i->second; |
- while (cur) { |
- hentry* next = cur->next_homonym; |
- DeleteHashEntry(cur); |
- cur = next; |
- } |
- } |
- hentry_cache.clear(); |
-} |
-#endif |
- |
-// lookup a root word in the hashtable |
- |
-struct hentry * HashMgr::lookup(const char *word) const |
-{ |
-#ifdef HUNSPELL_CHROME_CLIENT |
- int affix_ids[hunspell::BDict::MAX_AFFIXES_PER_WORD]; |
- int affix_count = bdict_reader->FindWord(word, affix_ids); |
- if (affix_count == 0) { // look for custom added word |
- std::map<base::StringPiece, int>::const_iterator iter = |
- custom_word_to_affix_id_map_.find(word); |
- if (iter != custom_word_to_affix_id_map_.end()) { |
- affix_count = 1; |
- affix_ids[0] = iter->second; |
- } |
- } |
- |
- static const int kMaxWordLen = 128; |
- static char word_buf[kMaxWordLen]; |
- // To take account of null-termination, we use upto 127. |
- strncpy(word_buf, word, kMaxWordLen - 1); |
- |
- return AffixIDsToHentry(word_buf, affix_ids, affix_count); |
-#else |
- struct hentry * dp; |
- if (tableptr) { |
- dp = tableptr[hash(word)]; |
- if (!dp) return NULL; |
- for ( ; dp != NULL; dp = dp->next) { |
- if (strcmp(word, dp->word) == 0) return dp; |
- } |
- } |
- return NULL; |
-#endif |
-} |
- |
-// add a word to the hash table (private) |
-int HashMgr::add_word(const char * word, int wbl, int wcl, unsigned short * aff, |
- int al, const char * desc, bool onlyupcase) |
-{ |
-#ifndef HUNSPELL_CHROME_CLIENT |
- bool upcasehomonym = false; |
- int descl = desc ? (aliasm ? sizeof(short) : strlen(desc) + 1) : 0; |
- // variable-length hash record with word and optional fields |
- struct hentry* hp = |
- (struct hentry *) malloc (sizeof(struct hentry) + wbl + descl); |
- if (!hp) return 1; |
- char * hpw = hp->word; |
- strcpy(hpw, word); |
- if (ignorechars != NULL) { |
- if (utf8) { |
- remove_ignored_chars_utf(hpw, ignorechars_utf16, ignorechars_utf16_len); |
- } else { |
- remove_ignored_chars(hpw, ignorechars); |
- } |
- } |
- if (complexprefixes) { |
- if (utf8) reverseword_utf(hpw); else reverseword(hpw); |
- } |
- |
- int i = hash(hpw); |
- |
- hp->blen = (unsigned char) wbl; |
- hp->clen = (unsigned char) wcl; |
- hp->alen = (short) al; |
- hp->astr = aff; |
- hp->next = NULL; |
- hp->next_homonym = NULL; |
- |
- // store the description string or its pointer |
- if (desc) { |
- hp->var = H_OPT; |
- if (aliasm) { |
- hp->var += H_OPT_ALIASM; |
- store_pointer(hpw + wbl + 1, get_aliasm(atoi(desc))); |
- } else { |
- strcpy(hpw + wbl + 1, desc); |
- if (complexprefixes) { |
- if (utf8) reverseword_utf(HENTRY_DATA(hp)); |
- else reverseword(HENTRY_DATA(hp)); |
- } |
- } |
- if (strstr(HENTRY_DATA(hp), MORPH_PHON)) hp->var += H_OPT_PHON; |
- } else hp->var = 0; |
- |
- struct hentry * dp = tableptr[i]; |
- if (!dp) { |
- tableptr[i] = hp; |
- return 0; |
- } |
- while (dp->next != NULL) { |
- if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) { |
- // remove hidden onlyupcase homonym |
- if (!onlyupcase) { |
- if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { |
- free(dp->astr); |
- dp->astr = hp->astr; |
- dp->alen = hp->alen; |
- free(hp); |
- return 0; |
- } else { |
- dp->next_homonym = hp; |
- } |
- } else { |
- upcasehomonym = true; |
- } |
- } |
- dp=dp->next; |
- } |
- if (strcmp(hp->word, dp->word) == 0) { |
- // remove hidden onlyupcase homonym |
- if (!onlyupcase) { |
- if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { |
- free(dp->astr); |
- dp->astr = hp->astr; |
- dp->alen = hp->alen; |
- free(hp); |
- return 0; |
- } else { |
- dp->next_homonym = hp; |
- } |
- } else { |
- upcasehomonym = true; |
- } |
- } |
- if (!upcasehomonym) { |
- dp->next = hp; |
- } else { |
- // remove hidden onlyupcase homonym |
- if (hp->astr) free(hp->astr); |
- free(hp); |
- } |
-#else |
- std::map<base::StringPiece, int>::iterator iter = |
- custom_word_to_affix_id_map_.find(word); |
- if(iter == custom_word_to_affix_id_map_.end()) { // word needs to be added |
- std::string* new_string_word = new std::string(word); |
- pointer_to_strings_.push_back(new_string_word); |
- base::StringPiece sp(*(new_string_word)); |
- custom_word_to_affix_id_map_[sp] = 0; // no affixes for custom words |
- return 1; |
- } |
-#endif |
- return 0; |
-} |
- |
-int HashMgr::add_hidden_capitalized_word(char * word, int wbl, int wcl, |
- unsigned short * flags, int al, char * dp, int captype) |
-{ |
- // add inner capitalized forms to handle the following allcap forms: |
- // Mixed caps: OpenOffice.org -> OPENOFFICE.ORG |
- // Allcaps with suffixes: CIA's -> CIA'S |
- if (((captype == HUHCAP) || (captype == HUHINITCAP) || |
- ((captype == ALLCAP) && (flags != NULL))) && |
- !((flags != NULL) && TESTAFF(flags, forbiddenword, al))) { |
- unsigned short * flags2 = (unsigned short *) malloc (sizeof(unsigned short) * (al+1)); |
- if (!flags2) return 1; |
- if (al) memcpy(flags2, flags, al * sizeof(unsigned short)); |
- flags2[al] = ONLYUPCASEFLAG; |
- if (utf8) { |
- char st[BUFSIZE]; |
- w_char w[BUFSIZE]; |
- int wlen = u8_u16(w, BUFSIZE, word); |
- mkallsmall_utf(w, wlen, langnum); |
- mkallcap_utf(w, 1, langnum); |
- u16_u8(st, BUFSIZE, w, wlen); |
- return add_word(st,wbl,wcl,flags2,al+1,dp, true); |
- } else { |
- mkallsmall(word, csconv); |
- mkinitcap(word, csconv); |
- return add_word(word,wbl,wcl,flags2,al+1,dp, true); |
- } |
- } |
- return 0; |
-} |
- |
-// detect captype and modify word length for UTF-8 encoding |
-int HashMgr::get_clen_and_captype(const char * word, int wbl, int * captype) { |
- int len; |
- if (utf8) { |
- w_char dest_utf[BUFSIZE]; |
- len = u8_u16(dest_utf, BUFSIZE, word); |
- *captype = get_captype_utf8(dest_utf, len, langnum); |
- } else { |
- len = wbl; |
- *captype = get_captype((char *) word, len, csconv); |
- } |
- return len; |
-} |
- |
-// remove word (personal dictionary function for standalone applications) |
-int HashMgr::remove(const char * word) |
-{ |
-#ifdef HUNSPELL_CHROME_CLIENT |
- std::map<base::StringPiece, int>::iterator iter = |
- custom_word_to_affix_id_map_.find(word); |
- if (iter != custom_word_to_affix_id_map_.end()) |
- custom_word_to_affix_id_map_.erase(iter); |
-#else |
- struct hentry * dp = lookup(word); |
- while (dp) { |
- if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) { |
- unsigned short * flags = |
- (unsigned short *) malloc(sizeof(short) * (dp->alen + 1)); |
- if (!flags) return 1; |
- for (int i = 0; i < dp->alen; i++) flags[i] = dp->astr[i]; |
- flags[dp->alen] = forbiddenword; |
- dp->astr = flags; |
- dp->alen++; |
- flag_qsort(flags, 0, dp->alen); |
- } |
- dp = dp->next_homonym; |
- } |
-#endif |
- return 0; |
-} |
- |
-/* remove forbidden flag to add a personal word to the hash */ |
-int HashMgr::remove_forbidden_flag(const char * word) { |
- struct hentry * dp = lookup(word); |
- if (!dp) return 1; |
- while (dp) { |
- if (dp->astr && TESTAFF(dp->astr, forbiddenword, dp->alen)) { |
- if (dp->alen == 1) dp->alen = 0; // XXX forbidden words of personal dic. |
- else { |
- unsigned short * flags2 = |
- (unsigned short *) malloc(sizeof(short) * (dp->alen - 1)); |
- if (!flags2) return 1; |
- int i, j = 0; |
- for (i = 0; i < dp->alen; i++) { |
- if (dp->astr[i] != forbiddenword) flags2[j++] = dp->astr[i]; |
- } |
- dp->alen--; |
- dp->astr = flags2; // XXX allowed forbidden words |
- } |
- } |
- dp = dp->next_homonym; |
- } |
- return 0; |
-} |
- |
-// add a custom dic. word to the hash table (public) |
-int HashMgr::add(const char * word) |
-{ |
- unsigned short * flags = NULL; |
- int al = 0; |
- if (remove_forbidden_flag(word)) { |
- int captype; |
- int wbl = strlen(word); |
- int wcl = get_clen_and_captype(word, wbl, &captype); |
- add_word(word, wbl, wcl, flags, al, NULL, false); |
- return add_hidden_capitalized_word((char *) word, wbl, wcl, flags, al, NULL, captype); |
- } |
- return 0; |
-} |
- |
-int HashMgr::add_with_affix(const char * word, const char * example) |
-{ |
- // detect captype and modify word length for UTF-8 encoding |
- struct hentry * dp = lookup(example); |
- remove_forbidden_flag(word); |
- if (dp && dp->astr) { |
- int captype; |
- int wbl = strlen(word); |
- int wcl = get_clen_and_captype(word, wbl, &captype); |
- if (aliasf) { |
- add_word(word, wbl, wcl, dp->astr, dp->alen, NULL, false); |
- } else { |
- unsigned short * flags = (unsigned short *) malloc (dp->alen * sizeof(short)); |
- if (flags) { |
- memcpy((void *) flags, (void *) dp->astr, dp->alen * sizeof(short)); |
- add_word(word, wbl, wcl, flags, dp->alen, NULL, false); |
- } else return 1; |
- } |
- return add_hidden_capitalized_word((char *) word, wbl, wcl, dp->astr, dp->alen, NULL, captype); |
- } |
- return 1; |
-} |
- |
-// walk the hash table entry by entry - null at end |
-// initialize: col=-1; hp = NULL; hp = walk_hashtable(&col, hp); |
-struct hentry * HashMgr::walk_hashtable(int &col, struct hentry * hp) const |
-{ |
-#ifdef HUNSPELL_CHROME_CLIENT |
- // Return NULL if dictionary is not valid. |
- if (!bdict_reader->IsValid()) |
- return NULL; |
- |
- // This function is only ever called by one place and not nested. We can |
- // therefore keep static state between calls and use |col| as a "reset" flag |
- // to avoid changing the API. It is set to -1 for the first call. |
- // Allocate the iterator on the heap to prevent an exit time destructor. |
- static hunspell::WordIterator& word_iterator = |
- *new hunspell::WordIterator(bdict_reader->GetAllWordIterator()); |
- if (col < 0) { |
- col = 1; |
- word_iterator = bdict_reader->GetAllWordIterator(); |
- } |
- |
- int affix_ids[hunspell::BDict::MAX_AFFIXES_PER_WORD]; |
- static const int kMaxWordLen = 128; |
- static char word[kMaxWordLen]; |
- int affix_count = word_iterator.Advance(word, kMaxWordLen, affix_ids); |
- if (affix_count == 0) |
- return NULL; |
- short word_len = static_cast<short>(strlen(word)); |
- |
- // Since hunspell 1.2.8, an hentry struct becomes a variable-length struct, |
- // i.e. a struct which uses its array 'word[1]' as a variable-length array. |
- // As noted above, this function is not nested. So, we just use a static |
- // struct which consists of an hentry and a char[kMaxWordLen], and initialize |
- // the static struct and return it for now. |
- // No need to create linked lists for the extra affixes. |
- static struct { |
- hentry entry; |
- char word[kMaxWordLen]; |
- } hash_entry; |
- |
- return InitHashEntry(&hash_entry.entry, sizeof(hash_entry), |
- &word[0], word_len, affix_ids[0]); |
-#else |
- if (hp && hp->next != NULL) return hp->next; |
- for (col++; col < tablesize; col++) { |
- if (tableptr[col]) return tableptr[col]; |
- } |
- // null at end and reset to start |
- col = -1; |
- return NULL; |
-#endif |
-} |
- |
-// load a munched word list and build a hash table on the fly |
-int HashMgr::load_tables(const char * tpath, const char * key) |
-{ |
-#ifndef HUNSPELL_CHROME_CLIENT |
- int al; |
- char * ap; |
- char * dp; |
- char * dp2; |
- unsigned short * flags; |
- char * ts; |
- |
- // open dictionary file |
- FileMgr * dict = new FileMgr(tpath, key); |
- if (dict == NULL) return 1; |
- |
- // first read the first line of file to get hash table size */ |
- if ((ts = dict->getline()) == NULL) { |
- HUNSPELL_WARNING(stderr, "error: empty dic file %s\n", tpath); |
- delete dict; |
- return 2; |
- } |
- mychomp(ts); |
- |
- /* remove byte order mark */ |
- if (strncmp(ts,"\xEF\xBB\xBF",3) == 0) { |
- memmove(ts, ts+3, strlen(ts+3)+1); |
- // warning: dic file begins with byte order mark: possible incompatibility with old Hunspell versions |
- } |
- |
- tablesize = atoi(ts); |
- if (tablesize == 0) { |
- HUNSPELL_WARNING(stderr, "error: line 1: missing or bad word count in the dic file\n"); |
- delete dict; |
- return 4; |
- } |
- tablesize = tablesize + 5 + USERWORD; |
- if ((tablesize %2) == 0) tablesize++; |
- |
- // allocate the hash table |
- tableptr = (struct hentry **) malloc(tablesize * sizeof(struct hentry *)); |
- if (! tableptr) { |
- delete dict; |
- return 3; |
- } |
- for (int i=0; i<tablesize; i++) tableptr[i] = NULL; |
- |
- // loop through all words on much list and add to hash |
- // table and create word and affix strings |
- |
- while ((ts = dict->getline()) != NULL) { |
- mychomp(ts); |
- // split each line into word and morphological description |
- dp = ts; |
- while ((dp = strchr(dp, ':')) != NULL) { |
- if ((dp > ts + 3) && (*(dp - 3) == ' ' || *(dp - 3) == '\t')) { |
- for (dp -= 4; dp >= ts && (*dp == ' ' || *dp == '\t'); dp--); |
- if (dp < ts) { // missing word |
- dp = NULL; |
- } else { |
- *(dp + 1) = '\0'; |
- dp = dp + 2; |
- } |
- break; |
- } |
- dp++; |
- } |
- |
- // tabulator is the old morphological field separator |
- dp2 = strchr(ts, '\t'); |
- if (dp2 && (!dp || dp2 < dp)) { |
- *dp2 = '\0'; |
- dp = dp2 + 1; |
- } |
- |
- // split each line into word and affix char strings |
- // "\/" signs slash in words (not affix separator) |
- // "/" at beginning of the line is word character (not affix separator) |
- ap = strchr(ts,'/'); |
- while (ap) { |
- if (ap == ts) { |
- ap++; |
- continue; |
- } else if (*(ap - 1) != '\\') break; |
- // replace "\/" with "/" |
- for (char * sp = ap - 1; *sp; *sp = *(sp + 1), sp++); |
- ap = strchr(ap,'/'); |
- } |
- |
- if (ap) { |
- *ap = '\0'; |
- if (aliasf) { |
- int index = atoi(ap + 1); |
- al = get_aliasf(index, &flags, dict); |
- if (!al) { |
- HUNSPELL_WARNING(stderr, "error: line %d: bad flag vector alias\n", dict->getlinenum()); |
- *ap = '\0'; |
- } |
- } else { |
- al = decode_flags(&flags, ap + 1, dict); |
- if (al == -1) { |
- HUNSPELL_WARNING(stderr, "Can't allocate memory.\n"); |
- delete dict; |
- return 6; |
- } |
- flag_qsort(flags, 0, al); |
- } |
- } else { |
- al = 0; |
- ap = NULL; |
- flags = NULL; |
- } |
- |
- int captype; |
- int wbl = strlen(ts); |
- int wcl = get_clen_and_captype(ts, wbl, &captype); |
- // add the word and its index plus its capitalized form optionally |
- if (add_word(ts,wbl,wcl,flags,al,dp, false) || |
- add_hidden_capitalized_word(ts, wbl, wcl, flags, al, dp, captype)) { |
- delete dict; |
- return 5; |
- } |
- } |
- |
- delete dict; |
-#endif |
- return 0; |
-} |
- |
-// the hash function is a simple load and rotate |
-// algorithm borrowed |
- |
-int HashMgr::hash(const char * word) const |
-{ |
-#ifdef HUNSPELL_CHROME_CLIENT |
- return 0; |
-#else |
- long hv = 0; |
- for (int i=0; i < 4 && *word != 0; i++) |
- hv = (hv << 8) | (*word++); |
- while (*word != 0) { |
- ROTATE(hv,ROTATE_LEN); |
- hv ^= (*word++); |
- } |
- return (unsigned long) hv % tablesize; |
-#endif |
-} |
- |
-int HashMgr::decode_flags(unsigned short ** result, char * flags, FileMgr * af) { |
- int len; |
- if (*flags == '\0') { |
- *result = NULL; |
- return 0; |
- } |
- switch (flag_mode) { |
- case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz) |
- len = strlen(flags); |
- if (len%2 == 1) HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n", af->getlinenum()); |
- len /= 2; |
- *result = (unsigned short *) malloc(len * sizeof(short)); |
- if (!*result) return -1; |
- for (int i = 0; i < len; i++) { |
- (*result)[i] = (((unsigned short) flags[i * 2]) << 8) + (unsigned short) flags[i * 2 + 1]; |
- } |
- break; |
- } |
- case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 23 233) |
- int i; |
- len = 1; |
- char * src = flags; |
- unsigned short * dest; |
- char * p; |
- for (p = flags; *p; p++) { |
- if (*p == ',') len++; |
- } |
- *result = (unsigned short *) malloc(len * sizeof(short)); |
- if (!*result) return -1; |
- dest = *result; |
- for (p = flags; *p; p++) { |
- if (*p == ',') { |
- i = atoi(src); |
- if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: line %d: flag id %d is too large (max: %d)\n", |
- af->getlinenum(), i, DEFAULTFLAGS - 1); |
- *dest = (unsigned short) i; |
- if (*dest == 0) HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", af->getlinenum()); |
- src = p + 1; |
- dest++; |
- } |
- } |
- i = atoi(src); |
- if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: line %d: flag id %d is too large (max: %d)\n", |
- af->getlinenum(), i, DEFAULTFLAGS - 1); |
- *dest = (unsigned short) i; |
- if (*dest == 0) HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", af->getlinenum()); |
- break; |
- } |
- case FLAG_UNI: { // UTF-8 characters |
- w_char w[BUFSIZE/2]; |
- len = u8_u16(w, BUFSIZE/2, flags); |
- *result = (unsigned short *) malloc(len * sizeof(short)); |
- if (!*result) return -1; |
- memcpy(*result, w, len * sizeof(short)); |
- break; |
- } |
- default: { // Ispell's one-character flags (erfg -> e r f g) |
- unsigned short * dest; |
- len = strlen(flags); |
- *result = (unsigned short *) malloc(len * sizeof(short)); |
- if (!*result) return -1; |
- dest = *result; |
- for (unsigned char * p = (unsigned char *) flags; *p; p++) { |
- *dest = (unsigned short) *p; |
- dest++; |
- } |
- } |
- } |
- return len; |
-} |
- |
-unsigned short HashMgr::decode_flag(const char * f) { |
- unsigned short s = 0; |
- int i; |
- switch (flag_mode) { |
- case FLAG_LONG: |
- s = ((unsigned short) f[0] << 8) + (unsigned short) f[1]; |
- break; |
- case FLAG_NUM: |
- i = atoi(f); |
- if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: flag id %d is too large (max: %d)\n", i, DEFAULTFLAGS - 1); |
- s = (unsigned short) i; |
- break; |
- case FLAG_UNI: |
- u8_u16((w_char *) &s, 1, f); |
- break; |
- default: |
- s = (unsigned short) *((unsigned char *)f); |
- } |
- if (s == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n"); |
- return s; |
-} |
- |
-char * HashMgr::encode_flag(unsigned short f) { |
- unsigned char ch[10]; |
- if (f==0) return mystrdup("(NULL)"); |
- if (flag_mode == FLAG_LONG) { |
- ch[0] = (unsigned char) (f >> 8); |
- ch[1] = (unsigned char) (f - ((f >> 8) << 8)); |
- ch[2] = '\0'; |
- } else if (flag_mode == FLAG_NUM) { |
- sprintf((char *) ch, "%d", f); |
- } else if (flag_mode == FLAG_UNI) { |
- u16_u8((char *) &ch, 10, (w_char *) &f, 1); |
- } else { |
- ch[0] = (unsigned char) (f); |
- ch[1] = '\0'; |
- } |
- return mystrdup((char *) ch); |
-} |
- |
-// read in aff file and set flag mode |
-int HashMgr::load_config(const char * affpath, const char * key) |
-{ |
- char * line; // io buffers |
- int firstline = 1; |
- |
- // open the affix file |
-#ifdef HUNSPELL_CHROME_CLIENT |
- hunspell::LineIterator iterator = bdict_reader->GetOtherLineIterator(); |
- FileMgr * afflst = new FileMgr(&iterator); |
-#else |
- FileMgr * afflst = new FileMgr(affpath, key); |
-#endif |
- if (!afflst) { |
- HUNSPELL_WARNING(stderr, "Error - could not open affix description file %s\n",affpath); |
- return 1; |
- } |
- |
- // read in each line ignoring any that do not |
- // start with a known line type indicator |
- |
- while ((line = afflst->getline()) != NULL) { |
- mychomp(line); |
- |
- /* remove byte order mark */ |
- if (firstline) { |
- firstline = 0; |
- if (strncmp(line,"\xEF\xBB\xBF",3) == 0) memmove(line, line+3, strlen(line+3)+1); |
- } |
- |
- /* parse in the try string */ |
- if ((strncmp(line,"FLAG",4) == 0) && isspace(line[4])) { |
- if (flag_mode != FLAG_CHAR) { |
- HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions of the FLAG affix file parameter\n", afflst->getlinenum()); |
- } |
- if (strstr(line, "long")) flag_mode = FLAG_LONG; |
- if (strstr(line, "num")) flag_mode = FLAG_NUM; |
- if (strstr(line, "UTF-8")) flag_mode = FLAG_UNI; |
- if (flag_mode == FLAG_CHAR) { |
- HUNSPELL_WARNING(stderr, "error: line %d: FLAG needs `num', `long' or `UTF-8' parameter\n", afflst->getlinenum()); |
- } |
- } |
- if (strncmp(line,"FORBIDDENWORD",13) == 0) { |
- char * st = NULL; |
- if (parse_string(line, &st, afflst->getlinenum())) { |
- delete afflst; |
- return 1; |
- } |
- forbiddenword = decode_flag(st); |
- free(st); |
- } |
- if (strncmp(line, "SET", 3) == 0) { |
- if (parse_string(line, &enc, afflst->getlinenum())) { |
- delete afflst; |
- return 1; |
- } |
- if (strcmp(enc, "UTF-8") == 0) { |
- utf8 = 1; |
-#ifndef OPENOFFICEORG |
-#ifndef MOZILLA_CLIENT |
- initialize_utf_tbl(); |
-#endif |
-#endif |
- } else csconv = get_current_cs(enc); |
- } |
- if (strncmp(line, "LANG", 4) == 0) { |
- if (parse_string(line, &lang, afflst->getlinenum())) { |
- delete afflst; |
- return 1; |
- } |
- langnum = get_lang_num(lang); |
- } |
- |
- /* parse in the ignored characters (for example, Arabic optional diacritics characters */ |
- if (strncmp(line,"IGNORE",6) == 0) { |
- if (parse_array(line, &ignorechars, &ignorechars_utf16, |
- &ignorechars_utf16_len, utf8, afflst->getlinenum())) { |
- delete afflst; |
- return 1; |
- } |
- } |
- |
- if ((strncmp(line,"AF",2) == 0) && isspace(line[2])) { |
- if (parse_aliasf(line, afflst)) { |
- delete afflst; |
- return 1; |
- } |
- } |
- |
- if ((strncmp(line,"AM",2) == 0) && isspace(line[2])) { |
- if (parse_aliasm(line, afflst)) { |
- delete afflst; |
- return 1; |
- } |
- } |
- |
- if (strncmp(line,"COMPLEXPREFIXES",15) == 0) complexprefixes = 1; |
- if (((strncmp(line,"SFX",3) == 0) || (strncmp(line,"PFX",3) == 0)) && isspace(line[3])) break; |
- } |
- if (csconv == NULL) csconv = get_current_cs(SPELL_ENCODING); |
- delete afflst; |
- return 0; |
-} |
- |
-/* parse in the ALIAS table */ |
-int HashMgr::parse_aliasf(char * line, FileMgr * af) |
-{ |
- if (numaliasf != 0) { |
- HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); |
- return 1; |
- } |
- char * tp = line; |
- char * piece; |
- int i = 0; |
- int np = 0; |
- piece = mystrsep(&tp, 0); |
- while (piece) { |
- if (*piece != '\0') { |
- switch(i) { |
- case 0: { np++; break; } |
- case 1: { |
- numaliasf = atoi(piece); |
- if (numaliasf < 1) { |
- numaliasf = 0; |
- aliasf = NULL; |
- aliasflen = NULL; |
- HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); |
- return 1; |
- } |
- aliasf = (unsigned short **) malloc(numaliasf * sizeof(unsigned short *)); |
- aliasflen = (unsigned short *) malloc(numaliasf * sizeof(short)); |
- if (!aliasf || !aliasflen) { |
- numaliasf = 0; |
- if (aliasf) free(aliasf); |
- if (aliasflen) free(aliasflen); |
- aliasf = NULL; |
- aliasflen = NULL; |
- return 1; |
- } |
- np++; |
- break; |
- } |
- default: break; |
- } |
- i++; |
- } |
- piece = mystrsep(&tp, 0); |
- } |
- if (np != 2) { |
- numaliasf = 0; |
- free(aliasf); |
- free(aliasflen); |
- aliasf = NULL; |
- aliasflen = NULL; |
- HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); |
- return 1; |
- } |
- |
- /* now parse the numaliasf lines to read in the remainder of the table */ |
- char * nl; |
- for (int j=0; j < numaliasf; j++) { |
- if ((nl = af->getline()) == NULL) return 1; |
- mychomp(nl); |
- tp = nl; |
- i = 0; |
- aliasf[j] = NULL; |
- aliasflen[j] = 0; |
- piece = mystrsep(&tp, 0); |
- while (piece) { |
- if (*piece != '\0') { |
- switch(i) { |
- case 0: { |
- if (strncmp(piece,"AF",2) != 0) { |
- numaliasf = 0; |
- free(aliasf); |
- free(aliasflen); |
- aliasf = NULL; |
- aliasflen = NULL; |
- HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); |
- return 1; |
- } |
- break; |
- } |
- case 1: { |
- aliasflen[j] = (unsigned short) decode_flags(&(aliasf[j]), piece, af); |
- flag_qsort(aliasf[j], 0, aliasflen[j]); |
- break; |
- } |
- default: break; |
- } |
- i++; |
- } |
- piece = mystrsep(&tp, 0); |
- } |
- if (!aliasf[j]) { |
- free(aliasf); |
- free(aliasflen); |
- aliasf = NULL; |
- aliasflen = NULL; |
- numaliasf = 0; |
- HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); |
- return 1; |
- } |
- } |
- return 0; |
-} |
- |
-#ifdef HUNSPELL_CHROME_CLIENT |
-int HashMgr::LoadAFLines() |
-{ |
- utf8 = 1; // We always use UTF-8. |
- |
- // Read in all the AF lines which tell us the rules for each affix group ID. |
- hunspell::LineIterator iterator = bdict_reader->GetAfLineIterator(); |
- FileMgr afflst(&iterator); |
- while (char* line = afflst.getline()) { |
- int rv = parse_aliasf(line, &afflst); |
- if (rv) |
- return rv; |
- } |
- |
- return 0; |
-} |
- |
-hentry* HashMgr::InitHashEntry(hentry* entry, |
- size_t item_size, |
- const char* word, |
- int word_length, |
- int affix_index) const { |
- // Return if the given buffer doesn't have enough space for a hentry struct |
- // or the given word is too long. |
- // Our BDICT cannot handle words longer than (128 - 1) bytes. So, it is |
- // better to return an error if the given word is too long and prevent |
- // an unexpected result caused by a long word. |
- const int kMaxWordLen = 128; |
- if (item_size < sizeof(hentry) + word_length + 1 || |
- word_length >= kMaxWordLen) |
- return NULL; |
- |
- // Initialize a hentry struct with the given parameters, and |
- // append the given string at the end of this hentry struct. |
- memset(entry, 0, item_size); |
- FileMgr af(NULL); |
- entry->alen = static_cast<short>( |
- const_cast<HashMgr*>(this)->get_aliasf(affix_index, &entry->astr, &af)); |
- entry->blen = static_cast<unsigned char>(word_length); |
- memcpy(&entry->word, word, word_length); |
- |
- return entry; |
-} |
- |
-hentry* HashMgr::CreateHashEntry(const char* word, |
- int word_length, |
- int affix_index) const { |
- // Return if the given word is too long. |
- // (See the comment in HashMgr::InitHashEntry().) |
- const int kMaxWordLen = 128; |
- if (word_length >= kMaxWordLen) |
- return NULL; |
- |
- const size_t kEntrySize = sizeof(hentry) + word_length + 1; |
- struct hentry* entry = reinterpret_cast<hentry*>(malloc(kEntrySize)); |
- if (entry) |
- InitHashEntry(entry, kEntrySize, word, word_length, affix_index); |
- |
- return entry; |
-} |
- |
-void HashMgr::DeleteHashEntry(hentry* entry) const { |
- free(entry); |
-} |
- |
-hentry* HashMgr::AffixIDsToHentry(char* word, |
- int* affix_ids, |
- int affix_count) const |
-{ |
- if (affix_count == 0) |
- return NULL; |
- |
- HEntryCache& cache = const_cast<HashMgr*>(this)->hentry_cache; |
- std::string std_word(word); |
- HEntryCache::iterator found = cache.find(std_word); |
- if (found != cache.end()) { |
- // We must return an existing hentry for the same word if we've previously |
- // handed one out. Hunspell will compare pointers in some cases to see if |
- // two words it has found are the same. |
- return found->second; |
- } |
- |
- short word_len = static_cast<short>(strlen(word)); |
- |
- // We can get a number of prefixes per word. There will normally be only one, |
- // but if not, there will be a linked list of "hentry"s for the "homonym"s |
- // for the word. |
- struct hentry* first_he = NULL; |
- struct hentry* prev_he = NULL; // For making linked list. |
- for (int i = 0; i < affix_count; i++) { |
- struct hentry* he = CreateHashEntry(word, word_len, affix_ids[i]); |
- if (!he) |
- break; |
- if (i == 0) |
- first_he = he; |
- if (prev_he) |
- prev_he->next_homonym = he; |
- prev_he = he; |
- } |
- |
- cache[std_word] = first_he; // Save this word in the cache for later. |
- return first_he; |
-} |
- |
-hentry* HashMgr::GetHentryFromHEntryCache(char* word) { |
- HEntryCache& cache = const_cast<HashMgr*>(this)->hentry_cache; |
- std::string std_word(word); |
- HEntryCache::iterator found = cache.find(std_word); |
- if (found != cache.end()) |
- return found->second; |
- else |
- return NULL; |
-} |
-#endif |
- |
-int HashMgr::is_aliasf() { |
- return (aliasf != NULL); |
-} |
- |
-int HashMgr::get_aliasf(int index, unsigned short ** fvec, FileMgr * af) { |
- if ((index > 0) && (index <= numaliasf)) { |
- *fvec = aliasf[index - 1]; |
- return aliasflen[index - 1]; |
- } |
- HUNSPELL_WARNING(stderr, "error: line %d: bad flag alias index: %d\n", af->getlinenum(), index); |
- *fvec = NULL; |
- return 0; |
-} |
- |
-/* parse morph alias definitions */ |
-int HashMgr::parse_aliasm(char * line, FileMgr * af) |
-{ |
- if (numaliasm != 0) { |
- HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum()); |
- return 1; |
- } |
- char * tp = line; |
- char * piece; |
- int i = 0; |
- int np = 0; |
- piece = mystrsep(&tp, 0); |
- while (piece) { |
- if (*piece != '\0') { |
- switch(i) { |
- case 0: { np++; break; } |
- case 1: { |
- numaliasm = atoi(piece); |
- if (numaliasm < 1) { |
- HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); |
- return 1; |
- } |
- aliasm = (char **) malloc(numaliasm * sizeof(char *)); |
- if (!aliasm) { |
- numaliasm = 0; |
- return 1; |
- } |
- np++; |
- break; |
- } |
- default: break; |
- } |
- i++; |
- } |
- piece = mystrsep(&tp, 0); |
- } |
- if (np != 2) { |
- numaliasm = 0; |
- free(aliasm); |
- aliasm = NULL; |
- HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); |
- return 1; |
- } |
- |
- /* now parse the numaliasm lines to read in the remainder of the table */ |
- char * nl = line; |
- for (int j=0; j < numaliasm; j++) { |
- if ((nl = af->getline()) == NULL) return 1; |
- mychomp(nl); |
- tp = nl; |
- i = 0; |
- aliasm[j] = NULL; |
- piece = mystrsep(&tp, ' '); |
- while (piece) { |
- if (*piece != '\0') { |
- switch(i) { |
- case 0: { |
- if (strncmp(piece,"AM",2) != 0) { |
- HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); |
- numaliasm = 0; |
- free(aliasm); |
- aliasm = NULL; |
- return 1; |
- } |
- break; |
- } |
- case 1: { |
- // add the remaining of the line |
- if (*tp) { |
- *(tp - 1) = ' '; |
- tp = tp + strlen(tp); |
- } |
- if (complexprefixes) { |
- if (utf8) reverseword_utf(piece); |
- else reverseword(piece); |
- } |
- aliasm[j] = mystrdup(piece); |
- if (!aliasm[j]) { |
- numaliasm = 0; |
- free(aliasm); |
- aliasm = NULL; |
- return 1; |
- } |
- break; } |
- default: break; |
- } |
- i++; |
- } |
- piece = mystrsep(&tp, ' '); |
- } |
- if (!aliasm[j]) { |
- numaliasm = 0; |
- free(aliasm); |
- aliasm = NULL; |
- HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); |
- return 1; |
- } |
- } |
- return 0; |
-} |
- |
-int HashMgr::is_aliasm() { |
- return (aliasm != NULL); |
-} |
- |
-char * HashMgr::get_aliasm(int index) { |
- if ((index > 0) && (index <= numaliasm)) return aliasm[index - 1]; |
- HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index); |
- return NULL; |
-} |