Index: third_party/hunspell/src/hunspell/suggestmgr.cxx |
=================================================================== |
--- third_party/hunspell/src/hunspell/suggestmgr.cxx (revision 50428) |
+++ third_party/hunspell/src/hunspell/suggestmgr.cxx (working copy) |
@@ -12,6 +12,98 @@ |
const w_char W_VLINE = { '\0', '|' }; |
+#ifdef HUNSPELL_CHROME_CLIENT |
+namespace { |
+// A simple class which creates temporary hentry objects which are available |
+// only in a scope. To conceal memory operations from SuggestMgr functions, |
+// this object automatically deletes all hentry objects created through |
+// CreateScopedHashEntry() calls in its destructor. So, the following snippet |
+// raises a memory error. |
+// |
+// hentry* bad_copy = NULL; |
+// { |
+// ScopedHashEntryFactory factory; |
+// hentry* scoped_copy = factory.CreateScopedHashEntry(0, source); |
+// ... |
+// bad_copy = scoped_copy; |
+// } |
+// if (bad_copy->word[0]) // memory for scoped_copy has been deleted! |
+// |
+// As listed in the above snippet, it is simple to use this class. |
+// 1. Declare an instance of this ScopedHashEntryFactory, and; |
+// 2. Call its CreateHashEntry() member instead of using 'new hentry' or |
+// 'operator='. |
+// |
+class ScopedHashEntryFactory { |
+ public: |
+ ScopedHashEntryFactory(); |
+ ~ScopedHashEntryFactory(); |
+ |
+ // Creates a temporary copy of the given hentry struct. |
+ // The returned copy is available only while this object is available. |
+ // NOTE: this function just calls memcpy() in creating a copy of the given |
+ // hentry struct, i.e. it does NOT copy objects referred by pointers of the |
+ // given hentry struct. |
+ hentry* CreateScopedHashEntry(int index, const hentry* source); |
+ |
+ private: |
+ // A struct which encapsulates the new hentry struct introduced in hunspell |
+ // 1.2.8. For a pointer to an hentry struct 'h', hunspell 1.2.8 stores a word |
+ // (including a NUL character) into 'h->word[0]',...,'h->word[h->blen]' even |
+ // though arraysize(h->word[]) is 1. Also, it changed 'astr' to a pointer so |
+ // it can store affix flags into 'h->astr[0]',...,'h->astr[alen-1]'. To handle |
+ // this new hentry struct, we define a struct which combines three values: an |
+ // hentry struct 'hentry'; a char array 'word[kMaxWordLen]', and; an unsigned |
+ // short value 'astr' so a hentry struct 'h' returned from |
+ // CreateScopedHashEntry() satisfies the following equations: |
+ // hentry* h = factory.CreateScopedHashEntry(0, source); |
+ // h->word[0] == ((HashEntryItem*)h)->entry.word[0]. |
+ // h->word[1] == ((HashEntryItem*)h)->word[0]. |
+ // ... |
+ // h->word[h->blen] == ((HashEntryItem*)h)->word[h->blen-1]. |
+ // h->astr[0] == ((HashEntryItem*)h)->astr. |
+ // Our BDICT does not use affix flags longer than one for now since they are |
+ // discarded by convert_dict, i.e. 'h->astr' is always <= 1. Therefore, this |
+ // struct does not use an array for 'astr'. |
+ enum { |
+ kMaxWordLen = 128, |
+ }; |
+ struct HashEntryItem { |
+ hentry entry; |
+ char word[kMaxWordLen]; |
+ unsigned short astr; |
+ }; |
+ |
+ HashEntryItem hash_items_[MAX_ROOTS]; |
+}; |
+ |
+ScopedHashEntryFactory::ScopedHashEntryFactory() { |
+ memset(&hash_items_[0], 0, sizeof(hash_items_)); |
+} |
+ |
+ScopedHashEntryFactory::~ScopedHashEntryFactory() { |
+} |
+ |
+hentry* ScopedHashEntryFactory::CreateScopedHashEntry(int index, |
+ const hentry* source) { |
+ if (index >= MAX_ROOTS || source->blen >= kMaxWordLen || source->alen > 1) |
+ return NULL; |
+ |
+ // Retrieve a HashEntryItem struct from our spool, initialize it, and |
+ // returns the address of its 'hentry' member. |
+ size_t source_size = sizeof(hentry) + source->blen + 1; |
+ HashEntryItem* hash_item = &hash_items_[index]; |
+ memcpy(&hash_item->entry, source, source_size); |
+ if (source->astr) { |
+ hash_item->astr = *source->astr; |
+ hash_item->entry.astr = &hash_item->astr; |
+ } |
+ return &hash_item->entry; |
+} |
+ |
+} // namespace |
+#endif |
+ |
SuggestMgr::SuggestMgr(const char * tryme, int maxn, |
AffixMgr * aptr) |
{ |
@@ -1029,6 +1121,11 @@ |
struct hentry* hp = NULL; |
int col = -1; |
+ |
+#ifdef HUNSPELL_CHROME_CLIENT |
+ ScopedHashEntryFactory hash_entry_factory; |
+#endif |
+ |
phonetable * ph = (pAMgr) ? pAMgr->get_phonetable() : NULL; |
char target[MAXSWUTF8L]; |
char candidate[MAXSWUTF8L]; |
@@ -1066,7 +1163,11 @@ |
if (sc > scores[lp]) { |
scores[lp] = sc; |
+#ifdef HUNSPELL_CHROME_CLIENT |
+ roots[lp] = hash_entry_factory.CreateScopedHashEntry(lp, hp); |
+#else |
roots[lp] = hp; |
+#endif |
lval = sc; |
for (j=0; j < MAX_ROOTS; j++) |
if (scores[j] < lval) { |